Merge branch 'dev/hybrid-canvas-grid'
# Conflicts: # apps/desktop/src/components/grid/DataGrid.vue # apps/desktop/src/stores/settingsStore.ts
This commit is contained in:
commit
df32a46080
10 files changed
+1180
-39
No files matched your search
@@ -0,0 +1,396 @@
|
||||
import type { CellValue } from "@/lib/cellValue";
|
||||
import type { RowStatus } from "@/lib/gridRowStatus";
|
||||
import { DATA_GRID_DARK_SEARCH_COLORS, resolveDataGridPaintTheme } from "@/lib/dataGridPaintTheme";
|
||||
|
||||
export const CANVAS_DATA_GRID_ROW_HEIGHT = 26;
|
||||
|
||||
export interface CanvasDataGridRow {
|
||||
id: number;
|
||||
displayIndex: number;
|
||||
data: CellValue[];
|
||||
isNew: boolean;
|
||||
isDeleted: boolean;
|
||||
isDirtyCol: boolean[];
|
||||
status: RowStatus;
|
||||
}
|
||||
|
||||
export interface CanvasHoverCell {
|
||||
rowIndex: number;
|
||||
visibleColIdx: number;
|
||||
}
|
||||
|
||||
export interface CanvasEditingCell {
|
||||
rowId: number;
|
||||
col: number;
|
||||
}
|
||||
|
||||
export interface CanvasSingleSelectedCell {
|
||||
rowIndex: number;
|
||||
visibleColIdx: number;
|
||||
}
|
||||
|
||||
export interface CanvasSearchMatch {
|
||||
displayRow: number;
|
||||
col: number;
|
||||
}
|
||||
|
||||
export interface DrawCanvasDataGridOptions {
|
||||
canvas: HTMLCanvasElement;
|
||||
scroller: HTMLElement;
|
||||
width: number;
|
||||
height: number;
|
||||
isDark: boolean;
|
||||
rows: CanvasDataGridRow[];
|
||||
renderedColumnWidths: number[];
|
||||
visibleColumnIndexes: number[];
|
||||
rowNumberWidth: number;
|
||||
hoverCell: CanvasHoverCell | null;
|
||||
isScrolling: boolean;
|
||||
editingCell: CanvasEditingCell | null;
|
||||
singleSelectedCell: CanvasSingleSelectedCell | null;
|
||||
searchMatchKeys: ReadonlySet<string>;
|
||||
currentSearchMatch: CanvasSearchMatch | null;
|
||||
formatCell: (value: CellValue, columnIndex: number) => string;
|
||||
isRowActive: (rowIndex: number) => boolean;
|
||||
isRowSelected: (rowId: number) => boolean;
|
||||
rowCellsUseSelectionVisual: (rowId: number) => boolean;
|
||||
cellIsSelected: (rowIndex: number, visibleColIdx: number) => boolean;
|
||||
cellCanHover: (row: CanvasDataGridRow, actualColIdx: number) => boolean;
|
||||
}
|
||||
|
||||
type NumericCanvasContext = CanvasRenderingContext2D & {
|
||||
fontVariantNumeric?: string;
|
||||
};
|
||||
|
||||
function setCanvasNumericVariant(ctx: CanvasRenderingContext2D, value: "normal" | "tabular-nums") {
|
||||
const numericCtx = ctx as NumericCanvasContext;
|
||||
if ("fontVariantNumeric" in numericCtx) numericCtx.fontVariantNumeric = value;
|
||||
}
|
||||
|
||||
function canvasTabularFontFamily(fontFamily: string): string {
|
||||
return `"Geist Variable Tabular", ${fontFamily}`;
|
||||
}
|
||||
|
||||
function fitCanvasText(ctx: CanvasRenderingContext2D, text: string, maxWidth: number): string {
|
||||
if (maxWidth <= 0 || ctx.measureText(text).width <= maxWidth) return text;
|
||||
const ellipsis = "...";
|
||||
if (ctx.measureText(ellipsis).width > maxWidth) return "";
|
||||
let low = 0;
|
||||
let high = text.length;
|
||||
while (low < high) {
|
||||
const mid = Math.ceil((low + high) / 2);
|
||||
if (ctx.measureText(`${text.slice(0, mid)}${ellipsis}`).width <= maxWidth) low = mid;
|
||||
else high = mid - 1;
|
||||
}
|
||||
return `${text.slice(0, low)}${ellipsis}`;
|
||||
}
|
||||
|
||||
function canvasFont(style: {
|
||||
family: string;
|
||||
sizePx: number;
|
||||
style?: string;
|
||||
weight?: string | number;
|
||||
lineHeight?: string;
|
||||
}): string {
|
||||
const fontStyle = style.style && style.style !== "normal" ? `${style.style} ` : "";
|
||||
const fontWeight = style.weight && style.weight !== "400" && style.weight !== "normal" ? `${style.weight} ` : "";
|
||||
const lineHeight = style.lineHeight && style.lineHeight !== "normal" ? `/${style.lineHeight}` : "";
|
||||
return `${fontStyle}${fontWeight}${style.sizePx}px${lineHeight} ${style.family}`;
|
||||
}
|
||||
|
||||
function columnOffsets(widths: number[]): number[] {
|
||||
const offsets = Array.from({ length: widths.length + 1 }, () => 0);
|
||||
offsets[0] = 0;
|
||||
for (let index = 0; index < widths.length; index++) {
|
||||
offsets[index + 1] = offsets[index] + (widths[index] ?? 0);
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
function firstVisibleColumn(offsets: number[], contentStart: number): number {
|
||||
let low = 0;
|
||||
let high = Math.max(0, offsets.length - 2);
|
||||
while (low < high) {
|
||||
const mid = Math.floor((low + high) / 2);
|
||||
if ((offsets[mid + 1] ?? 0) < contentStart) low = mid + 1;
|
||||
else high = mid;
|
||||
}
|
||||
return low;
|
||||
}
|
||||
|
||||
export function drawCanvasDataGrid(options: DrawCanvasDataGridOptions) {
|
||||
const {
|
||||
canvas,
|
||||
scroller,
|
||||
width,
|
||||
height,
|
||||
isDark,
|
||||
rows,
|
||||
renderedColumnWidths,
|
||||
visibleColumnIndexes,
|
||||
rowNumberWidth,
|
||||
hoverCell,
|
||||
isScrolling,
|
||||
editingCell,
|
||||
singleSelectedCell,
|
||||
searchMatchKeys,
|
||||
currentSearchMatch,
|
||||
formatCell,
|
||||
isRowActive,
|
||||
isRowSelected,
|
||||
rowCellsUseSelectionVisual,
|
||||
cellIsSelected,
|
||||
cellCanHover,
|
||||
} = options;
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const pixelWidth = Math.floor(width * dpr);
|
||||
const pixelHeight = Math.floor(height * dpr);
|
||||
if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
|
||||
canvas.width = pixelWidth;
|
||||
canvas.height = pixelHeight;
|
||||
}
|
||||
canvas.style.width = `${width}px`;
|
||||
canvas.style.height = `${height}px`;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
const canvasStyle = getComputedStyle(canvas);
|
||||
const fontFamily =
|
||||
canvasStyle.fontFamily || `"Geist Variable", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif`;
|
||||
const fontSize = Number.parseFloat(canvasStyle.fontSize) || 12;
|
||||
const lineHeight = canvasStyle.lineHeight;
|
||||
const normalFont = canvasFont({
|
||||
family: fontFamily,
|
||||
sizePx: fontSize,
|
||||
weight: canvasStyle.fontWeight,
|
||||
lineHeight,
|
||||
});
|
||||
const tabularFont = canvasFont({
|
||||
family: canvasTabularFontFamily(fontFamily),
|
||||
sizePx: fontSize,
|
||||
weight: canvasStyle.fontWeight,
|
||||
lineHeight,
|
||||
});
|
||||
const semiboldFont = canvasFont({ family: fontFamily, sizePx: fontSize, weight: 600, lineHeight });
|
||||
const italicFont = canvasFont({
|
||||
family: fontFamily,
|
||||
sizePx: fontSize,
|
||||
style: "italic",
|
||||
weight: canvasStyle.fontWeight,
|
||||
lineHeight,
|
||||
});
|
||||
const theme = resolveDataGridPaintTheme({
|
||||
getVar: (name) => canvasStyle.getPropertyValue(name),
|
||||
isDark,
|
||||
});
|
||||
const searchFill = isDark ? DATA_GRID_DARK_SEARCH_COLORS.match : theme.cellSearch;
|
||||
const currentSearchFill = isDark ? DATA_GRID_DARK_SEARCH_COLORS.current : theme.cellCurrentSearch;
|
||||
const currentSearchBorder = isDark ? DATA_GRID_DARK_SEARCH_COLORS.currentBorder : theme.cellCurrentSearchBorder;
|
||||
|
||||
const scrollTop = scroller.scrollTop;
|
||||
const scrollLeft = scroller.scrollLeft;
|
||||
const firstRow = Math.max(0, Math.floor(scrollTop / CANVAS_DATA_GRID_ROW_HEIGHT));
|
||||
const lastRow = Math.min(rows.length - 1, Math.ceil((scrollTop + height) / CANVAS_DATA_GRID_ROW_HEIGHT));
|
||||
|
||||
ctx.fillStyle = theme.background;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
ctx.font = normalFont;
|
||||
ctx.textBaseline = "middle";
|
||||
|
||||
const offsets = columnOffsets(renderedColumnWidths);
|
||||
const contentStart = Math.max(0, scrollLeft - rowNumberWidth);
|
||||
const firstCol = firstVisibleColumn(offsets, contentStart);
|
||||
const columnOffset = offsets[firstCol] ?? 0;
|
||||
const paintSearchMatches = !isScrolling && searchMatchKeys.size > 0;
|
||||
|
||||
for (let rowIndex = firstRow; rowIndex <= lastRow; rowIndex++) {
|
||||
const item = rows[rowIndex];
|
||||
if (!item) continue;
|
||||
const y = rowIndex * CANVAS_DATA_GRID_ROW_HEIGHT - scrollTop;
|
||||
const rowIsActive = isRowActive(item.displayIndex);
|
||||
const rowBase = item.isDeleted
|
||||
? theme.rowDeleted
|
||||
: item.isNew && !rowIsActive
|
||||
? theme.rowNew
|
||||
: item.displayIndex % 2 === 1 && !rowIsActive
|
||||
? theme.rowMuted
|
||||
: theme.background;
|
||||
ctx.globalAlpha = item.isDeleted ? 0.7 : 1;
|
||||
ctx.fillStyle = rowBase;
|
||||
ctx.fillRect(0, y, width, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
|
||||
let rowNumberFill =
|
||||
item.status === "new"
|
||||
? theme.rowNumberNew
|
||||
: item.status === "edited"
|
||||
? theme.rowNumberEdited
|
||||
: item.status === "deleted"
|
||||
? theme.rowNumberDeleted
|
||||
: theme.rowNumberDefault;
|
||||
if (rowIsActive && !item.isDeleted) rowNumberFill = theme.rowNumberActive;
|
||||
if (isRowSelected(item.id) && item.status === "clean") rowNumberFill = theme.rowNumberSelected;
|
||||
ctx.fillStyle = rowNumberFill;
|
||||
ctx.fillRect(0, y, rowNumberWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
if (
|
||||
hoverCell?.rowIndex === item.displayIndex &&
|
||||
hoverCell.visibleColIdx < 0 &&
|
||||
!isScrolling &&
|
||||
item.status === "clean" &&
|
||||
!rowIsActive &&
|
||||
!isRowSelected(item.id)
|
||||
) {
|
||||
ctx.fillStyle = theme.cellHover;
|
||||
ctx.fillRect(0, y, rowNumberWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
ctx.strokeStyle = theme.border;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(rowNumberWidth + 0.5, y);
|
||||
ctx.lineTo(rowNumberWidth + 0.5, y + CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
ctx.stroke();
|
||||
|
||||
const rowNumberText =
|
||||
item.status === "new"
|
||||
? theme.rowNumberTextNew
|
||||
: item.status === "edited"
|
||||
? theme.rowNumberTextEdited
|
||||
: item.status === "deleted"
|
||||
? theme.rowNumberTextDeleted
|
||||
: isRowSelected(item.id)
|
||||
? theme.primary
|
||||
: theme.rowNumberTextClean;
|
||||
ctx.fillStyle = rowNumberText;
|
||||
ctx.font = item.status === "new" || item.status === "edited" || isRowSelected(item.id) ? semiboldFont : normalFont;
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(String(item.displayIndex + 1), rowNumberWidth / 2, y + CANVAS_DATA_GRID_ROW_HEIGHT / 2);
|
||||
ctx.font = normalFont;
|
||||
|
||||
let x = rowNumberWidth + columnOffset - scrollLeft;
|
||||
for (let visibleColIdx = firstCol; visibleColIdx < renderedColumnWidths.length && x < width; visibleColIdx++) {
|
||||
const colWidth = renderedColumnWidths[visibleColIdx] ?? 0;
|
||||
const actualColIdx = visibleColumnIndexes[visibleColIdx];
|
||||
if (actualColIdx === undefined) {
|
||||
x += colWidth;
|
||||
continue;
|
||||
}
|
||||
if (x + colWidth >= rowNumberWidth) {
|
||||
const selectedCell = cellIsSelected(item.displayIndex, visibleColIdx);
|
||||
const rowSelectionVisual = rowCellsUseSelectionVisual(item.id);
|
||||
const isSingleSelectedCell =
|
||||
singleSelectedCell?.rowIndex === item.displayIndex && singleSelectedCell.visibleColIdx === visibleColIdx;
|
||||
const isDirtyCell = item.isDirtyCol[actualColIdx];
|
||||
const selectedFillVisual =
|
||||
rowSelectionVisual || (selectedCell && !isSingleSelectedCell && (!rowIsActive || isDirtyCell));
|
||||
const selectedBorderVisual = rowSelectionVisual || selectedCell;
|
||||
const isSearchMatch = paintSearchMatches && searchMatchKeys.has(`${item.displayIndex}:${actualColIdx}`);
|
||||
const isCurrentSearchMatch =
|
||||
paintSearchMatches &&
|
||||
currentSearchMatch?.displayRow === item.displayIndex &&
|
||||
currentSearchMatch.col === actualColIdx;
|
||||
const clippedX = Math.max(x, rowNumberWidth);
|
||||
const cellPaintWidth = colWidth - Math.max(0, clippedX - x);
|
||||
|
||||
if (isDirtyCell) {
|
||||
ctx.fillStyle = theme.cellDirty;
|
||||
ctx.fillRect(clippedX, y, cellPaintWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
if (
|
||||
hoverCell?.rowIndex === item.displayIndex &&
|
||||
hoverCell.visibleColIdx === visibleColIdx &&
|
||||
!isScrolling &&
|
||||
!isSearchMatch &&
|
||||
!isCurrentSearchMatch &&
|
||||
cellCanHover(item, actualColIdx)
|
||||
) {
|
||||
ctx.fillStyle = theme.cellHover;
|
||||
ctx.fillRect(clippedX, y, cellPaintWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
if (selectedFillVisual) {
|
||||
ctx.fillStyle = isDirtyCell ? theme.cellSelectedDirty : theme.cellSelected;
|
||||
ctx.fillRect(clippedX, y, cellPaintWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
if (rowIsActive && !item.isDeleted && !isDirtyCell) {
|
||||
ctx.fillStyle = theme.cellActive;
|
||||
ctx.fillRect(clippedX, y, cellPaintWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
if (isSearchMatch) {
|
||||
ctx.fillStyle = searchFill;
|
||||
ctx.fillRect(clippedX, y, cellPaintWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
if (isCurrentSearchMatch) {
|
||||
ctx.fillStyle = currentSearchFill;
|
||||
ctx.fillRect(clippedX, y, cellPaintWidth, CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
ctx.rect(clippedX, y, Math.min(cellPaintWidth, width - clippedX), CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
ctx.clip();
|
||||
const value = item.data[actualColIdx];
|
||||
ctx.textAlign = "left";
|
||||
ctx.fillStyle = value === null ? theme.mutedForeground : theme.foreground;
|
||||
ctx.font = value === null ? italicFont : typeof value === "number" ? tabularFont : normalFont;
|
||||
setCanvasNumericVariant(ctx, typeof value === "number" ? "tabular-nums" : "normal");
|
||||
const textLeft = x + 12;
|
||||
const textMaxWidth = Math.max(0, x + colWidth - textLeft - 12);
|
||||
const isEditingThisCell = editingCell?.rowId === item.id && editingCell.col === actualColIdx;
|
||||
const displayText = isEditingThisCell ? "" : formatCell(value, actualColIdx);
|
||||
const text = isEditingThisCell || isScrolling ? displayText : fitCanvasText(ctx, displayText, textMaxWidth);
|
||||
ctx.fillText(text, textLeft, y + CANVAS_DATA_GRID_ROW_HEIGHT / 2);
|
||||
if (item.isDeleted && text) {
|
||||
const textWidth = Math.min(ctx.measureText(text).width, textMaxWidth);
|
||||
ctx.strokeStyle = theme.foreground;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(textLeft, y + CANVAS_DATA_GRID_ROW_HEIGHT / 2);
|
||||
ctx.lineTo(textLeft + textWidth, y + CANVAS_DATA_GRID_ROW_HEIGHT / 2);
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.restore();
|
||||
setCanvasNumericVariant(ctx, "normal");
|
||||
ctx.font = normalFont;
|
||||
|
||||
ctx.strokeStyle = theme.border;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x + colWidth - 0.5, y);
|
||||
ctx.lineTo(x + colWidth - 0.5, y + CANVAS_DATA_GRID_ROW_HEIGHT);
|
||||
ctx.stroke();
|
||||
|
||||
if (selectedBorderVisual && cellPaintWidth >= 2) {
|
||||
const selectedLeftX = clippedX + 0.5;
|
||||
const selectedRightX = clippedX + cellPaintWidth - 1.5;
|
||||
const selectedTopY = y + 0.5;
|
||||
const selectedBottomY = y + CANVAS_DATA_GRID_ROW_HEIGHT - 1.5;
|
||||
ctx.strokeStyle = theme.cellSelectedBorder;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(selectedLeftX, selectedTopY);
|
||||
ctx.lineTo(selectedRightX, selectedTopY);
|
||||
ctx.moveTo(selectedLeftX, selectedBottomY);
|
||||
ctx.lineTo(selectedRightX, selectedBottomY);
|
||||
ctx.moveTo(selectedLeftX, selectedTopY);
|
||||
ctx.lineTo(selectedLeftX, selectedBottomY);
|
||||
ctx.moveTo(selectedRightX, selectedTopY);
|
||||
ctx.lineTo(selectedRightX, selectedBottomY);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
if (isCurrentSearchMatch) {
|
||||
ctx.strokeStyle = currentSearchBorder;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.strokeRect(clippedX + 1, y + 1, Math.max(0, cellPaintWidth - 2), CANVAS_DATA_GRID_ROW_HEIGHT - 2);
|
||||
ctx.lineWidth = 1;
|
||||
}
|
||||
}
|
||||
x += colWidth;
|
||||
}
|
||||
if (!isRowSelected(item.id)) {
|
||||
ctx.strokeStyle = theme.border;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(0, y + CANVAS_DATA_GRID_ROW_HEIGHT - 0.5);
|
||||
ctx.lineTo(width, y + CANVAS_DATA_GRID_ROW_HEIGHT - 0.5);
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
export interface DataGridPaintTheme {
|
||||
background: string;
|
||||
border: string;
|
||||
foreground: string;
|
||||
mutedForeground: string;
|
||||
primary: string;
|
||||
rowMuted: string;
|
||||
rowNew: string;
|
||||
rowDeleted: string;
|
||||
cellActive: string;
|
||||
cellDirty: string;
|
||||
cellSelected: string;
|
||||
cellSelectedDirty: string;
|
||||
cellSelectedBorder: string;
|
||||
cellHover: string;
|
||||
cellSearch: string;
|
||||
cellCurrentSearch: string;
|
||||
cellCurrentSearchBorder: string;
|
||||
rowNumberDefault: string;
|
||||
rowNumberNew: string;
|
||||
rowNumberEdited: string;
|
||||
rowNumberDeleted: string;
|
||||
rowNumberActive: string;
|
||||
rowNumberSelected: string;
|
||||
rowNumberTextClean: string;
|
||||
rowNumberTextNew: string;
|
||||
rowNumberTextEdited: string;
|
||||
rowNumberTextDeleted: string;
|
||||
}
|
||||
|
||||
export const DATA_GRID_DARK_SEARCH_COLORS = {
|
||||
match: "rgb(72 57 8)",
|
||||
current: "rgb(116 87 0)",
|
||||
currentBorder: "rgb(239 177 0)",
|
||||
} as const;
|
||||
|
||||
export function cssVarColor(getVar: (name: string) => string, name: string, fallback: string): string {
|
||||
const value = getVar(name).trim();
|
||||
if (!value) return fallback;
|
||||
return value.startsWith("#") || /^(rgb|hsl|oklch|oklab|lab|lch|color-mix)\(/.test(value) ? value : `hsl(${value})`;
|
||||
}
|
||||
|
||||
function resolveCssVarReferences(value: string, getVar: (name: string) => string, depth = 0): string {
|
||||
if (depth > 6 || !value.includes("var(")) return value;
|
||||
return value.replace(/var\(\s*(--[\w-]+)(?:\s*,\s*([^)]+))?\s*\)/g, (_match, name: string, fallback?: string) => {
|
||||
const resolved = getVar(name).trim() || fallback?.trim() || "";
|
||||
if (!resolved) return "";
|
||||
const nested = resolveCssVarReferences(resolved, getVar, depth + 1);
|
||||
return cssVarColor(() => nested, name, nested);
|
||||
});
|
||||
}
|
||||
|
||||
function paintToken(getVar: (name: string) => string, name: string, fallback: string): string {
|
||||
const value = resolveCssVarReferences(getVar(name).trim(), getVar);
|
||||
if (!value) return fallback;
|
||||
return value.startsWith("#") || /^(rgb|hsl|oklch|oklab|lab|lch|color-mix)\(/.test(value)
|
||||
? value
|
||||
: cssVarColor(() => value, name, fallback);
|
||||
}
|
||||
|
||||
export function resolveDataGridPaintTheme(options: {
|
||||
getVar: (name: string) => string;
|
||||
isDark: boolean;
|
||||
}): DataGridPaintTheme {
|
||||
const { getVar, isDark } = options;
|
||||
const background = cssVarColor(getVar, "--background", isDark ? "oklch(0.145 0 0)" : "oklch(1 0 0)");
|
||||
const foreground = cssVarColor(getVar, "--foreground", isDark ? "oklch(0.985 0 0)" : "oklch(0.145 0 0)");
|
||||
const mutedForeground = cssVarColor(getVar, "--muted-foreground", isDark ? "oklch(0.708 0 0)" : "oklch(0.556 0 0)");
|
||||
const primary = cssVarColor(getVar, "--primary", isDark ? "oklch(0.922 0 0)" : "oklch(0.205 0 0)");
|
||||
const muted = cssVarColor(getVar, "--muted", isDark ? "oklch(0.269 0 0)" : "oklch(0.97 0 0)");
|
||||
const destructive = cssVarColor(getVar, "--destructive", "oklch(0.6 0.22 25)");
|
||||
const accent = cssVarColor(getVar, "--accent", isDark ? "oklch(0.269 0 0)" : "oklch(0.97 0 0)");
|
||||
const yellow500 = "oklch(0.795 0.184 86.047)";
|
||||
const activeSurface = isDark ? "rgb(64 64 64)" : `color-mix(in oklab, ${primary} 10%, ${background})`;
|
||||
const rowMuted = `color-mix(in oklab, ${muted} 30%, transparent)`;
|
||||
const rowNew = `color-mix(in oklab, ${primary} 5%, transparent)`;
|
||||
const rowDeleted = `color-mix(in oklab, ${destructive} 5%, transparent)`;
|
||||
const cellActive = activeSurface;
|
||||
const cellDirty = `color-mix(in oklab, ${yellow500} 10%, transparent)`;
|
||||
const cellSelected = `color-mix(in oklab, ${primary} 25%, transparent)`;
|
||||
const cellSelectedDirty = `color-mix(in oklab, oklch(0.8 0.15 85) 30%, color-mix(in oklab, ${primary} 18%, transparent))`;
|
||||
const cellSelectedBorder = `color-mix(in oklab, ${primary} 70%, transparent)`;
|
||||
const cellHover = `color-mix(in oklab, ${accent} 50%, transparent)`;
|
||||
const cellSearch = isDark ? DATA_GRID_DARK_SEARCH_COLORS.match : "rgb(253 245 184)";
|
||||
const cellCurrentSearch = isDark ? DATA_GRID_DARK_SEARCH_COLORS.current : "rgb(253 224 71 / 52%)";
|
||||
const cellCurrentSearchBorder = isDark ? DATA_GRID_DARK_SEARCH_COLORS.currentBorder : "rgb(234 179 8 / 82%)";
|
||||
const rowNumberDefault = isDark ? "rgb(15 15 15)" : "rgb(255 255 255)";
|
||||
const rowNumberNew = `color-mix(in oklab, rgb(16 185 129) 15%, ${background})`;
|
||||
const rowNumberEdited = `color-mix(in oklab, rgb(245 158 11) 15%, ${background})`;
|
||||
const rowNumberDeleted = `color-mix(in oklab, ${destructive} 15%, ${background})`;
|
||||
const rowNumberActive = activeSurface;
|
||||
const rowNumberSelected = `color-mix(in oklab, ${primary} 25%, ${background})`;
|
||||
|
||||
return {
|
||||
background,
|
||||
border: cssVarColor(getVar, "--border", isDark ? "rgb(63 63 70)" : "rgb(229 231 235)"),
|
||||
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),
|
||||
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),
|
||||
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),
|
||||
rowNumberTextClean: mutedForeground,
|
||||
rowNumberTextNew: isDark ? "oklch(0.845 0.143 164.978)" : "oklch(0.508 0.118 165.612)",
|
||||
rowNumberTextEdited: isDark ? "oklch(0.879 0.169 91.605)" : "oklch(0.555 0.163 48.998)",
|
||||
rowNumberTextDeleted: destructive,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user