diff --git a/apps/web/src/lib/note-print-appearance.test.mjs b/apps/web/src/lib/note-print-appearance.test.mjs
index 68751a2b..cd13d005 100644
--- a/apps/web/src/lib/note-print-appearance.test.mjs
+++ b/apps/web/src/lib/note-print-appearance.test.mjs
@@ -19,7 +19,7 @@ describe("note print appearance", () => {
expect(css).not.toContain("color: #");
});
- test("tints links, bold, and checked boxes with the account palette", () => {
+ test("tints links, bold, checked boxes, and tables with the account palette", () => {
const css = notePrintAppearanceCss(notePrintAppearanceFromProse(resolveNoteProse({
palette: "teal",
customCss: "strong { color: #112233 }",
@@ -28,6 +28,8 @@ describe("note print appearance", () => {
expect(css).toContain("color: #14796E");
expect(css).toContain("color: #20AD9D");
expect(css).toContain("accent-color: #20AD9D");
+ expect(css).toContain("background: #F2FBFA;");
+ expect(css).not.toContain("border-color: #CDEFEA;");
expect(css).toContain(".edgeever-editor .ProseMirror strong { color: #112233; }");
expect(css).not.toContain("not-a-theme");
});
diff --git a/apps/web/src/lib/note-print-appearance.ts b/apps/web/src/lib/note-print-appearance.ts
index 041ad1de..a99200c6 100644
--- a/apps/web/src/lib/note-print-appearance.ts
+++ b/apps/web/src/lib/note-print-appearance.ts
@@ -65,6 +65,12 @@ const paletteRules = (palette: NoteProsePaletteChoice) => {
".edgeever-print-content ul[data-type=\"taskList\"] li[data-checked] > label input {",
` accent-color: ${colors.accent};`,
"}",
+ ".edgeever-print-content th {",
+ ` background: ${colors.surface};`,
+ "}",
+ ".edgeever-print-content tbody tr:nth-child(even) td {",
+ ` background: color-mix(in srgb, ${colors.surface} 60%, transparent);`,
+ "}",
].join("\n");
};
diff --git a/apps/web/src/lib/wechat-copy.test.mjs b/apps/web/src/lib/wechat-copy.test.mjs
index e063ea82..657e5a30 100644
--- a/apps/web/src/lib/wechat-copy.test.mjs
+++ b/apps/web/src/lib/wechat-copy.test.mjs
@@ -80,6 +80,8 @@ describe("preparePublishArticle", () => {
"--note-palette-accent": "#B39AE8",
"--note-palette-light-accent": "#7351CF",
"--note-palette-text": "#3F3F46",
+ "--note-palette-surface": "#F4F4F5",
+ "--note-palette-divider": "#E1DEFF",
"--note-palette-code-bg": "#F3F1FF",
"--note-palette-code-text": "#5B4EE0",
})[name] ?? "",
@@ -89,10 +91,20 @@ describe("preparePublishArticle", () => {
expect(context.colors.accent).toBe("#7351CF");
expect(context.colors.codeText).toBe("#5B4EE0");
expect(context.colors.codeBackground).toBe("#F3F1FF");
- const root = preparePublishArticle("
重点 Cmd/Ctrl + E
", container);
+ expect(context.colors.surface).toBe("#F4F4F5");
+ expect(context.colors.divider).toBe("#E1DEFF");
+ const root = preparePublishArticle([
+ "重点 Cmd/Ctrl + E
",
+ "",
+ ].join(""), container);
expect(css(root.querySelector("strong"))).toContain("color:#7351CF");
expect(css(root.querySelector("code"))).toContain("color:#5B4EE0");
expect(css(root.querySelector("code"))).toContain("background:#F3F1FF");
+ const th = root.querySelector("th");
+ expect(css(th)).toContain("background:#F4F4F5");
+ expect(css(th)).toContain("border:1px solid #e5e5e5");
+ const rows = root.querySelectorAll("tbody tr");
+ expect(css(rows[1].querySelector("td"))).toContain("background-color:#F4F4F5");
} finally {
globalThis.getComputedStyle = previous;
}
diff --git a/apps/web/src/lib/wechat-copy.ts b/apps/web/src/lib/wechat-copy.ts
index 80af799e..5dc99679 100644
--- a/apps/web/src/lib/wechat-copy.ts
+++ b/apps/web/src/lib/wechat-copy.ts
@@ -66,6 +66,7 @@ const applyLegacyWeChatStyles = (
: "box-shadow: inset 0 0 0 1px rgba(61,68,80,0.08);";
const accent = colors?.accent ?? BODY_COLOR;
const bold = colors ? `font-weight: 800; color: ${accent};` : "font-weight: 800;";
+ const thBackground = colors ? colors.surface : "#f5f5f5";
const textStyle = `font-family: ${PUBLISH_FONT}; font-size: ${fontSize}; line-height: ${lineHeight}; letter-spacing: -0.005em; color: ${BODY_COLOR};`;
const styles: Record = {
p: `margin: 0 0 ${PARAGRAPH_SPACING}; padding: 0; ${textStyle}`,
@@ -88,7 +89,7 @@ const applyLegacyWeChatStyles = (
pre: `margin: 0 0 16px; padding: 14px 16px; overflow: hidden; border: 1px solid #e4e4e4; border-radius: 8px; background: #fafafa; color: #0f172a; font-family: ${PUBLISH_MONO}; font-size: ${codeSize}; line-height: 1.6; text-align: left; white-space: pre-wrap;`,
hr: "margin: 24px 0; border: 0; border-top: 1px solid #1a1d21;",
table: `width: 100%; margin: 20px 0; border-collapse: collapse; font-size: ${fontSize}; line-height: 1.45;`,
- th: "padding: 8px 13px; border: 1px solid #e5e5e5; background: #f5f5f5; color: #0f172a; font-weight: 600; font-size: 13px; text-align: left;",
+ th: `padding: 8px 13px; border: 1px solid #e5e5e5; background: ${thBackground}; color: #0f172a; font-weight: 600; font-size: 13px; text-align: left;`,
td: `padding: 8px 13px; border: 1px solid #e5e5e5; color: ${BODY_COLOR}; text-align: left;`,
img: "display: block; max-width: 100%; height: auto; margin: 16px 0; border: 1px solid #b8dfd0; border-radius: 8px;",
};
@@ -115,6 +116,18 @@ const applyLegacyWeChatStyles = (
root.querySelectorAll("pre code").forEach((element) => {
element.style.cssText = `padding: 0; border: 0; background: transparent; color: inherit; font-family: ${PUBLISH_MONO}; font-size: ${codeSize}; font-weight: 400; white-space: pre-wrap;`;
});
+
+ if (colors) {
+ root.querySelectorAll("table").forEach((table) => {
+ table.querySelectorAll("tbody tr").forEach((tr, index) => {
+ if (index % 2 === 1) {
+ tr.querySelectorAll("td").forEach((td) => {
+ td.style.backgroundColor = colors.surface;
+ });
+ }
+ });
+ });
+ }
};
const applyInlineStyles = (
diff --git a/apps/web/src/styles/editor-typography.test.mjs b/apps/web/src/styles/editor-typography.test.mjs
index b4a1c9fb..e146e3a5 100644
--- a/apps/web/src/styles/editor-typography.test.mjs
+++ b/apps/web/src/styles/editor-typography.test.mjs
@@ -81,7 +81,7 @@ describe("editor typography contract", () => {
expect(prose).not.toContain('data-note-palette="custom"');
});
- test("named palettes recolor links, bold, inline code, and checked task boxes", () => {
+ test("named palettes recolor links, bold, inline code, checked task boxes, and table surfaces", () => {
const prose = readStyle("./note-prose.css");
expect(prose).toMatch(/color:\s*var\(--note-palette-link\)/);
@@ -92,10 +92,10 @@ describe("editor typography contract", () => {
expect(prose).toMatch(/ul\[data-type="taskList"\] li\[data-checked\] > label input/);
expect(prose).toMatch(/\.ProseMirror code/);
expect(prose).toMatch(/\.ProseMirror pre code/);
+ expect(prose).toMatch(/background:\s*var\(--note-palette-surface\)/);
const globals = readStyle("./globals.css");
expect(declarationsForSelector(globals, ".ProseMirror code")).toContain("color: #3d4450;");
expect(prose).not.toMatch(/--note-palette-text/);
- expect(prose).not.toMatch(/--note-palette-surface/);
expect(prose).not.toMatch(/--note-palette-muted/);
expect(prose).not.toMatch(/--note-palette-divider/);
expect(prose).not.toMatch(/blockquote/);
diff --git a/apps/web/src/styles/note-prose.css b/apps/web/src/styles/note-prose.css
index 6760d7bd..1cec1c45 100644
--- a/apps/web/src/styles/note-prose.css
+++ b/apps/web/src/styles/note-prose.css
@@ -1,4 +1,4 @@
-/* Named hues tint links, bold, inline code, and checked task boxes. Body, quotes, rules, tables, and code blocks stay native. */
+/* Named hues tint links, bold, inline code, checked task boxes, and table surfaces. Body, quotes, rules, and code blocks stay native. */
:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) {
/* Override the light accent supplied by inline account prose variables. */
--note-palette-accent: var(--note-palette-dark-accent) !important;
@@ -36,6 +36,25 @@
accent-color: var(--note-palette-accent);
}
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror th,
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .markdown-content th {
+ background: var(--note-palette-surface);
+}
+
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror tbody tr:nth-child(even) td,
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .markdown-content tbody tr:nth-child(even) td {
+ background: color-mix(in srgb, var(--note-palette-surface) 60%, transparent);
+}
+
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror tbody tr:hover td,
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .markdown-content tbody tr:hover td {
+ background: color-mix(in srgb, var(--note-palette-surface) 85%, rgb(var(--slate-200-rgb) / 0.5));
+}
+
+.edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror .selectedCell::after {
+ background: color-mix(in srgb, var(--note-palette-accent) 14%, transparent);
+}
+
:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror a:not(.edgeever-attachment-link) {
color: var(--note-palette-accent);
text-decoration-color: color-mix(in srgb, var(--note-palette-accent) 45%, transparent);
@@ -59,3 +78,21 @@
color: inherit;
}
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror th,
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .markdown-content th {
+ background: color-mix(in srgb, var(--note-palette-accent) 12%, transparent);
+}
+
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror tbody tr:nth-child(even) td,
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .markdown-content tbody tr:nth-child(even) td {
+ background: color-mix(in srgb, var(--note-palette-accent) 4.5%, transparent);
+}
+
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror tbody tr:hover td,
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .markdown-content tbody tr:hover td {
+ background: color-mix(in srgb, var(--note-palette-accent) 9%, transparent);
+}
+
+:root.dark .edgeever-editor[data-note-palette]:not([data-note-palette="native"]) .ProseMirror .selectedCell::after {
+ background: color-mix(in srgb, var(--note-palette-accent) 20%, transparent);
+}
diff --git a/docs/editor-typography-plan.zh-CN.md b/docs/editor-typography-plan.zh-CN.md
index 582e8c90..92ea82aa 100644
--- a/docs/editor-typography-plan.zh-CN.md
+++ b/docs/editor-typography-plan.zh-CN.md
@@ -61,7 +61,7 @@
笔记正文字体维持现状:本机选择,内置字体仍可发布到公开分享页,自定义字体名称不发布。
-正文配色放在「阅读」里,用固定选项,不用滑杆。每一项右侧有一块该色的圆角矩形,当前选项在收起时也带着。原生用界面前景色。默认是现在的原生配色。另外 9 款按色相分开,每款差一个大色相。选中一款时,只改链接、行内代码、粗体和待办勾选框,粗体和勾选框用该款强调色。空框和划掉的文字仍用原生。正文、标题、引用、分隔线、表格、代码底和代码边框仍用原生。深色模式同样只改这几项,链接和行内代码用强调色。界面、侧栏、工具栏、图表和信息图不跟着变。
+正文配色放在「阅读」里,用固定选项,不用滑杆。每一项右侧有一块该色的圆角矩形,当前选项在收起时也带着。原生用界面前景色。默认是现在的原生配色。另外 9 款按色相分开,每款差一个大色相。选中一款时,只改链接、行内代码、粗体、待办勾选框以及表格浅底色(表头用该款浅底色,偶数行浅底,单元格选中用强调色半透明高亮;表格边框仍用原生中性灰)。空框和划掉的文字仍用原生。正文、标题、引用、分隔线、代码底和代码边框仍用原生。深色模式同样只改这几项,链接和行内代码用强调色,表格表头底色用暗色微弱强调色混溶。界面、侧栏、工具栏、图表和信息图不跟着变。
原先那 10 款里,琥珀和日暖都是金黄,夜蓝和青页都是蓝,雾色和青玉都是青,林绿又接近品牌绿。这四款舍弃。空出来的位置用酒红,再补色相上没有的橙色和粉色。绿色曾放进选项,后来去掉。设置里的名字直接用色名。
diff --git a/packages/shared/src/note-prose.ts b/packages/shared/src/note-prose.ts
index 6352e6fe..4bc4d084 100644
--- a/packages/shared/src/note-prose.ts
+++ b/packages/shared/src/note-prose.ts
@@ -112,7 +112,7 @@ export const NOTE_PROSE_PALETTES: Record