feat: dark mode

This commit is contained in:
雷军 2023-11-03 14:16:45 +08:00
parent 688cd427a8
commit 4cfdda2059
9 changed files with 363 additions and 22 deletions

View file

@ -11,7 +11,7 @@ index cdbc0fa..cb2a9db 100644
bind(target, 'touchend', (evt) => {
if (!end) return;
diff --git a/node_modules/x-data-spreadsheet/src/component/sheet.js b/node_modules/x-data-spreadsheet/src/component/sheet.js
index 086b8c4..cd01f6e 100644
index 086b8c4..264823c 100644
--- a/node_modules/x-data-spreadsheet/src/component/sheet.js
+++ b/node_modules/x-data-spreadsheet/src/component/sheet.js
@@ -77,11 +77,11 @@ function selectorSet(multiple, ri, ci, indexesUpdated = true, moving = false) {
@ -28,11 +28,179 @@ index 086b8c4..cd01f6e 100644
}
toolbar.reset();
table.render();
@@ -854,7 +854,7 @@ function sheetInitEvents() {
}
export default class Sheet {
- constructor(targetEl, data) {
+ constructor(targetEl, data, isDark) {
this.eventMap = createEventEmitter();
const { view, showToolbar, showContextmenu } = data.settings;
this.el = h('div', `${cssPrefix}-sheet`);
@@ -904,7 +904,7 @@ export default class Sheet {
this.sortFilter.el,
);
// table
- this.table = new Table(this.tableEl.el, data);
+ this.table = new Table(this.tableEl.el, data, isDark);
sheetInitEvents.call(this);
sheetReset.call(this);
// init selector [0, 0]
diff --git a/node_modules/x-data-spreadsheet/src/component/table.js b/node_modules/x-data-spreadsheet/src/component/table.js
index 41e1e14..09ac678 100644
--- a/node_modules/x-data-spreadsheet/src/component/table.js
+++ b/node_modules/x-data-spreadsheet/src/component/table.js
@@ -7,22 +7,23 @@ import { formatm } from '../core/format';
import {
Draw, DrawBox, thinLineWidth, npx,
} from '../canvas/draw';
+import { idText } from 'typescript';
// gobal var
const cellPaddingWidth = 5;
const tableFixedHeaderCleanStyle = { fillStyle: '#f4f5f8' };
-const tableGridStyle = {
+var tableGridStyle = {
fillStyle: '#fff',
lineWidth: thinLineWidth,
strokeStyle: '#e6e6e6',
};
-function tableFixedHeaderStyle() {
+function tableFixedHeaderStyle(isDark) {
return {
textAlign: 'center',
textBaseline: 'middle',
font: `500 ${npx(12)}px Source Sans Pro`,
- fillStyle: '#585757',
+ fillStyle: isDark ? '#dcdcdc' : '#585757',
lineWidth: thinLineWidth(),
- strokeStyle: '#e6e6e6',
+ strokeStyle: isDark ? '#c0c0c0': '#e6e6e6',
};
}
@@ -184,13 +185,18 @@ function renderSelectedHeaderCell(x, y, w, h) {
// h: the fixed height of header
// tx: moving distance on x-axis
// ty: moving distance on y-axis
-function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
+function renderFixedHeaders(type, viewRange, w, h, tx, ty, isDark) {
const { draw, data } = this;
const sumHeight = viewRange.h; // rows.sumHeight(viewRange.sri, viewRange.eri + 1);
const sumWidth = viewRange.w; // cols.sumWidth(viewRange.sci, viewRange.eci + 1);
const nty = ty + h;
const ntx = tx + w;
+ if (isDark) {
+ tableFixedHeaderCleanStyle.fillStyle = '#595d88'
+ tableFixedHeaderCleanStyle.strokeStyle = '#5d5d5d'
+ }
+
draw.save();
// draw rect background
draw.attr(tableFixedHeaderCleanStyle);
@@ -203,7 +209,7 @@ function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
// console.log(data.selectIndexes);
// draw text
// text font, align...
- draw.attr(tableFixedHeaderStyle());
+ draw.attr(tableFixedHeaderStyle(isDark));
// y-header-text
if (type === 'all' || type === 'left') {
data.rowEach(viewRange.sri, viewRange.eri, (i, y1, rowHeight) => {
@@ -247,21 +253,25 @@ function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
draw.restore();
}
-function renderFixedLeftTopCell(fw, fh) {
+function renderFixedLeftTopCell(fw, fh, isDark) {
const { draw } = this;
draw.save();
// left-top-cell
- draw.attr({ fillStyle: '#f4f5f8' })
+ draw.attr({ fillStyle: isDark ? '#595d88' : '#f4f5f8', strokeStyle: isDark ? '#5d5d5d' : '#e6e6e6' })
.fillRect(0, 0, fw, fh);
draw.restore();
}
function renderContentGrid({
sri, sci, eri, eci, w, h,
-}, fw, fh, tx, ty) {
+}, fw, fh, tx, ty, isDark) {
const { draw, data } = this;
const { settings } = data;
+ if (isDark) {
+ tableGridStyle.strokeStyle = '#5d5d5d'
+ }
+
draw.save();
draw.attr(tableGridStyle)
.translate(fw + tx, fh + ty);
@@ -300,10 +310,11 @@ function renderFreezeHighlightLine(fw, fh, ftw, fth) {
/** end */
class Table {
- constructor(el, data) {
+ constructor(el, data, isDark) {
this.el = el;
this.draw = new Draw(el, data.viewWidth(), data.viewHeight());
this.data = data;
+ this.isDark = isDark
}
resetData(data) {
@@ -329,10 +340,10 @@ class Table {
const ty = data.freezeTotalHeight();
const { x, y } = data.scroll;
// 1
- renderContentGrid.call(this, viewRange, fw, fh, tx, ty);
+ renderContentGrid.call(this, viewRange, fw, fh, tx, ty, this.isDark);
renderContent.call(this, viewRange, fw, fh, -x, -y);
- renderFixedHeaders.call(this, 'all', viewRange, fw, fh, tx, ty);
- renderFixedLeftTopCell.call(this, fw, fh);
+ renderFixedHeaders.call(this, 'all', viewRange, fw, fh, tx, ty, this.isDark);
+ renderFixedLeftTopCell.call(this, fw, fh, this.isDark);
const [fri, fci] = data.freeze;
if (fri > 0 || fci > 0) {
// 2
@@ -343,7 +354,7 @@ class Table {
vr.h = ty;
renderContentGrid.call(this, vr, fw, fh, tx, 0);
renderContent.call(this, vr, fw, fh, -x, 0);
- renderFixedHeaders.call(this, 'top', vr, fw, fh, tx, 0);
+ renderFixedHeaders.call(this, 'top', vr, fw, fh, tx, 0, this.isDark);
}
// 3
if (fci > 0) {
@@ -352,13 +363,13 @@ class Table {
vr.eci = fci - 1;
vr.w = tx;
renderContentGrid.call(this, vr, fw, fh, 0, ty);
- renderFixedHeaders.call(this, 'left', vr, fw, fh, 0, ty);
+ renderFixedHeaders.call(this, 'left', vr, fw, fh, 0, ty, this.isDark);
renderContent.call(this, vr, fw, fh, 0, -y);
}
// 4
const freezeViewRange = data.freezeViewRange();
renderContentGrid.call(this, freezeViewRange, fw, fh, 0, 0);
- renderFixedHeaders.call(this, 'all', freezeViewRange, fw, fh, 0, 0);
+ renderFixedHeaders.call(this, 'all', freezeViewRange, fw, fh, 0, 0, this.isDark);
renderContent.call(this, freezeViewRange, fw, fh, 0, 0);
// 5
renderFreezeHighlightLine.call(this, fw, fh, tx, ty);
diff --git a/node_modules/x-data-spreadsheet/src/index.d.ts b/node_modules/x-data-spreadsheet/src/index.d.ts
index 948a8e9..7fe36b3 100644
index 948a8e9..72fb91e 100644
--- a/node_modules/x-data-spreadsheet/src/index.d.ts
+++ b/node_modules/x-data-spreadsheet/src/index.d.ts
@@ -45,18 +45,18 @@ declare module 'x-data-spreadsheet' {
@@ -34,6 +34,7 @@ declare module 'x-data-spreadsheet' {
italic: false;
};
};
+ isDark: boolean;
}
export type CELL_SELECTED = 'cell-selected';
@@ -45,18 +46,18 @@ declare module 'x-data-spreadsheet' {
export interface SpreadsheetEventHandler {
(
envt: CELL_SELECTED,
@ -54,7 +222,7 @@ index 948a8e9..7fe36b3 100644
): void;
}
@@ -182,6 +182,19 @@ declare module 'x-data-spreadsheet' {
@@ -182,6 +183,19 @@ declare module 'x-data-spreadsheet' {
* @param callback
*/
change(callback: (json: Record<string, any>) => void): this;
@ -75,9 +243,18 @@ index 948a8e9..7fe36b3 100644
* set locale
* @param lang
diff --git a/node_modules/x-data-spreadsheet/src/index.js b/node_modules/x-data-spreadsheet/src/index.js
index 479a0b7..96d0f3a 100644
index 479a0b7..ae82d34 100644
--- a/node_modules/x-data-spreadsheet/src/index.js
+++ b/node_modules/x-data-spreadsheet/src/index.js
@@ -11,7 +11,7 @@ import './index.less';
class Spreadsheet {
constructor(selectors, options = {}) {
let targetEl = selectors;
- this.options = { showBottomBar: true, ...options };
+ this.options = { isDark: false, showBottomBar: true, ...options };
this.sheetIndex = 1;
this.datas = [];
if (typeof selectors === 'string') {
@@ -20,6 +20,7 @@ class Spreadsheet {
this.bottombar = this.options.showBottomBar ? new Bottombar(() => {
const d = this.addSheet();
@ -86,7 +263,7 @@ index 479a0b7..96d0f3a 100644
}, (index) => {
const d = this.datas[index];
this.sheet.resetData(d);
@@ -27,6 +28,7 @@ class Spreadsheet {
@@ -27,13 +28,14 @@ class Spreadsheet {
this.deleteSheet();
}, (index, value) => {
this.datas[index].name = value;
@ -94,6 +271,14 @@ index 479a0b7..96d0f3a 100644
}) : null;
this.data = this.addSheet();
const rootEl = h('div', `${cssPrefix}`)
.on('contextmenu', evt => evt.preventDefault());
// create canvas element
targetEl.appendChild(rootEl.el);
- this.sheet = new Sheet(rootEl, this.data);
+ this.sheet = new Sheet(rootEl, this.data, options.isDark);
if (this.bottombar !== null) {
rootEl.child(this.bottombar.el);
}
@@ -120,6 +122,16 @@ class Spreadsheet {
return this;
}

View file

@ -15,6 +15,21 @@ export class ExcelSettingTab extends PluginSettingTab {
containerEl.empty()
containerEl.createEl("h1", { text: t("BASE_COLOR") });
new Setting(containerEl)
.setName(t("BASE_COLOR"))
.setDesc(t("BASE_COLOR_DESC"))
.addDropdown((dropdown) =>
dropdown
.addOption("light","Light")
.addOption("dark","Dark")
.setValue(this.plugin.settings.theme)
.onChange(async (value) => {
this.plugin.settings.theme = value
}),
);
containerEl.createEl("h1", { text: t("FILE_SETTING") });
new Setting(containerEl)

View file

@ -8,6 +8,7 @@ import { getExcelData } from "./utils/DataUtils";
import zhCn from "./lang/locale/sheet-zh-cn"
import en from "./lang/locale/sheet-en"
import { t } from "./lang/helpers"
import { updateSheetTheme } from "./utils/ThemeUtils";
export class ExcelView extends TextFileView {
public plugin: ExcelPlugin;
@ -186,6 +187,41 @@ export class ExcelView extends TextFileView {
} else {
Spreadsheet.locale('en', en)
}
// 设置 sheet 样式
var style = {
bgcolor: '#ffffff',
align: 'left',
valign: 'middle',
textwrap: false,
strike: false,
underline: false,
color: '#0a0a0a',
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
},
}
if (this.plugin.settings.theme === "dark") {
style = {
bgcolor: '#363636',
align: 'left',
valign: 'middle',
textwrap: false,
strike: false,
underline: false,
color: '#fff',
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
},
}
}
//@ts-ignore
this.sheet = new Spreadsheet(this.sheetEle, {
@ -204,6 +240,9 @@ export class ExcelView extends TextFileView {
indexWidth: 60,
minWidth: 60,
},
//@ts-ignore
style: style,
isDark: this.plugin.settings.theme === "dark"
})
.loadData(jsonData) // load data
.change(() => {
@ -241,6 +280,8 @@ export class ExcelView extends TextFileView {
this.cellsSelected.eci = ci;
});
updateSheetTheme(this.plugin.settings.theme === "dark")
// @ts-ignore
this.sheet.validate();
}

View file

@ -7,6 +7,7 @@ import {
import ExcelPlugin from "./main";
import Spreadsheet from "x-data-spreadsheet";
import { getExcelData, getExcelAreaData } from "./utils/DataUtils";
import { updateSheetTheme } from "./utils/ThemeUtils";
let plugin: ExcelPlugin;
let vault: Vault;
@ -179,6 +180,42 @@ const createSheetEl = (data: string, file: TFile, width: number, height: number
const jsonData = JSON.parse(data || "{}") || {};
// console.log("createSheetEl", jsonData, data)
// 设置 sheet 样式
var style = {
bgcolor: '#ffffff',
align: 'left',
valign: 'middle',
textwrap: false,
strike: false,
underline: false,
color: '#0a0a0a',
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
},
}
if (plugin.settings.theme === "dark") {
style = {
bgcolor: '#363636',
align: 'left',
valign: 'middle',
textwrap: false,
strike: false,
underline: false,
color: '#fff',
font: {
name: 'Helvetica',
size: 10,
bold: false,
italic: false,
},
}
}
//@ts-ignore
const sheet = new Spreadsheet(sheetEl, {
mode: "read",
@ -186,7 +223,7 @@ const createSheetEl = (data: string, file: TFile, width: number, height: number
showBottomBar: true,
view: {
height: () => height,
width: () => width,
width: () => width - 10,
},
row: {
len: 100,
@ -198,8 +235,13 @@ const createSheetEl = (data: string, file: TFile, width: number, height: number
indexWidth: 60,
minWidth: 60,
},
// @ts-ignore
style: style,
isDark: plugin.settings.theme === "dark",
}).loadData(jsonData); // load data
updateSheetTheme(plugin.settings.theme === "dark")
// @ts-ignore
sheet.validate();
sheetDiv.appendChild(sheetEl)

View file

@ -25,6 +25,8 @@ export default {
// ExcelSettingTab.ts
BASE_COLOR: "Base color scheme",
BASE_COLOR_DESC: "Choose default color scheme",
FILE_SETTING: "File Setting",
FOLDER: "FOLDER",
FOLDER_DESC: "Create files in this folder by default",

View file

@ -24,6 +24,8 @@ export default {
EXPORT_XLSX_FILE: "到处 xlsx 文件",
// ExcelSettingTab.ts
BASE_COLOR: "基础颜色",
BASE_COLOR_DESC: "选择默认基础色",
FILE_SETTING: "文件设置",
FOLDER: "文件夹",
FOLDER_DESC: "新建文件将放在此文件夹下",

View file

@ -4,7 +4,8 @@ export interface ExcelSettings {
excelFilenameDateTime: string,
sheetHeight: string,
rowHeight: string,
colWidth: string
colWidth: string,
theme: string
}
export const DEFAULT_SETTINGS: ExcelSettings = {
@ -13,5 +14,6 @@ export const DEFAULT_SETTINGS: ExcelSettings = {
excelFilenameDateTime: "YYYY-MM-DD HH.mm.ss",
sheetHeight: "300",
rowHeight: "25",
colWidth: "100"
colWidth: "100",
theme: "light"
};

28
src/utils/ThemeUtils.ts Normal file
View file

@ -0,0 +1,28 @@
export function updateSheetTheme(isDark: Boolean) {
const root = document.documentElement;
if (isDark) {
root.style.setProperty('--sheet-iframe-background-color', "#363636")
root.style.setProperty('--sheet-iframe-border-color', "#a5a0f8")
root.style.setProperty('--sheet-toolbar-background-color', "#a5a0f8")
root.style.setProperty('--sheet-toolbar-divider-color', "#a5a0f8")
root.style.setProperty('--sheet-dropdown-content-background-color', "#857fe6")
root.style.setProperty('--sheet-dropdown-content-color', "#dcdcdc")
root.style.setProperty('--sheet-dropdown-title-color', "rgba(0,0,0,0.9)")
root.style.setProperty('--sheet-menu-color', "#000")
root.style.setProperty('--sheet-menu-active-background-color', "#bdb9f9")
root.style.setProperty('--sheet-header-background-color', "#bdb9f9")
root.style.setProperty('--sheet-checked-before', "#025492")
} else {
root.style.setProperty('--sheet-iframe-border-color', "#f5f6f7")
root.style.setProperty('--sheet-iframe-background-color', "#fff")
root.style.setProperty('--sheet-toolbar-background-color', "#f5f6f7")
root.style.setProperty('--sheet-toolbar-divider-color', "#e0e2e4")
root.style.setProperty('--sheet-dropdown-content-background-color', "#fff")
root.style.setProperty('--sheet-dropdown-content-color', "rgba(0,0,0,0.9)")
root.style.setProperty('--sheet-dropdown-title-color', "rgba(0,0,0,0.9)")
root.style.setProperty('--sheet-menu-color', "#80868b")
root.style.setProperty('--sheet-menu-active-background-color', "#fff")
root.style.setProperty('--sheet-header-background-color', "#f8f8f9")
root.style.setProperty('--sheet-checked-before', "#4b89ff")
}
}

View file

@ -1,3 +1,17 @@
:root {
--sheet-iframe-border-color: #f5f6f7;
--sheet-iframe-background-color: #fff;
--sheet-toolbar-background-color: #f5f6f7;
--sheet-toolbar-divider-color: #e0e2e4;
--sheet-dropdown-content-background-color: #fff;
--sheet-dropdown-content-color: rgba(0,0,0,0.9);
--sheet-dropdown-title-color: rgba(0,0,0,0.9);
--sheet-menu-color: #80868b;
--sheet-menu-active-background-color: #fff;
--sheet-header-background-color: #f8f8f9;
--sheet-checked-before: #4b89ff;
}
.sheet-box {
width: 100%;
height: 100%;
@ -16,8 +30,8 @@
/* Markdown 文档引入样式设置*/
.sheet-iframe {
width: 100%;
background-color: var(--background-primary-alt);
border: 5px solid #f5f6f7;
background-color: var(--sheet-iframe-background-color);
border: 5px solid var(--sheet-iframe-border-color);
}
ul.x-spreadsheet-menu {
@ -39,7 +53,7 @@ body {
-moz-user-select: none;
font-family: "Lato", "Source Sans Pro", Roboto, Helvetica, Arial, sans-serif;
box-sizing: content-box;
background: #fff;
background: var(--sheet-iframe-background-color);
-webkit-font-smoothing: antialiased;
}
.x-spreadsheet textarea {
@ -158,7 +172,7 @@ body {
.x-spreadsheet-dropdown .x-spreadsheet-dropdown-content {
position: absolute;
z-index: 200;
background: #fff;
background: var(--sheet-dropdown-content-background-color);
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
}
.x-spreadsheet-dropdown.bottom-left .x-spreadsheet-dropdown-content {
@ -181,6 +195,11 @@ body {
padding: 0 5px;
display: inline-block;
}
.x-spreadsheet-dropdown-title {
color: var(--sheet-dropdown-title-color);
}
.x-spreadsheet-dropdown
.x-spreadsheet-dropdown-header
.x-spreadsheet-icon.arrow-left {
@ -353,7 +372,7 @@ body {
border: 1px solid transparent;
outline: none;
height: 26px;
color: rgba(0, 0, 0, 0.9);
color: var(--sheet-dropdown-content-color);
line-height: 26px;
list-style: none;
padding: 2px 10px;
@ -399,7 +418,7 @@ body {
}
.x-spreadsheet-item.state.checked:before,
.x-spreadsheet-header.state.checked:before {
background: #4b89ff;
background: var(--sheet-checked-before);
}
.x-spreadsheet-checkbox {
position: relative;
@ -424,7 +443,7 @@ body {
.x-spreadsheet-sort-filter {
position: absolute;
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
background: #fff;
background: var(--sheet-dropdown-content-background-color);
z-index: 100;
width: 260px;
pointer-events: auto;
@ -440,7 +459,7 @@ body {
}
.x-spreadsheet-filter .x-spreadsheet-header {
padding: 0.5em 0.75em;
background: #f8f8f9;
background: var(--sheet-header-background-color);
border-bottom: 1px solid #e9e9e9;
border-left: 1px solid transparent;
}
@ -460,9 +479,14 @@ body {
height: 40px;
padding: 0 30px;
text-align: left;
background: #f5f6f7;
background: var(--sheet-toolbar-background-color);
display: flex;
}
.x-spreadsheet-toolbar {
width: 100% !important
}
.x-spreadsheet-bottombar {
position: relative;
border-top: 1px solid #e0e2e4;
@ -473,7 +497,7 @@ body {
padding-top: 0;
padding-bottom: 0;
vertical-align: middle;
border-right: 1px solid #e8eaed;
border-right: 1px solid var(--sheet-toolbar-divider-color);
}
.x-spreadsheet-menu {
list-style: none;
@ -489,14 +513,14 @@ body {
vertical-align: middle;
text-align: left;
font-weight: 400;
color: #80868b;
color: var(--sheet-menu-color);
white-space: nowrap;
cursor: pointer;
transition: all 0.3s;
font-weight: bold;
}
.x-spreadsheet-menu > li.active {
background-color: #fff;
background-color: var(--sheet-menu-active-background-color);
color: rgba(0, 0, 0, 0.65);
}
.x-spreadsheet-menu > li .x-spreadsheet-icon {
@ -545,7 +569,7 @@ body {
}
.x-spreadsheet-toolbar-divider {
display: inline-block;
border-right: 1px solid #e0e2e4;
border-right: 1px solid var(--sheet-toolbar-divider-color);
width: 0;
vertical-align: middle;
height: 18px;