Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
CI / CI OK (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Issue Close Require / close-issues (push) Has been cancelled
Close stale issues / stale (push) Has been cancelled
147 lines
4.1 KiB
TypeScript
147 lines
4.1 KiB
TypeScript
export interface SpreadsheetTheme {
|
|
headerBg: string;
|
|
headerText: string;
|
|
cellBg: string;
|
|
border: string;
|
|
text: string;
|
|
textMuted: string;
|
|
selectionBg: string;
|
|
selectionBorder: string;
|
|
dirtyBg: string;
|
|
rowNumBg: string;
|
|
fillHandle: string;
|
|
fixedShadow: string;
|
|
imagePlaceholder: string;
|
|
findMatchBg: string;
|
|
findActiveMatchBg: string;
|
|
findActiveBorder: string;
|
|
}
|
|
|
|
export function getSpreadsheetTheme(isDark: boolean): SpreadsheetTheme {
|
|
if (isDark) {
|
|
return {
|
|
headerBg: '#1f1f1f',
|
|
headerText: 'rgba(255, 255, 255, 0.85)',
|
|
cellBg: '#141414',
|
|
border: '#424242',
|
|
text: 'rgba(255, 255, 255, 0.85)',
|
|
textMuted: 'rgba(255, 255, 255, 0.45)',
|
|
selectionBg: 'rgba(22, 93, 255, 0.25)',
|
|
selectionBorder: '#1668dc',
|
|
dirtyBg: 'rgba(255, 125, 0, 0.2)',
|
|
rowNumBg: '#1a1a1a',
|
|
fillHandle: '#1668dc',
|
|
fixedShadow: 'rgba(0, 0, 0, 0.45)',
|
|
imagePlaceholder: '#303030',
|
|
findMatchBg: 'rgba(255, 212, 0, 0.35)',
|
|
findActiveMatchBg: 'rgba(255, 212, 0, 0.55)',
|
|
findActiveBorder: '#faad14',
|
|
};
|
|
}
|
|
return {
|
|
headerBg: '#f5f7fa',
|
|
headerText: '#1d2129',
|
|
cellBg: '#ffffff',
|
|
border: '#e5e6eb',
|
|
text: '#1d2129',
|
|
textMuted: '#86909c',
|
|
selectionBg: 'rgba(22, 93, 255, 0.08)',
|
|
selectionBorder: '#165dff',
|
|
dirtyBg: 'rgba(255, 125, 0, 0.12)',
|
|
rowNumBg: '#fafafa',
|
|
fillHandle: '#165dff',
|
|
fixedShadow: 'rgba(0, 0, 0, 0.12)',
|
|
imagePlaceholder: '#f2f3f5',
|
|
findMatchBg: '#fff566',
|
|
findActiveMatchBg: '#ffe58f',
|
|
findActiveBorder: '#faad14',
|
|
};
|
|
}
|
|
|
|
export const HEADER_COLOR_PRESETS = [
|
|
'#f0f5ff',
|
|
'#fff7e6',
|
|
'#f6ffed',
|
|
'#fff1f0',
|
|
'#f9f0ff',
|
|
'#e6fffb',
|
|
];
|
|
|
|
function parseHexColor(hex: string): { r: number; g: number; b: number } | null {
|
|
const normalized = hex.trim().replace('#', '');
|
|
if (normalized.length === 3) {
|
|
return {
|
|
r: Number.parseInt(normalized[0]! + normalized[0], 16),
|
|
g: Number.parseInt(normalized[1]! + normalized[1], 16),
|
|
b: Number.parseInt(normalized[2]! + normalized[2], 16),
|
|
};
|
|
}
|
|
if (normalized.length === 6) {
|
|
return {
|
|
r: Number.parseInt(normalized.slice(0, 2), 16),
|
|
g: Number.parseInt(normalized.slice(2, 4), 16),
|
|
b: Number.parseInt(normalized.slice(4, 6), 16),
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function rgbToHsl(r: number, g: number, b: number) {
|
|
const rn = r / 255;
|
|
const gn = g / 255;
|
|
const bn = b / 255;
|
|
const max = Math.max(rn, gn, bn);
|
|
const min = Math.min(rn, gn, bn);
|
|
const l = (max + min) / 2;
|
|
if (max === min) {
|
|
return { h: 0, s: 0, l };
|
|
}
|
|
const d = max - min;
|
|
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
let h = 0;
|
|
if (max === rn) h = ((gn - bn) / d + (gn < bn ? 6 : 0)) / 6;
|
|
else if (max === gn) h = ((bn - rn) / d + 2) / 6;
|
|
else h = ((rn - gn) / d + 4) / 6;
|
|
return { h, s, l };
|
|
}
|
|
|
|
function hslToHex(h: number, s: number, l: number): string {
|
|
if (s === 0) {
|
|
const v = Math.round(l * 255);
|
|
const hex = v.toString(16).padStart(2, '0');
|
|
return `#${hex}${hex}${hex}`;
|
|
}
|
|
const hue2rgb = (p: number, q: number, t: number) => {
|
|
let tt = t;
|
|
if (tt < 0) tt += 1;
|
|
if (tt > 1) tt -= 1;
|
|
if (tt < 1 / 6) return p + (q - p) * 6 * tt;
|
|
if (tt < 1 / 2) return q;
|
|
if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;
|
|
return p;
|
|
};
|
|
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
const p = 2 * l - q;
|
|
const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255);
|
|
const g = Math.round(hue2rgb(p, q, h) * 255);
|
|
const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255);
|
|
return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
}
|
|
|
|
export function resolveHeaderColor(
|
|
color: string | undefined,
|
|
isDark: boolean,
|
|
fallback: string,
|
|
): string {
|
|
if (!color) return fallback;
|
|
if (!isDark) return color;
|
|
|
|
const rgb = parseHexColor(color);
|
|
if (!rgb) return fallback;
|
|
|
|
const { h, s, l } = rgbToHsl(rgb.r, rgb.g, rgb.b);
|
|
const darkL = Math.min(0.28, Math.max(0.16, l * 0.35 + 0.12));
|
|
const darkS = Math.min(0.55, s * 0.75 + 0.08);
|
|
return hslToHex(h, darkS, darkL);
|
|
}
|