fix(grid): restore DataGrid palette
This commit is contained in:
1 parent
b1f0784d49
commit
51ab6fb9ec
5 files changed
+208
-164
No files matched your search
@@ -138,7 +138,7 @@ import { canFetchNextDataGridSegment, canGoNextDataGridPage, hasCompleteLocalDat
|
||||
import { dataGridCountQueryOptions } from "@/lib/dataGrid/dataGridQueryOptions";
|
||||
import { dataGridBottomScrollTop, dataGridScrollPosition, isDataGridAtScrollBottom, isDataGridNearScrollBottom, shouldCheckInfiniteScrollAfterScroll, type DataGridScrollPosition } from "@/lib/dataGrid/dataGridInfiniteScroll";
|
||||
import { CANVAS_DATA_GRID_ROW_HEIGHT, canvasDataGridActionReservedWidth, dataGridSearchMatchKey, drawCanvasDataGrid } from "@/lib/dataGrid/canvasDataGridRenderer";
|
||||
import { DATA_GRID_DARK_ROW_NUMBER_BG, DATA_GRID_DARK_STRIPED_ROW_BG, DATA_GRID_LIGHT_STRIPED_ROW_BG, dataGridActiveRowBackground } from "@/lib/dataGrid/dataGridPaintTheme";
|
||||
import { DATA_GRID_DARK_STRIPED_ROW_BG, DATA_GRID_LIGHT_STRIPED_ROW_BG, dataGridActiveRowBackground } from "@/lib/dataGrid/dataGridPaintTheme";
|
||||
import { createRowLowerTextCache } from "@/lib/dataGrid/dataGridRowLowerText";
|
||||
import { dataGridPreviewLabelKey, dataGridSaveActionMode, dataGridSaveToolbarState } from "@/lib/dataGrid/dataGridSaveUi";
|
||||
import type { QueryEditabilityReason } from "@/lib/sql/sqlAnalysis";
|
||||
@@ -4388,16 +4388,16 @@ function isNull(value: unknown): boolean {
|
||||
|
||||
function rowNumberStatusClass(item: RowItem): string {
|
||||
if (item.status === "draft") {
|
||||
return "data-grid-row-number--status-draft font-semibold";
|
||||
return "border-muted-foreground/20 bg-muted/20 font-semibold text-muted-foreground";
|
||||
}
|
||||
if (item.status === "new") {
|
||||
return "data-grid-row-number--status-new font-semibold";
|
||||
return "border-emerald-500/40 bg-emerald-500/15 font-semibold text-emerald-700 dark:text-emerald-300";
|
||||
}
|
||||
if (item.status === "edited") {
|
||||
return "data-grid-row-number--status-edited font-semibold";
|
||||
return "border-amber-500/40 bg-amber-500/15 font-semibold text-amber-700 dark:text-amber-300";
|
||||
}
|
||||
if (item.status === "deleted") {
|
||||
return "data-grid-row-number--status-deleted font-semibold line-through";
|
||||
return "border-destructive/40 bg-destructive/15 font-semibold text-destructive line-through";
|
||||
}
|
||||
return "text-muted-foreground";
|
||||
}
|
||||
@@ -4408,27 +4408,53 @@ function rowCellsUseSelectionVisual(rowId: number): boolean {
|
||||
|
||||
function dataGridRowStyle(item: RowItem): CSSProperties {
|
||||
const dark = isDark.value || (typeof document !== "undefined" && document.documentElement.classList.contains("dark"));
|
||||
const deletedBg = "var(--color-error-bg, color-mix(in srgb, var(--destructive) 12%, transparent))";
|
||||
const newBg = "var(--success-bg, color-mix(in srgb, var(--success) 12%, transparent))";
|
||||
const editedBg = "var(--warning-bg, color-mix(in srgb, var(--warning) 14%, transparent))";
|
||||
const activeBg = `var(--data-grid-cell-active-bg, ${dataGridActiveRowBackground(dark)})`;
|
||||
const resolvedRowBg = item.isDeleted
|
||||
? deletedBg
|
||||
const activeRowBg = dataGridActiveRowBackground(dark);
|
||||
const rowBg = item.isDeleted
|
||||
? dark
|
||||
? "rgb(55, 31, 32)"
|
||||
: "rgb(255, 244, 244)"
|
||||
: isRowActive(item.displayIndex)
|
||||
? activeBg
|
||||
: item.isNew || item.isDraft
|
||||
? "color-mix(in srgb, var(--muted) 80%, var(--background))"
|
||||
: item.displayIndex % 2 === 1
|
||||
? `var(--data-grid-row-muted-bg, ${dark ? DATA_GRID_DARK_STRIPED_ROW_BG : DATA_GRID_LIGHT_STRIPED_ROW_BG})`
|
||||
: "var(--background)";
|
||||
const rowNumberBg = item.status === "new" ? newBg : item.status === "edited" ? editedBg : item.status === "deleted" ? deletedBg : isRowActive(item.displayIndex) && !item.isDeleted ? activeBg : dark ? DATA_GRID_DARK_ROW_NUMBER_BG : "var(--background)";
|
||||
? activeRowBg
|
||||
: item.isNew
|
||||
? dark
|
||||
? "rgb(51, 51, 55)"
|
||||
: "rgb(243, 243, 243)"
|
||||
: item.isDraft
|
||||
? dark
|
||||
? "rgb(51, 51, 55)"
|
||||
: "rgb(243, 243, 243)"
|
||||
: item.displayIndex % 2 === 1
|
||||
? `var(--data-grid-row-muted-bg, ${dark ? DATA_GRID_DARK_STRIPED_ROW_BG : DATA_GRID_LIGHT_STRIPED_ROW_BG})`
|
||||
: dark
|
||||
? "rgb(19, 20, 22)"
|
||||
: "rgb(255, 255, 255)";
|
||||
const rowNumberBg =
|
||||
item.status === "new"
|
||||
? dark
|
||||
? "rgb(33, 45, 40)"
|
||||
: "rgb(219, 244, 233)"
|
||||
: item.status === "edited"
|
||||
? dark
|
||||
? "rgb(48, 41, 28)"
|
||||
: "rgb(253, 241, 219)"
|
||||
: item.status === "deleted"
|
||||
? dark
|
||||
? "rgb(55, 31, 32)"
|
||||
: "rgb(255, 244, 244)"
|
||||
: isRowActive(item.displayIndex) && !item.isDeleted
|
||||
? activeRowBg
|
||||
: dark
|
||||
? "rgb(35, 37, 42)"
|
||||
: "rgb(255, 255, 255)";
|
||||
return {
|
||||
"--data-grid-cell-bg": resolvedRowBg,
|
||||
"--data-grid-cell-bg": rowBg,
|
||||
"--data-grid-row-number-bg": rowNumberBg,
|
||||
// Keep selection fill/border from [data-grid-root] tokens (primary/ring mix).
|
||||
// Do not flatten them to --accent/--border — that erases outline contrast.
|
||||
"--data-grid-cell-selected-dirty-bg": editedBg,
|
||||
"--data-grid-row-number-active-bg": activeBg,
|
||||
"--data-grid-cell-selected-bg": dark ? "rgb(20, 40, 60)" : "rgb(239, 246, 255)",
|
||||
"--data-grid-cell-selected-single-bg": dark ? "rgb(30, 64, 96)" : "rgb(191, 219, 254)",
|
||||
"--data-grid-cell-selected-dirty-bg": dark ? "rgb(76, 66, 38)" : "rgb(235, 224, 184)",
|
||||
"--data-grid-cell-selected-border": dark ? "rgb(96, 165, 250)" : "rgb(59, 130, 246)",
|
||||
"--data-grid-row-number-active-bg": activeRowBg,
|
||||
"--data-grid-row-number-selected-bg": dark ? "rgb(30, 64, 96)" : "rgb(191, 219, 254)",
|
||||
} as CSSProperties;
|
||||
}
|
||||
|
||||
@@ -7979,8 +8005,8 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
<div
|
||||
class="sticky left-0 z-10 flex shrink-0 items-center border-r border-border bg-background px-3 py-0 font-medium truncate"
|
||||
:class="{
|
||||
'cell-search-match': transposeHeaderIsSearchMatch(visibleColumnIndexes[index]),
|
||||
'cell-current-search-match': transposeHeaderIsCurrentMatch(visibleColumnIndexes[index]),
|
||||
'bg-yellow-200/60 dark:bg-yellow-500/20': transposeHeaderIsSearchMatch(visibleColumnIndexes[index]),
|
||||
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': transposeHeaderIsCurrentMatch(visibleColumnIndexes[index]),
|
||||
}"
|
||||
:style="{ width: `${transposePinnedWidth}px` }"
|
||||
:title="item.column"
|
||||
@@ -7999,11 +8025,11 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
'row-cell-selected': transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
|
||||
'row-cell-selected-dirty': transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex) && displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
|
||||
'bg-primary/15': transposeRecordUsesActiveHighlight(cell.recordIndex) && !transposeRecordUsesSelectionVisual(cell.recordIndex) && !displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex] && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex),
|
||||
'cell-dirty': displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
|
||||
'cell-search-match': cellIsSearchMatch(cell.recordIndex, cell.valueIndex),
|
||||
'cell-current-search-match': cellIsCurrentMatch(cell.recordIndex, cell.valueIndex),
|
||||
'bg-yellow-500/10 cell-dirty': displayItems[cell.recordIndex]?.isDirtyCol[cell.valueIndex],
|
||||
'bg-yellow-200/60 dark:bg-yellow-500/20': cellIsSearchMatch(cell.recordIndex, cell.valueIndex),
|
||||
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': cellIsCurrentMatch(cell.recordIndex, cell.valueIndex),
|
||||
'cursor-text': !isScrolling && canEditCellItem(displayItems[cell.recordIndex], cell.valueIndex),
|
||||
'hover:bg-accent':
|
||||
'hover:bg-gray-200 dark:hover:bg-gray-800':
|
||||
!isScrolling && canEditCellItem(displayItems[cell.recordIndex], cell.valueIndex) && !transposeRecordUsesSelectionVisual(cell.recordIndex) && !transposeRecordUsesActiveHighlight(cell.recordIndex) && !transposeCellIsSelected(cell.recordIndex, cell.valueIndex),
|
||||
}"
|
||||
:style="{ width: `${getTransposeRecordWidth(cell.recordIndex)}px` }"
|
||||
@@ -8651,15 +8677,17 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
'data-grid-cell--frozen-separator': frozenColumnCount > 0 && col.visibleColIdx === frozenColumnCount - 1,
|
||||
'text-right': columnAligns[col.visibleColIdx] === 'right',
|
||||
'text-muted-foreground italic': isNull(item.data[col.actualColIdx]),
|
||||
'cell-dirty': item.isDirtyCol[col.actualColIdx],
|
||||
'bg-yellow-500/10 cell-dirty': item.isDirtyCol[col.actualColIdx],
|
||||
'cell-selected': cellIsSelected(item.displayIndex, col.visibleColIdx) && !item.isDirtyCol[col.actualColIdx],
|
||||
'cell-selected-dirty': cellIsSelected(item.displayIndex, col.visibleColIdx) && item.isDirtyCol[col.actualColIdx],
|
||||
'row-cell-selected': rowCellsUseSelectionVisual(item.id) && !cellIsSelected(item.displayIndex, col.visibleColIdx) && !item.isDirtyCol[col.actualColIdx],
|
||||
'row-cell-selected-dirty': rowCellsUseSelectionVisual(item.id) && !cellIsSelected(item.displayIndex, col.visibleColIdx) && item.isDirtyCol[col.actualColIdx],
|
||||
'cell-search-match': cellIsSearchMatch(item.displayIndex, col.actualColIdx),
|
||||
'cell-current-search-match': cellIsCurrentMatch(item.displayIndex, col.actualColIdx),
|
||||
'bg-yellow-200/60 dark:bg-yellow-500/20': cellIsSearchMatch(item.displayIndex, col.actualColIdx),
|
||||
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': cellIsCurrentMatch(item.displayIndex, col.actualColIdx),
|
||||
'tabular-nums': typeof item.data[col.actualColIdx] === 'number',
|
||||
'cursor-text hover:bg-accent': !isScrolling && canEditCellItem(item, col.actualColIdx),
|
||||
'cursor-text hover:bg-gray-200 dark:hover:bg-gray-800': !isScrolling && canEditCellItem(item, col.actualColIdx),
|
||||
'line-through': item.isDeleted,
|
||||
'overflow-visible z-20 border-r-transparent': editingCell?.rowId === item.id && editingCell?.col === col.actualColIdx,
|
||||
'overflow-hidden': !(editingCell?.rowId === item.id && editingCell?.col === col.actualColIdx),
|
||||
@@ -8916,8 +8944,8 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
<div class="min-w-0 flex-1">
|
||||
<div class="font-medium truncate">{{ index.name }}</div>
|
||||
<div class="mt-1 flex flex-wrap gap-1">
|
||||
<span v-if="index.is_primary" class="rounded bg-warning-bg px-1.5 py-0.5 text-warning">PK</span>
|
||||
<span v-if="index.is_unique" class="rounded bg-success-bg px-1.5 py-0.5 text-success">UNIQUE</span>
|
||||
<span v-if="index.is_primary" class="rounded bg-amber-500/10 px-1.5 py-0.5 text-amber-600">PK</span>
|
||||
<span v-if="index.is_unique" class="rounded bg-emerald-500/10 px-1.5 py-0.5 text-emerald-600">UNIQUE</span>
|
||||
<span v-if="index.index_type" class="rounded bg-muted px-1.5 py-0.5 text-muted-foreground">{{ index.index_type }}</span>
|
||||
</div>
|
||||
<div class="mt-2 font-mono text-[11px] text-muted-foreground break-all">
|
||||
@@ -9312,32 +9340,74 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
@reference "../../styles/globals.css";
|
||||
|
||||
[data-grid-root] {
|
||||
/* Status / selection chrome — derived from theme tokens so palettes stay in sync. */
|
||||
--data-grid-row-muted-bg: color-mix(in srgb, var(--muted) 92%, var(--foreground));
|
||||
--data-grid-row-new-bg: color-mix(in srgb, var(--muted) 80%, var(--background));
|
||||
--data-grid-row-deleted-bg: var(--color-error-bg, color-mix(in srgb, var(--destructive) 12%, transparent));
|
||||
--data-grid-cell-active-bg: color-mix(in srgb, var(--info) 10%, var(--background));
|
||||
--data-grid-cell-dirty-bg: var(--warning-bg, color-mix(in srgb, var(--warning) 14%, transparent));
|
||||
--data-grid-cell-selected-bg: color-mix(in srgb, var(--primary) 12%, var(--accent));
|
||||
--data-grid-cell-selected-single-bg: color-mix(in srgb, var(--primary) 22%, var(--accent));
|
||||
--data-grid-cell-selected-dirty-bg: color-mix(in srgb, var(--warning) 22%, var(--accent));
|
||||
/* Prefer ring/primary so the outline stays visible on the selected fill. */
|
||||
--data-grid-cell-selected-border: color-mix(in srgb, var(--ring) 55%, var(--primary));
|
||||
--data-grid-cell-selected-single-border: var(--primary);
|
||||
--data-grid-cell-hover-bg: var(--accent);
|
||||
--data-grid-cell-search-bg: var(--warning-bg, color-mix(in srgb, var(--warning) 18%, transparent));
|
||||
--data-grid-cell-current-search-bg: color-mix(in srgb, var(--warning) 35%, transparent);
|
||||
--data-grid-cell-current-search-border: var(--warning);
|
||||
--data-grid-row-number-default-bg: var(--background);
|
||||
--data-grid-row-number-new-bg: var(--success-bg, color-mix(in srgb, var(--success) 12%, transparent));
|
||||
--data-grid-row-number-edited-bg: var(--warning-bg, color-mix(in srgb, var(--warning) 14%, transparent));
|
||||
--data-grid-row-number-deleted-bg: var(--color-error-bg, color-mix(in srgb, var(--destructive) 12%, transparent));
|
||||
--data-grid-row-number-active-bg: var(--data-grid-cell-active-bg);
|
||||
--data-grid-row-number-selected-bg: var(--data-grid-cell-selected-single-bg);
|
||||
--data-grid-scrollbar-thumb: color-mix(in srgb, var(--foreground) 30%, transparent);
|
||||
--data-grid-scrollbar-thumb-hover: color-mix(in srgb, var(--foreground) 48%, transparent);
|
||||
--data-grid-row-muted-bg: rgb(240, 240, 240);
|
||||
--data-grid-row-new-bg: rgb(243, 243, 243);
|
||||
--data-grid-row-deleted-bg: rgb(255, 244, 244);
|
||||
--data-grid-cell-active-bg: rgb(244, 248, 255);
|
||||
--data-grid-cell-dirty-bg: rgb(255, 248, 230);
|
||||
--data-grid-cell-selected-bg: rgb(239, 246, 255);
|
||||
--data-grid-cell-selected-single-bg: rgb(191, 219, 254);
|
||||
--data-grid-cell-selected-dirty-bg: rgb(235, 224, 184);
|
||||
--data-grid-cell-selected-border: rgb(59, 130, 246);
|
||||
--data-grid-cell-hover-bg: rgb(245, 245, 245);
|
||||
--data-grid-cell-search-bg: rgb(253, 245, 184);
|
||||
--data-grid-cell-current-search-bg: rgba(253, 224, 71, 0.52);
|
||||
--data-grid-cell-current-search-border: rgba(234, 179, 8, 0.82);
|
||||
--data-grid-row-number-default-bg: rgb(255, 255, 255);
|
||||
--data-grid-row-number-new-bg: rgb(219, 244, 233);
|
||||
--data-grid-row-number-edited-bg: rgb(253, 241, 219);
|
||||
--data-grid-row-number-deleted-bg: rgb(255, 244, 244);
|
||||
--data-grid-row-number-active-bg: rgb(244, 248, 255);
|
||||
--data-grid-row-number-selected-bg: rgb(191, 219, 254);
|
||||
--data-grid-scrollbar-thumb: color-mix(in oklch, var(--foreground) 30%, transparent);
|
||||
--data-grid-scrollbar-thumb-hover: color-mix(in oklch, var(--foreground) 48%, transparent);
|
||||
--data-grid-scrollbar-track: transparent;
|
||||
background-color: var(--background);
|
||||
background-color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
[data-grid-root].data-grid--dark,
|
||||
:global(.dark) [data-grid-root] {
|
||||
--data-grid-row-muted-bg: rgb(40, 40, 43);
|
||||
--data-grid-row-new-bg: rgb(51, 51, 55);
|
||||
--data-grid-row-deleted-bg: rgb(55, 31, 32);
|
||||
--data-grid-cell-active-bg: rgb(25, 34, 46);
|
||||
--data-grid-cell-dirty-bg: rgb(94, 75, 26);
|
||||
--data-grid-cell-selected-bg: rgb(20, 40, 60);
|
||||
--data-grid-cell-selected-single-bg: rgb(30, 64, 96);
|
||||
--data-grid-cell-selected-dirty-bg: rgb(76, 66, 38);
|
||||
--data-grid-cell-selected-border: rgb(96, 165, 250);
|
||||
--data-grid-cell-hover-bg: rgb(46, 47, 51);
|
||||
--data-grid-cell-search-bg: rgb(72, 57, 8);
|
||||
--data-grid-cell-current-search-bg: rgb(116, 87, 0);
|
||||
--data-grid-cell-current-search-border: rgb(239, 177, 0);
|
||||
--data-grid-row-number-default-bg: rgb(35, 37, 42);
|
||||
--data-grid-row-number-new-bg: rgb(33, 45, 40);
|
||||
--data-grid-row-number-edited-bg: rgb(48, 41, 28);
|
||||
--data-grid-row-number-deleted-bg: rgb(55, 31, 32);
|
||||
--data-grid-row-number-active-bg: rgb(25, 34, 46);
|
||||
--data-grid-row-number-selected-bg: rgb(30, 64, 96);
|
||||
--data-grid-scrollbar-thumb: rgb(82, 82, 91);
|
||||
--data-grid-scrollbar-thumb-hover: rgb(113, 113, 122);
|
||||
--data-grid-scrollbar-track: rgb(24, 24, 27);
|
||||
background-color: rgb(19, 20, 22);
|
||||
}
|
||||
|
||||
@supports (background: color-mix(in oklab, white 50%, transparent)) {
|
||||
[data-grid-root] {
|
||||
--data-grid-row-muted-bg: color-mix(in oklab, var(--muted) 99%, var(--foreground));
|
||||
--data-grid-row-new-bg: color-mix(in oklab, var(--primary) 5%, transparent);
|
||||
--data-grid-row-deleted-bg: color-mix(in oklab, var(--destructive) 5%, transparent);
|
||||
--data-grid-cell-dirty-bg: color-mix(in oklab, rgb(240 177 0) 10%, transparent);
|
||||
--data-grid-cell-selected-bg: color-mix(in oklab, rgb(59 130 246) 12%, var(--background));
|
||||
--data-grid-cell-selected-single-bg: color-mix(in oklab, rgb(59 130 246) 30%, var(--background));
|
||||
--data-grid-cell-selected-dirty-bg: color-mix(in oklab, rgb(234 181 50) 30%, color-mix(in oklab, rgb(59 130 246) 18%, var(--background)));
|
||||
--data-grid-cell-selected-border: color-mix(in oklab, rgb(59 130 246) 75%, transparent);
|
||||
--data-grid-cell-hover-bg: color-mix(in oklab, var(--accent) 50%, transparent);
|
||||
--data-grid-row-number-new-bg: color-mix(in oklab, rgb(16 185 129) 15%, var(--background));
|
||||
--data-grid-row-number-edited-bg: color-mix(in oklab, rgb(245 158 11) 15%, var(--background));
|
||||
--data-grid-row-number-deleted-bg: color-mix(in oklab, var(--destructive) 15%, var(--background));
|
||||
--data-grid-row-number-selected-bg: color-mix(in oklab, rgb(59 130 246) 30%, var(--background));
|
||||
}
|
||||
}
|
||||
|
||||
.data-grid-header-shell {
|
||||
@@ -9347,28 +9417,36 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
}
|
||||
|
||||
.data-grid-header-cell {
|
||||
background-color: color-mix(in srgb, var(--muted) 88%, var(--background));
|
||||
background-color: rgb(239, 239, 239);
|
||||
}
|
||||
|
||||
[data-grid-root].data-grid--dark .data-grid-header-cell,
|
||||
:global(.dark) [data-grid-root] .data-grid-header-cell {
|
||||
background-color: color-mix(in srgb, var(--muted) 70%, var(--background));
|
||||
background-color: rgb(32, 32, 34) !important;
|
||||
}
|
||||
|
||||
[data-grid-root].data-grid--dark .data-grid-header-row,
|
||||
:global(.dark) [data-grid-root] .data-grid-header-row {
|
||||
color: var(--foreground);
|
||||
color: rgb(215, 215, 219);
|
||||
}
|
||||
|
||||
[data-grid-root].data-grid--dark .data-grid-header-cell:hover,
|
||||
:global(.dark) [data-grid-root] .data-grid-header-cell:hover {
|
||||
background-color: var(--accent);
|
||||
background-color: rgb(46, 47, 51) !important;
|
||||
}
|
||||
|
||||
.data-grid-header-cell--selected {
|
||||
background-color: var(--data-grid-cell-selected-single-bg) !important;
|
||||
}
|
||||
|
||||
:global(.dark) [data-grid-root] {
|
||||
--data-grid-cell-selected-bg: rgb(20, 40, 60);
|
||||
--data-grid-cell-selected-single-bg: rgb(30, 64, 96);
|
||||
--data-grid-cell-selected-dirty-bg: rgb(76, 66, 38);
|
||||
--data-grid-cell-selected-border: rgb(96, 165, 250);
|
||||
--data-grid-row-number-selected-bg: rgb(30, 64, 96);
|
||||
}
|
||||
|
||||
[data-grid-root].data-grid--dark .data-grid-header-cell--selected,
|
||||
[data-grid-root].data-grid--dark .transpose-record-header-selected,
|
||||
[data-grid-root].data-grid--dark .transpose-record-header-active,
|
||||
@@ -9376,7 +9454,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
:global(.dark) [data-grid-root] .transpose-record-header-selected,
|
||||
:global(.dark) [data-grid-root] .transpose-record-header-active {
|
||||
background-color: var(--data-grid-cell-selected-single-bg) !important;
|
||||
color: var(--foreground) !important;
|
||||
color: rgb(244, 244, 245) !important;
|
||||
}
|
||||
|
||||
.data-grid-row {
|
||||
@@ -9389,12 +9467,12 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
|
||||
/* 冻结列:不透明背景遮挡滚动的非冻结列;状态 class 的 !important 会覆盖此项 */
|
||||
.data-grid-cell--frozen {
|
||||
background-color: var(--data-grid-cell-bg, var(--background)) !important;
|
||||
background-color: var(--data-grid-cell-bg, rgb(255, 255, 255)) !important;
|
||||
}
|
||||
|
||||
/* 冻结列分隔线:与 Canvas 模式和列头一致(2px 深色右边框) */
|
||||
.data-grid-cell--frozen-separator {
|
||||
border-right: 2px solid color-mix(in srgb, var(--border) 80%, var(--foreground)) !important;
|
||||
border-right: 2px solid rgb(100, 116, 139) !important;
|
||||
}
|
||||
|
||||
.data-grid-row-number {
|
||||
@@ -9847,28 +9925,16 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
|
||||
background-color: var(--data-grid-cell-selected-dirty-bg) !important;
|
||||
}
|
||||
|
||||
.data-grid-row-number--status-draft {
|
||||
border: 1px solid color-mix(in srgb, var(--muted-foreground) 20%, transparent);
|
||||
background-color: color-mix(in srgb, var(--muted) 20%, transparent);
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.data-grid-row-number--status-new {
|
||||
border: 1px solid color-mix(in srgb, var(--success) 40%, transparent);
|
||||
.data-grid-row-number.bg-emerald-500\/15 {
|
||||
background-color: var(--data-grid-row-number-new-bg);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.data-grid-row-number--status-edited {
|
||||
border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
|
||||
.data-grid-row-number.bg-amber-500\/15 {
|
||||
background-color: var(--data-grid-row-number-edited-bg);
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.data-grid-row-number--status-deleted {
|
||||
border: 1px solid color-mix(in srgb, var(--destructive) 40%, transparent);
|
||||
.data-grid-row-number.bg-destructive\/15 {
|
||||
background-color: var(--data-grid-row-number-deleted-bg);
|
||||
color: var(--destructive);
|
||||
}
|
||||
|
||||
.active-row > .data-grid-row-number {
|
||||
|
||||
@@ -39,36 +39,7 @@ describe("data grid paint theme", () => {
|
||||
expect(resolveDataGridPaintTheme({ getVar: emptyCssVariable, isDark: true }).rowNumberActive).toBe(DATA_GRID_DARK_ACTIVE_ROW_BG);
|
||||
});
|
||||
|
||||
it("reads semantic success/warning tokens when present", () => {
|
||||
const vars: Record<string, string> = {
|
||||
"--background": "rgb(255, 255, 255)",
|
||||
"--foreground": "rgb(10, 10, 10)",
|
||||
"--muted-foreground": "rgb(115, 115, 115)",
|
||||
"--primary": "rgb(23, 23, 23)",
|
||||
"--destructive": "rgb(231, 0, 11)",
|
||||
"--accent": "rgb(245, 245, 245)",
|
||||
"--border": "rgb(229, 229, 229)",
|
||||
"--muted": "rgb(245, 245, 245)",
|
||||
"--success": "rgb(22, 163, 74)",
|
||||
"--warning": "rgb(217, 119, 6)",
|
||||
"--success-bg": "rgb(220, 252, 231)",
|
||||
"--warning-bg": "rgb(254, 243, 199)",
|
||||
"--color-error-bg": "rgb(254, 226, 226)",
|
||||
};
|
||||
|
||||
const theme = resolveDataGridPaintTheme({
|
||||
getVar: (name) => vars[name] ?? "",
|
||||
isDark: false,
|
||||
});
|
||||
|
||||
expect(theme.rowNumberTextNew).toBe("rgb(22, 163, 74)");
|
||||
expect(theme.rowNumberTextEdited).toBe("rgb(217, 119, 6)");
|
||||
expect(theme.rowNumberNew).toBe("rgb(220, 252, 231)");
|
||||
expect(theme.cellDirty).toBe("rgb(254, 243, 199)");
|
||||
expect(theme.rowDeleted).toBe("rgb(254, 226, 226)");
|
||||
});
|
||||
|
||||
it("derives selection border from ring/primary instead of the low-contrast border token", () => {
|
||||
it("keeps the classic blue selection palette instead of theme accent/ring mixing", () => {
|
||||
const vars: Record<string, string> = {
|
||||
"--background": "rgb(255, 255, 255)",
|
||||
"--foreground": "rgb(10, 10, 10)",
|
||||
@@ -79,19 +50,32 @@ describe("data grid paint theme", () => {
|
||||
"--border": "rgb(229, 229, 229)",
|
||||
"--ring": "rgb(23, 23, 23)",
|
||||
"--muted": "rgb(245, 245, 245)",
|
||||
"--success": "rgb(22, 163, 74)",
|
||||
"--warning": "rgb(217, 119, 6)",
|
||||
};
|
||||
|
||||
const theme = resolveDataGridPaintTheme({
|
||||
const light = resolveDataGridPaintTheme({
|
||||
getVar: (name) => vars[name] ?? "",
|
||||
isDark: false,
|
||||
});
|
||||
const dark = resolveDataGridPaintTheme({
|
||||
getVar: (name) => vars[name] ?? "",
|
||||
isDark: true,
|
||||
});
|
||||
|
||||
expect(theme.cellSelectedBorder).toBe("rgb(23, 23, 23)");
|
||||
expect(theme.cellSelectedBorder).not.toBe(vars["--border"]);
|
||||
expect(contrastRatio(theme.cellSelectedBorder, theme.cellSelected)).toBeGreaterThanOrEqual(3);
|
||||
expect(light.cellSelected).toBe("rgb(239, 246, 255)");
|
||||
expect(light.cellSelectedBorder).toBe("rgb(59, 130, 246)");
|
||||
expect(light.cellSelectedSingle).toBe("rgb(191, 219, 254)");
|
||||
expect(light.rowNumberTextNew).toBe("rgb(0, 122, 85)");
|
||||
expect(light.rowNumberTextEdited).toBe("rgb(187, 77, 0)");
|
||||
expect(contrastRatio(light.cellSelectedBorder, light.cellSelected)).toBeGreaterThanOrEqual(3);
|
||||
|
||||
expect(dark.cellSelected).toBe("rgb(20, 40, 60)");
|
||||
expect(dark.cellSelectedBorder).toBe("rgb(96, 165, 250)");
|
||||
expect(dark.cellSelectedSingle).toBe("rgb(30, 64, 96)");
|
||||
});
|
||||
|
||||
it("honors an explicit --data-grid-cell-selected-border token when provided", () => {
|
||||
it("honors an explicit --data-grid-cell-selected-border token when provided in light mode", () => {
|
||||
const vars: Record<string, string> = {
|
||||
"--background": "rgb(255, 255, 255)",
|
||||
"--foreground": "rgb(10, 10, 10)",
|
||||
@@ -100,7 +84,6 @@ describe("data grid paint theme", () => {
|
||||
"--destructive": "rgb(231, 0, 11)",
|
||||
"--accent": "rgb(226, 226, 226)",
|
||||
"--border": "rgb(229, 229, 229)",
|
||||
"--ring": "rgb(161, 161, 161)",
|
||||
"--muted": "rgb(245, 245, 245)",
|
||||
"--data-grid-cell-selected-border": "rgb(37, 99, 235)",
|
||||
};
|
||||
|
||||
@@ -246,33 +246,26 @@ export function resolveDataGridPaintTheme(options: { getVar: (name: string) => s
|
||||
const primary = cssVarColor(getVar, "--primary", isDark ? "rgb(208, 208, 214)" : "rgb(23, 23, 23)");
|
||||
const destructive = cssVarColor(getVar, "--destructive", isDark ? "rgb(243, 98, 95)" : "rgb(231, 0, 11)");
|
||||
const accent = cssVarColor(getVar, "--accent", isDark ? "rgb(46, 47, 51)" : "rgb(245, 245, 245)");
|
||||
const success = cssVarColor(getVar, "--success", isDark ? "rgb(74, 222, 128)" : "rgb(22, 163, 74)");
|
||||
const warning = cssVarColor(getVar, "--warning", isDark ? "rgb(251, 191, 36)" : "rgb(217, 119, 6)");
|
||||
const successBg = paintToken(getVar, "--success-bg", isDark ? DATA_GRID_DARK_ROW_NUMBER_NEW_BG : DATA_GRID_LIGHT_ROW_NUMBER_NEW_BG);
|
||||
const warningBg = paintToken(getVar, "--warning-bg", isDark ? DATA_GRID_DARK_ROW_NUMBER_EDITED_BG : DATA_GRID_LIGHT_ROW_NUMBER_EDITED_BG);
|
||||
const destructiveBg = paintToken(getVar, "--color-error-bg", isDark ? DATA_GRID_DARK_ROW_NUMBER_DELETED_BG : DATA_GRID_LIGHT_ROW_NUMBER_DELETED_BG);
|
||||
const activeSurface = paintToken(getVar, "--data-grid-cell-active-bg", dataGridActiveRowBackground(isDark));
|
||||
const activeSurface = dataGridActiveRowBackground(isDark);
|
||||
const rowMuted = isDark ? DATA_GRID_DARK_STRIPED_ROW_BG : DATA_GRID_LIGHT_STRIPED_ROW_BG;
|
||||
const rowNew = paintToken(getVar, "--muted", isDark ? "rgb(51, 51, 55)" : "rgb(243, 243, 243)");
|
||||
const rowDeleted = destructiveBg;
|
||||
const rowNew = isDark ? "rgb(51, 51, 55)" : "rgb(243, 243, 243)";
|
||||
const rowDeleted = isDark ? "rgb(55, 31, 32)" : "rgb(255, 244, 244)";
|
||||
const cellActive = activeSurface;
|
||||
const cellDirty = warningBg;
|
||||
const cellSelected = paintToken(getVar, "--accent", isDark ? "rgb(20, 40, 60)" : "rgb(239, 246, 255)");
|
||||
const cellSelectedDirty = warningBg;
|
||||
// Selection outline must stay readable on the selected fill (WCAG non-text ~3:1).
|
||||
// Prefer ring/primary over the generic border token, which is often near the fill.
|
||||
const cellSelectedBorder = paintToken(getVar, "--ring", isDark ? "rgb(96, 165, 250)" : primary);
|
||||
const cellSelectedSingle = paintToken(getVar, "--muted", isDark ? "rgb(30, 64, 96)" : "rgb(191, 219, 254)");
|
||||
const cellDirty = isDark ? "rgb(94, 75, 26)" : "rgb(255, 248, 230)";
|
||||
const cellSelected = isDark ? "rgb(20, 40, 60)" : "rgb(239, 246, 255)";
|
||||
const cellSelectedDirty = isDark ? "rgb(76, 66, 38)" : "rgb(235, 224, 184)";
|
||||
const cellSelectedBorder = isDark ? "rgb(96, 165, 250)" : "rgb(59, 130, 246)";
|
||||
const cellSelectedSingle = isDark ? "rgb(30, 64, 96)" : "rgb(191, 219, 254)";
|
||||
const cellHover = accent;
|
||||
const cellSearch = paintToken(getVar, "--warning-bg", isDark ? DATA_GRID_DARK_SEARCH_COLORS.match : "rgb(253, 245, 184)");
|
||||
const cellCurrentSearch = paintToken(getVar, "--warning-bg", isDark ? DATA_GRID_DARK_SEARCH_COLORS.current : "rgba(253, 224, 71, 0.52)");
|
||||
const cellCurrentSearchBorder = paintToken(getVar, "--warning", isDark ? DATA_GRID_DARK_SEARCH_COLORS.currentBorder : "rgba(234, 179, 8, 0.82)");
|
||||
const cellSearch = isDark ? DATA_GRID_DARK_SEARCH_COLORS.match : "rgb(253, 245, 184)";
|
||||
const cellCurrentSearch = isDark ? DATA_GRID_DARK_SEARCH_COLORS.current : "rgba(253, 224, 71, 0.52)";
|
||||
const cellCurrentSearchBorder = isDark ? DATA_GRID_DARK_SEARCH_COLORS.currentBorder : "rgba(234, 179, 8, 0.82)";
|
||||
const rowNumberDefault = isDark ? DATA_GRID_DARK_ROW_NUMBER_BG : paintToken(getVar, "--data-grid-row-number-default-bg", "rgb(255, 255, 255)");
|
||||
const rowNumberNew = successBg;
|
||||
const rowNumberEdited = warningBg;
|
||||
const rowNumberDeleted = destructiveBg;
|
||||
const rowNumberNew = isDark ? DATA_GRID_DARK_ROW_NUMBER_NEW_BG : DATA_GRID_LIGHT_ROW_NUMBER_NEW_BG;
|
||||
const rowNumberEdited = isDark ? DATA_GRID_DARK_ROW_NUMBER_EDITED_BG : DATA_GRID_LIGHT_ROW_NUMBER_EDITED_BG;
|
||||
const rowNumberDeleted = isDark ? DATA_GRID_DARK_ROW_NUMBER_DELETED_BG : DATA_GRID_LIGHT_ROW_NUMBER_DELETED_BG;
|
||||
const rowNumberActive = activeSurface;
|
||||
const rowNumberSelected = cellSelectedSingle;
|
||||
const rowNumberSelected = isDark ? "rgb(30, 64, 96)" : "rgb(191, 219, 254)";
|
||||
|
||||
return {
|
||||
background,
|
||||
@@ -280,29 +273,29 @@ export function resolveDataGridPaintTheme(options: { getVar: (name: string) => s
|
||||
foreground,
|
||||
mutedForeground,
|
||||
primary,
|
||||
rowMuted: paintToken(getVar, "--data-grid-row-muted-bg", rowMuted),
|
||||
rowNew: paintToken(getVar, "--data-grid-row-new-bg", rowNew),
|
||||
rowDeleted: paintToken(getVar, "--data-grid-row-deleted-bg", rowDeleted),
|
||||
cellActive: paintToken(getVar, "--data-grid-cell-active-bg", cellActive),
|
||||
cellDirty: paintToken(getVar, "--data-grid-cell-dirty-bg", cellDirty),
|
||||
cellSelected: paintToken(getVar, "--data-grid-cell-selected-bg", cellSelected),
|
||||
cellSelectedDirty: paintToken(getVar, "--data-grid-cell-selected-dirty-bg", cellSelectedDirty),
|
||||
cellSelectedBorder: paintToken(getVar, "--data-grid-cell-selected-border", cellSelectedBorder),
|
||||
cellSelectedSingle: paintToken(getVar, "--data-grid-cell-selected-single-bg", cellSelectedSingle),
|
||||
cellSelectedSingleBorder: paintToken(getVar, "--data-grid-cell-selected-single-border", primary),
|
||||
cellHover: paintToken(getVar, "--data-grid-cell-hover-bg", cellHover),
|
||||
cellSearch: paintToken(getVar, "--data-grid-cell-search-bg", cellSearch),
|
||||
cellCurrentSearch: paintToken(getVar, "--data-grid-cell-current-search-bg", cellCurrentSearch),
|
||||
cellCurrentSearchBorder: paintToken(getVar, "--data-grid-cell-current-search-border", cellCurrentSearchBorder),
|
||||
rowMuted: isDark ? rowMuted : paintToken(getVar, "--data-grid-row-muted-bg", rowMuted),
|
||||
rowNew: isDark ? rowNew : paintToken(getVar, "--data-grid-row-new-bg", rowNew),
|
||||
rowDeleted: isDark ? rowDeleted : paintToken(getVar, "--data-grid-row-deleted-bg", rowDeleted),
|
||||
cellActive: isDark ? cellActive : paintToken(getVar, "--data-grid-cell-active-bg", cellActive),
|
||||
cellDirty: isDark ? cellDirty : paintToken(getVar, "--data-grid-cell-dirty-bg", cellDirty),
|
||||
cellSelected: isDark ? cellSelected : paintToken(getVar, "--data-grid-cell-selected-bg", cellSelected),
|
||||
cellSelectedDirty: isDark ? cellSelectedDirty : paintToken(getVar, "--data-grid-cell-selected-dirty-bg", cellSelectedDirty),
|
||||
cellSelectedBorder: isDark ? cellSelectedBorder : paintToken(getVar, "--data-grid-cell-selected-border", cellSelectedBorder),
|
||||
cellSelectedSingle: isDark ? cellSelectedSingle : paintToken(getVar, "--data-grid-cell-selected-single-bg", cellSelectedSingle),
|
||||
cellSelectedSingleBorder: isDark ? primary : paintToken(getVar, "--data-grid-cell-selected-single-border", primary),
|
||||
cellHover: isDark ? cellHover : paintToken(getVar, "--data-grid-cell-hover-bg", cellHover),
|
||||
cellSearch: isDark ? cellSearch : paintToken(getVar, "--data-grid-cell-search-bg", cellSearch),
|
||||
cellCurrentSearch: isDark ? cellCurrentSearch : paintToken(getVar, "--data-grid-cell-current-search-bg", cellCurrentSearch),
|
||||
cellCurrentSearchBorder: isDark ? cellCurrentSearchBorder : paintToken(getVar, "--data-grid-cell-current-search-border", cellCurrentSearchBorder),
|
||||
rowNumberDefault,
|
||||
rowNumberNew: paintToken(getVar, "--data-grid-row-number-new-bg", rowNumberNew),
|
||||
rowNumberEdited: paintToken(getVar, "--data-grid-row-number-edited-bg", rowNumberEdited),
|
||||
rowNumberDeleted: paintToken(getVar, "--data-grid-row-number-deleted-bg", rowNumberDeleted),
|
||||
rowNumberActive: paintToken(getVar, "--data-grid-row-number-active-bg", rowNumberActive),
|
||||
rowNumberSelected: paintToken(getVar, "--data-grid-row-number-selected-bg", rowNumberSelected),
|
||||
rowNumberNew: isDark ? rowNumberNew : paintToken(getVar, "--data-grid-row-number-new-bg", rowNumberNew),
|
||||
rowNumberEdited: isDark ? rowNumberEdited : paintToken(getVar, "--data-grid-row-number-edited-bg", rowNumberEdited),
|
||||
rowNumberDeleted: isDark ? rowNumberDeleted : paintToken(getVar, "--data-grid-row-number-deleted-bg", rowNumberDeleted),
|
||||
rowNumberActive: isDark ? rowNumberActive : paintToken(getVar, "--data-grid-row-number-active-bg", rowNumberActive),
|
||||
rowNumberSelected: isDark ? rowNumberSelected : paintToken(getVar, "--data-grid-row-number-selected-bg", rowNumberSelected),
|
||||
rowNumberTextClean: mutedForeground,
|
||||
rowNumberTextNew: success,
|
||||
rowNumberTextEdited: warning,
|
||||
rowNumberTextNew: isDark ? "rgb(94, 233, 181)" : "rgb(0, 122, 85)",
|
||||
rowNumberTextEdited: isDark ? "rgb(255, 210, 48)" : "rgb(187, 77, 0)",
|
||||
rowNumberTextDeleted: destructive,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user