Add themed editor blocks and split theme styles
This commit is contained in:
1 parent
2e5bf5063e
commit
a5222fbddd
24 files changed
+1145
-154
No files matched your search
@@ -230,6 +230,7 @@ If you want to migrate notes from other platforms to EdgeEver, please refer to t
|
||||
## Acknowledgements
|
||||
|
||||
- The visual design of the editor themes is inspired by [gzh-design-skill](https://github.com/isjiamu/gzh-design-skill), whose themes were originally created by Jiamu (甲木) × Moyu Xiaoli (摸鱼小李). Thanks for their open-source work.
|
||||
- The `嫩青` editor theme is adapted from the visual style of the [MDNice editor](https://editor.mdnice.com/). Thanks to the original authors for the reference.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ Cloudflare Worker 侧执行图片处理会消耗计算/图片处理额度,因
|
||||
## 致谢
|
||||
|
||||
- 编辑器主题的视觉设计参考自 [gzh-design-skill](https://github.com/isjiamu/gzh-design-skill),相关主题由甲木 × 摸鱼小李原创。感谢作者的开源工作。
|
||||
- `嫩青`编辑器主题的视觉样式参考自 [MDNice 编辑器](https://editor.mdnice.com/)。感谢原作者提供的设计参考。
|
||||
|
||||
## 免责声明
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import {
|
||||
Search,
|
||||
Type,
|
||||
X,
|
||||
Copy,
|
||||
} from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { GitHubRepositoryLink } from "@/components/GitHubRepositoryLink";
|
||||
@@ -85,6 +86,8 @@ import {
|
||||
getEditableMemoTitle,
|
||||
getNotebookMoveOptions,
|
||||
} from "@/lib/app-helpers";
|
||||
import { copyEditorToWeChat, copyMarkdownToWeChat } from "@/lib/wechat-copy";
|
||||
import { ThemeBlock } from "./ThemeBlock";
|
||||
|
||||
const SUPPORTED_PASTE_IMAGE_TYPES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp", "image/avif"]);
|
||||
const MOBILE_EDITOR_QUERY = "(max-width: 639px)";
|
||||
@@ -1145,6 +1148,7 @@ const RichEditorPane = ({
|
||||
const [mobileImeDebugOpen, setMobileImeDebugOpen] = useState(false);
|
||||
const [mobileImeDebugActiveElement, setMobileImeDebugActiveElement] = useState(getActiveElementLabel);
|
||||
const [mobileImeDebugEvents, setMobileImeDebugEvents] = useState<MobileImeDebugEntry[]>([]);
|
||||
const [wechatCopyState, setWechatCopyState] = useState<"idle" | "copied" | "error">("idle");
|
||||
const notebookOptions = useMemo(() => getNotebookMoveOptions(notebooks), [notebooks]);
|
||||
const readOnly = isTrashView || Boolean(memo?.isDeleted);
|
||||
const mobileDefaultEditRequested = Boolean(memo?.id && memo.id === mobileDefaultEditMemoId && !readOnly);
|
||||
@@ -1306,6 +1310,7 @@ const RichEditorPane = ({
|
||||
extensions: [
|
||||
StarterKit.configure({ codeBlock: false }),
|
||||
EdgeEverCodeBlock.configure({ lowlight: codeBlockLowlight, defaultLanguage: "plaintext" }),
|
||||
ThemeBlock,
|
||||
ResizableImage.configure({
|
||||
allowBase64: false,
|
||||
inline: false,
|
||||
@@ -1919,6 +1924,25 @@ const RichEditorPane = ({
|
||||
markDirty();
|
||||
}, [markDirty]);
|
||||
|
||||
const handleCopyToWeChat = useCallback(async () => {
|
||||
if (!isEditorReady(editor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (useMarkdownSourceEditor) {
|
||||
await copyMarkdownToWeChat(markdownSource);
|
||||
} else {
|
||||
await copyEditorToWeChat(editor);
|
||||
}
|
||||
setWechatCopyState("copied");
|
||||
window.setTimeout(() => setWechatCopyState("idle"), 1800);
|
||||
} catch {
|
||||
setWechatCopyState("error");
|
||||
window.setTimeout(() => setWechatCopyState("idle"), 2200);
|
||||
}
|
||||
}, [editor, markdownSource, useMarkdownSourceEditor]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!useMobilePlainTextEditor) {
|
||||
return;
|
||||
@@ -2560,6 +2584,17 @@ const RichEditorPane = ({
|
||||
<Button className="hidden h-8 w-8 text-slate-500 transition-colors hover:bg-slate-100 hover:text-slate-950 focus-visible:ring-2 focus-visible:ring-slate-300 sm:inline-flex" size="icon" variant="ghost" title={t("editor.searchCurrentMemo")} aria-label={t("editor.searchCurrentMemo")} onClick={() => openNoteSearch()}>
|
||||
<Search className="h-5 w-5" strokeWidth={2.25} />
|
||||
</Button>
|
||||
<Button
|
||||
className={cn("hidden h-8 items-center gap-1.5 px-2 text-xs font-medium text-emerald-700 transition-colors hover:bg-emerald-50 hover:text-emerald-900 focus-visible:ring-2 focus-visible:ring-emerald-300 sm:inline-flex", wechatCopyState === "copied" && "bg-emerald-50")}
|
||||
variant="ghost"
|
||||
title={t("editor.copyToWeChat")}
|
||||
aria-label={t("editor.copyToWeChat")}
|
||||
onClick={() => void handleCopyToWeChat()}
|
||||
disabled={!editor || effectiveReadOnly || useMobilePlainTextEditor}
|
||||
>
|
||||
<Copy className="h-4 w-4" />
|
||||
{t(wechatCopyState === "copied" ? "editor.copiedToWeChat" : wechatCopyState === "error" ? "editor.copyToWeChatFailed" : "editor.copyToWeChat")}
|
||||
</Button>
|
||||
<Button className="hidden h-8 w-8 text-slate-500 transition-colors hover:bg-slate-100 hover:text-slate-950 focus-visible:ring-2 focus-visible:ring-slate-300 sm:inline-flex" size="icon" variant="ghost" title={t("editor.versionHistory")} aria-label={t("editor.versionHistory")} onClick={() => setHistoryOpen(true)}>
|
||||
<History className="h-5 w-5" strokeWidth={2.25} />
|
||||
</Button>
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
Workflow,
|
||||
Minus,
|
||||
Paperclip,
|
||||
Blocks,
|
||||
} from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@/components/ui/select";
|
||||
@@ -22,6 +23,13 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/comp
|
||||
import { getActiveBlockValue } from "@/lib/app-helpers";
|
||||
import { CODE_BLOCK_LANGUAGES, getCodeBlockLanguageValue } from "@/lib/code-block";
|
||||
import { EditorTableMenu } from "@/components/EditorTableMenu";
|
||||
import { insertThemeBlock, type ThemeBlockKind } from "./ThemeBlock";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
|
||||
const EditorToolbarButton = ({
|
||||
active = false,
|
||||
@@ -393,6 +401,27 @@ export const EditorToolbar = ({
|
||||
>
|
||||
<Minus className="h-4 w-4" />
|
||||
</EditorToolbarButton>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md border border-transparent bg-transparent text-slate-700 transition hover:border-slate-200 hover:bg-slate-50 disabled:pointer-events-none disabled:opacity-40"
|
||||
aria-label={t("editorToolbar.themeBlock")}
|
||||
title={t("editorToolbar.themeBlock")}
|
||||
disabled={disabled}
|
||||
onMouseDown={(event) => event.preventDefault()}
|
||||
>
|
||||
<Blocks className="h-4 w-4" />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
{(["intro", "key-point", "callout", "chapter"] as ThemeBlockKind[]).map((kind) => (
|
||||
<DropdownMenuItem key={kind} onSelect={() => run((current) => insertThemeBlock(current, kind))}>
|
||||
{t(`editorToolbar.themeBlocks.${kind}`)}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<EditorTableMenu editor={editor} readOnly={readOnly} />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
} from "@/lib/mobile-editor-standalone";
|
||||
import { getMemoUpdateQueueId, isMemoUpdateAlreadyApplied, queueMemoUpdate, shouldQueueMemoSaveError } from "@/lib/sync-queue";
|
||||
import { EdgeEverCodeBlock, codeBlockLowlight } from "@/lib/code-block";
|
||||
import { ThemeBlock } from "./ThemeBlock";
|
||||
|
||||
type ListNotebooksResponse = {
|
||||
notebooks: Notebook[];
|
||||
@@ -172,6 +173,7 @@ export const MobileStandaloneTiptapEditor = ({
|
||||
extensions: [
|
||||
StarterKit.configure({ codeBlock: false }),
|
||||
EdgeEverCodeBlock.configure({ lowlight: codeBlockLowlight, defaultLanguage: "plaintext" }),
|
||||
ThemeBlock,
|
||||
Image.configure({
|
||||
allowBase64: false,
|
||||
inline: false,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { Node, mergeAttributes } from "@tiptap/core";
|
||||
import { NodeViewContent, NodeViewWrapper, ReactNodeViewRenderer, type NodeViewProps } from "@tiptap/react";
|
||||
import { Lightbulb, MessageCircle, PanelTop, Trash2 } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const THEME_BLOCK_KINDS = ["intro", "key-point", "callout", "chapter"] as const;
|
||||
export type ThemeBlockKind = (typeof THEME_BLOCK_KINDS)[number];
|
||||
|
||||
const kindIcon = {
|
||||
intro: MessageCircle,
|
||||
"key-point": Lightbulb,
|
||||
callout: PanelTop,
|
||||
chapter: PanelTop,
|
||||
} satisfies Record<ThemeBlockKind, typeof MessageCircle>;
|
||||
|
||||
const ThemeBlockView = ({ node, deleteNode, selected }: NodeViewProps) => {
|
||||
const { t } = useTranslation();
|
||||
const kind = (node.attrs.kind as ThemeBlockKind) || "intro";
|
||||
const Icon = kindIcon[kind] ?? MessageCircle;
|
||||
|
||||
return (
|
||||
<NodeViewWrapper
|
||||
className="edgeever-theme-block"
|
||||
data-theme-block-kind={kind}
|
||||
data-theme-block-selected={selected ? "true" : undefined}
|
||||
>
|
||||
<div className="edgeever-theme-block__toolbar" contentEditable={false}>
|
||||
<span className="edgeever-theme-block__label">
|
||||
<Icon aria-hidden="true" className="h-3.5 w-3.5" />
|
||||
{t(`editorToolbar.themeBlocks.${kind}`)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
className="edgeever-theme-block__delete"
|
||||
aria-label={t("editorToolbar.deleteThemeBlock")}
|
||||
title={t("editorToolbar.deleteThemeBlock")}
|
||||
onMouseDown={(event) => event.preventDefault()}
|
||||
onClick={deleteNode}
|
||||
>
|
||||
<Trash2 aria-hidden="true" className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
<NodeViewContent className="edgeever-theme-block__content" />
|
||||
</NodeViewWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export const ThemeBlock = Node.create({
|
||||
name: "edgeeverThemeBlock",
|
||||
group: "block",
|
||||
content: "block+",
|
||||
defining: true,
|
||||
isolating: true,
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
kind: {
|
||||
default: "intro",
|
||||
parseHTML: (element: HTMLElement) => element.getAttribute("data-theme-block-kind") || "intro",
|
||||
renderHTML: (attributes: { kind?: string }) => ({
|
||||
"data-theme-block-kind": attributes.kind || "intro",
|
||||
}),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [{ tag: "section[data-theme-block-kind]" }];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ["section", mergeAttributes(HTMLAttributes, { "data-edgeever-theme-block": "true" }), 0];
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
return ReactNodeViewRenderer(ThemeBlockView);
|
||||
},
|
||||
});
|
||||
|
||||
export const insertThemeBlock = (editor: { chain: () => any; state: any }, kind: ThemeBlockKind) => {
|
||||
const { from, to } = editor.state.selection;
|
||||
const selectedText = editor.state.doc.textBetween(from, to, "\n", "\n").trim();
|
||||
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.insertContentAt(
|
||||
{ from, to },
|
||||
{
|
||||
type: "edgeeverThemeBlock",
|
||||
attrs: { kind },
|
||||
content: [{ type: "paragraph", content: selectedText ? [{ type: "text", text: selectedText }] : undefined }],
|
||||
}
|
||||
)
|
||||
.run();
|
||||
};
|
||||
@@ -29,6 +29,7 @@ export const EDITOR_THEME_NAMES = [
|
||||
"zen-whitespace",
|
||||
"moyu-ticket",
|
||||
"olive-journal",
|
||||
"mdnice-nenqing",
|
||||
] as const;
|
||||
export type EditorThemeName = (typeof EDITOR_THEME_NAMES)[number];
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import type { Editor } from "@tiptap/react";
|
||||
import { marked } from "marked";
|
||||
|
||||
const WECHAT_STYLES: Record<string, string> = {
|
||||
p: "margin: 0 0 1em; line-height: 1.75; font-size: 16px; color: #333;",
|
||||
h1: "margin: 1.2em 0 0.6em; font-size: 24px; line-height: 1.35; font-weight: 700; color: #1f2937;",
|
||||
h2: "margin: 1.1em 0 0.55em; font-size: 21px; line-height: 1.4; font-weight: 700; color: #1f2937;",
|
||||
h3: "margin: 1em 0 0.5em; font-size: 18px; line-height: 1.45; font-weight: 700; color: #1f2937;",
|
||||
blockquote: "margin: 1em 0; padding: 0.6em 1em; border-left: 4px solid #10b981; background: #f0fdf4; color: #4b5563; line-height: 1.75;",
|
||||
ul: "margin: 0 0 1em; padding-left: 1.6em; line-height: 1.75;",
|
||||
ol: "margin: 0 0 1em; padding-left: 1.6em; line-height: 1.75;",
|
||||
li: "margin: 0.25em 0; line-height: 1.75;",
|
||||
a: "color: #059669; text-decoration: underline;",
|
||||
strong: "font-weight: 700;",
|
||||
em: "font-style: italic;",
|
||||
del: "text-decoration: line-through;",
|
||||
code: "padding: 0.15em 0.35em; border-radius: 3px; background: #f3f4f6; color: #be123c; font-family: Menlo, Consolas, monospace; font-size: 0.9em;",
|
||||
pre: "margin: 1em 0; padding: 12px 14px; overflow: hidden; border-radius: 6px; background: #f6f8fa; color: #24292f; line-height: 1.6; text-align: left;",
|
||||
hr: "margin: 1.5em 0; border: 0; border-top: 1px solid #e5e7eb;",
|
||||
table: "width: 100%; margin: 1em 0; border-collapse: collapse; font-size: 14px; line-height: 1.6;",
|
||||
th: "padding: 8px; border: 1px solid #d1d5db; background: #f3f4f6; font-weight: 700; text-align: left;",
|
||||
td: "padding: 8px; border: 1px solid #d1d5db; text-align: left;",
|
||||
img: "display: block; max-width: 100%; height: auto; margin: 1em auto;",
|
||||
};
|
||||
|
||||
const THEME_BLOCK_LABELS: Record<string, string> = {
|
||||
intro: "引言",
|
||||
"key-point": "重点观点",
|
||||
callout: "提示",
|
||||
chapter: "章节",
|
||||
};
|
||||
|
||||
const THEME_BLOCK_STYLES: Record<string, { block: string; label: string }> = {
|
||||
intro: {
|
||||
block: "margin: 20px 0; padding: 0 0 4px; border-left: 5px solid #059669; background: #f0fdf4; color: #374151;",
|
||||
label: "padding: 10px 14px 0; color: #059669; font-size: 12px; font-weight: 700; letter-spacing: 1px;",
|
||||
},
|
||||
"key-point": {
|
||||
block: "margin: 20px 0; padding: 0 0 4px; border: 1px solid #a7f3d0; border-radius: 8px; background: #f0fdf4; color: #374151;",
|
||||
label: "padding: 10px 14px 0; color: #047857; font-size: 12px; font-weight: 700; letter-spacing: 1px;",
|
||||
},
|
||||
callout: {
|
||||
block: "margin: 20px 0; padding: 0 0 4px; border: 1px dashed #6ee7b7; background: #ecfdf5; color: #374151;",
|
||||
label: "padding: 10px 14px 0; color: #059669; font-size: 12px; font-weight: 700; letter-spacing: 1px;",
|
||||
},
|
||||
chapter: {
|
||||
block: "margin: 28px 0 16px; padding: 0 0 4px; border-top: 3px solid #059669; color: #111827;",
|
||||
label: "padding: 10px 0 0; color: #059669; font-size: 12px; font-weight: 700; letter-spacing: 2px;",
|
||||
},
|
||||
};
|
||||
|
||||
const applyInlineStyles = (root: HTMLElement, editorTheme?: string) => {
|
||||
root.style.cssText = "font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 16px; line-height: 1.75; color: #333; word-break: break-word;";
|
||||
root.querySelectorAll<HTMLElement>("*").forEach((element) => {
|
||||
const style = WECHAT_STYLES[element.tagName.toLowerCase()];
|
||||
if (style) element.style.cssText = `${style}${element.style.cssText}`;
|
||||
});
|
||||
root.querySelectorAll<HTMLElement>("pre code").forEach((element) => {
|
||||
element.style.cssText = "padding: 0; background: transparent; color: inherit; font-family: Menlo, Consolas, monospace; font-size: 13px; white-space: pre-wrap;";
|
||||
});
|
||||
|
||||
root.querySelectorAll<HTMLElement>("[data-edgeever-theme-block]").forEach((block) => {
|
||||
const kind = block.getAttribute("data-theme-block-kind") || "intro";
|
||||
const themeStyles = THEME_BLOCK_STYLES[kind] || THEME_BLOCK_STYLES.intro;
|
||||
const accent = editorTheme === "red-white" ? "#dc2626" : editorTheme === "olive-journal" ? "#ed7b2f" : editorTheme === "graphite-minimal" ? "#52525b" : "#059669";
|
||||
block.style.cssText = `${themeStyles.block} border-left-color: ${accent}; ${block.style.cssText}`;
|
||||
|
||||
const label = document.createElement("p");
|
||||
label.textContent = THEME_BLOCK_LABELS[kind] || "主题组件";
|
||||
label.style.cssText = `${themeStyles.label} color: ${accent}; margin: 0;`;
|
||||
block.insertBefore(label, block.firstChild);
|
||||
});
|
||||
};
|
||||
|
||||
export const buildWeChatClipboardHtml = (editor: Editor) => {
|
||||
const container = document.createElement("div");
|
||||
container.innerHTML = editor.getHTML();
|
||||
const editorTheme = editor.view.dom.closest<HTMLElement>("[data-editor-theme]")?.dataset.editorTheme;
|
||||
applyInlineStyles(container, editorTheme);
|
||||
return container.outerHTML;
|
||||
};
|
||||
|
||||
const copyHtmlToClipboard = async (html: string, plainText: string) => {
|
||||
if (navigator.clipboard && "ClipboardItem" in window) {
|
||||
await navigator.clipboard.write([new ClipboardItem({
|
||||
"text/html": new Blob([html], { type: "text/html" }),
|
||||
"text/plain": new Blob([plainText], { type: "text/plain" }),
|
||||
})]);
|
||||
return;
|
||||
}
|
||||
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
const container = document.createElement("div");
|
||||
container.setAttribute("contenteditable", "true");
|
||||
container.style.cssText = "position: fixed; left: -99999px; top: 0;";
|
||||
container.innerHTML = html;
|
||||
document.body.appendChild(container);
|
||||
range.selectNodeContents(container);
|
||||
selection?.removeAllRanges();
|
||||
selection?.addRange(range);
|
||||
const copied = document.execCommand("copy");
|
||||
selection?.removeAllRanges();
|
||||
container.remove();
|
||||
if (!copied) throw new Error("Clipboard copy was not available");
|
||||
};
|
||||
|
||||
export const copyEditorToWeChat = async (editor: Editor) =>
|
||||
copyHtmlToClipboard(buildWeChatClipboardHtml(editor), editor.getText({ blockSeparator: "\n" }));
|
||||
|
||||
export const copyMarkdownToWeChat = async (markdown: string) => {
|
||||
const container = document.createElement("div");
|
||||
container.innerHTML = marked.parse(markdown, { async: false, gfm: true, breaks: false });
|
||||
applyInlineStyles(container);
|
||||
await copyHtmlToClipboard(container.outerHTML, container.textContent ?? "");
|
||||
};
|
||||
@@ -0,0 +1,340 @@
|
||||
/* Shared editor theme structure and themed block components */
|
||||
|
||||
/* Editor reading themes inspired by the curated gzh-design-skill presets. */
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #ffffff;
|
||||
--editor-theme-text: #1f2937;
|
||||
--editor-theme-muted: #64748b;
|
||||
--editor-theme-accent: #059669;
|
||||
--editor-theme-soft: #ecfdf5;
|
||||
--editor-theme-border: #a7f3d0;
|
||||
background: var(--editor-theme-bg);
|
||||
}
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror {
|
||||
|
||||
background: var(--editor-theme-bg);
|
||||
color: var(--editor-theme-text);
|
||||
font-family: var(--editor-theme-font, inherit);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h2,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h3 {
|
||||
|
||||
color: var(--editor-theme-heading, var(--editor-theme-text));
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
border-bottom: 2px solid var(--editor-theme-accent);
|
||||
padding-bottom: 0.55rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
border-left: 4px solid var(--editor-theme-accent);
|
||||
padding-left: 0.7rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
border-left: 4px solid var(--editor-theme-accent);
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-muted);
|
||||
padding: 0.8rem 1rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror hr {
|
||||
|
||||
border-color: var(--editor-theme-border);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror code,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror pre,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-code-source {
|
||||
|
||||
border-color: var(--editor-theme-border);
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-text);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror th {
|
||||
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-heading, var(--editor-theme-text));
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror td,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror th {
|
||||
|
||||
border-color: var(--editor-theme-border);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror {
|
||||
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror p {
|
||||
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror strong {
|
||||
|
||||
color: var(--editor-theme-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror em {
|
||||
|
||||
color: var(--editor-theme-muted);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror a:not(.edgeever-attachment-link) {
|
||||
|
||||
color: var(--editor-theme-accent);
|
||||
text-decoration: underline;
|
||||
text-decoration-color: color-mix(in srgb, var(--editor-theme-accent) 40%, transparent);
|
||||
text-underline-offset: 0.15em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror ul,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror ol {
|
||||
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror li::marker {
|
||||
|
||||
color: var(--editor-theme-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror hr {
|
||||
|
||||
height: 2px;
|
||||
border: 0;
|
||||
background: var(--editor-theme-border);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror img {
|
||||
|
||||
border: 1px solid var(--editor-theme-border);
|
||||
border-radius: var(--editor-theme-radius, 6px);
|
||||
box-shadow: var(--editor-theme-shadow, none);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .tableWrapper {
|
||||
|
||||
border-color: var(--editor-theme-border);
|
||||
border-radius: var(--editor-theme-radius, 6px);
|
||||
box-shadow: var(--editor-theme-shadow, none);
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block {
|
||||
|
||||
position: relative;
|
||||
margin: 1.25rem 0;
|
||||
border: 1px solid #dbeee5;
|
||||
border-radius: 4px;
|
||||
background: #fbfefc;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block__toolbar {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
color: #64748b;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
opacity: 0;
|
||||
transition: max-height 140ms ease, padding 140ms ease, opacity 140ms ease;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block__label {
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block__delete {
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: #64748b;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block__content {
|
||||
|
||||
padding: 0.35rem 0.9rem 0.45rem;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block:hover .edgeever-theme-block__toolbar,
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block[data-theme-block-selected="true"] .edgeever-theme-block__toolbar {
|
||||
|
||||
min-height: 2rem;
|
||||
max-height: 2.5rem;
|
||||
padding: 0.35rem 0.75rem;
|
||||
border-bottom: 1px solid #e2eee8;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block__content > :first-child {
|
||||
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor .ProseMirror .edgeever-theme-block__content > :last-child {
|
||||
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: var(--editor-theme-soft);
|
||||
--theme-block-border: var(--editor-theme-border);
|
||||
--theme-block-shadow: var(--editor-theme-shadow, none);
|
||||
position: relative;
|
||||
margin: 1.25rem 0;
|
||||
border: 1px solid color-mix(in srgb, var(--theme-block-border) 58%, transparent);
|
||||
border-radius: var(--editor-theme-radius, 4px);
|
||||
background: color-mix(in srgb, var(--theme-block-bg) 42%, var(--editor-theme-bg));
|
||||
box-shadow: none;
|
||||
color: var(--editor-theme-text);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__toolbar {
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
color: var(--editor-theme-accent);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
opacity: 0;
|
||||
transition: max-height 140ms ease, padding 140ms ease, opacity 140ms ease;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__label {
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__delete {
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--editor-theme-muted);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__delete:hover {
|
||||
|
||||
color: var(--editor-theme-accent);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__content {
|
||||
|
||||
padding: 0.35rem 0.9rem 0.45rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block:hover .edgeever-theme-block__toolbar,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-selected="true"] .edgeever-theme-block__toolbar {
|
||||
|
||||
min-height: 2rem;
|
||||
max-height: 2.5rem;
|
||||
padding: 0.35rem 0.75rem;
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--theme-block-border) 45%, transparent);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__content > :first-child {
|
||||
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__content > :last-child {
|
||||
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-selected="true"] {
|
||||
|
||||
outline: 2px solid color-mix(in srgb, var(--editor-theme-accent) 42%, transparent);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-kind="intro"] {
|
||||
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-left: 3px solid var(--editor-theme-accent);
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-kind="key-point"] {
|
||||
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-left: 3px solid var(--editor-theme-accent);
|
||||
border-radius: 0;
|
||||
background: color-mix(in srgb, var(--theme-block-bg) 35%, var(--editor-theme-bg));
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-kind="callout"] {
|
||||
|
||||
border-style: solid;
|
||||
border-left-width: 3px;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-kind="chapter"] {
|
||||
|
||||
border-top: 3px solid var(--editor-theme-accent);
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block[data-theme-block-kind="chapter"] .edgeever-theme-block__toolbar {
|
||||
|
||||
border-bottom-color: var(--editor-theme-border);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror th,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror td {
|
||||
|
||||
font-family: var(--editor-theme-font, inherit);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* graphite-minimal editor theme */
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: #f4f4f5;
|
||||
--theme-block-border: #a1a1aa;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #fafafa;
|
||||
--editor-theme-text: #3f3f46;
|
||||
--editor-theme-accent: #52525b;
|
||||
--editor-theme-soft: #f4f4f5;
|
||||
--editor-theme-border: #d4d4d8;
|
||||
--editor-theme-font: Inter, ui-sans-serif, system-ui, sans-serif;
|
||||
--editor-theme-radius: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
border-left: 0;
|
||||
border-bottom: 1px solid #a1a1aa;
|
||||
padding-left: 0;
|
||||
border-bottom-color: #52525b;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
font-size: 2.1rem;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror strong {
|
||||
|
||||
color: #27272a;
|
||||
border-bottom: 2px solid #52525b;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
border-left: 1px solid #71717a;
|
||||
background: #f4f4f5;
|
||||
color: #52525b;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
@import "./base.css";
|
||||
@import "./moyu-green.css";
|
||||
@import "./red-white.css";
|
||||
@import "./graphite-minimal.css";
|
||||
@import "./zen-whitespace.css";
|
||||
@import "./moyu-ticket.css";
|
||||
@import "./olive-journal.css";
|
||||
@import "./mdnice-nenqing.css";
|
||||
@@ -0,0 +1,126 @@
|
||||
/* mdnice-nenqing editor theme */
|
||||
|
||||
/* Adapted from the visual rules of MDNice's "嫩青" editor theme. */
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #ffffff;
|
||||
--editor-theme-text: #595959;
|
||||
--editor-theme-muted: #595959;
|
||||
--editor-theme-heading: rgb(0 0 0 / 85%);
|
||||
--editor-theme-accent: #47c1a8;
|
||||
--editor-theme-soft: rgb(0 0 0 / 5%);
|
||||
--editor-theme-border: #47c1a8;
|
||||
--editor-theme-font: Optima, "Microsoft YaHei", "PingFang SC", serif;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror {
|
||||
|
||||
font-size: 1rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror p {
|
||||
|
||||
margin: 0;
|
||||
padding: 0.5rem 0;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror h2,
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror h3 {
|
||||
|
||||
color: var(--editor-theme-heading);
|
||||
font-family: var(--editor-theme-font);
|
||||
font-weight: 700;
|
||||
margin: 1.875rem 0 0.9375rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
font-size: 1.75rem;
|
||||
line-height: 1.5;
|
||||
border-bottom: 2px solid #595959;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
font-size: 1.5rem;
|
||||
line-height: 1.5;
|
||||
border-left: 0;
|
||||
border-bottom: 2px solid #595959;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror h3 {
|
||||
|
||||
font-size: 1.17rem;
|
||||
line-height: 1.3;
|
||||
border: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror strong,
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror a {
|
||||
|
||||
color: var(--editor-theme-accent);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
margin: 1.25rem 0;
|
||||
border-left: 0;
|
||||
border-radius: 0;
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-text);
|
||||
padding: 0.625rem 0.625rem 0.625rem 1.25rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror ul,
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror ol {
|
||||
|
||||
margin: 0.5rem 0;
|
||||
padding-left: 1.5625rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror li {
|
||||
|
||||
margin: 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror li::marker {
|
||||
|
||||
color: var(--editor-theme-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror code {
|
||||
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
background: rgb(27 31 35 / 5%);
|
||||
color: var(--editor-theme-accent);
|
||||
font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;
|
||||
font-size: 0.875rem;
|
||||
padding: 0.125rem 0.25rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror pre {
|
||||
|
||||
border: 0;
|
||||
border-radius: 0.3125rem;
|
||||
background: #f6f6f6;
|
||||
color: #595959;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror hr {
|
||||
|
||||
border-color: #808080;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="mdnice-nenqing"]:not([data-editor-theme="default"]) .ProseMirror th {
|
||||
|
||||
background: rgb(71 193 168 / 12%);
|
||||
color: var(--editor-theme-heading);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* moyu-green editor theme */
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: #f0fdf4;
|
||||
--theme-block-border: #bbf7d0;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #fbfefc;
|
||||
--editor-theme-text: #1f2937;
|
||||
--editor-theme-accent: #059669;
|
||||
--editor-theme-soft: #ecfdf5;
|
||||
--editor-theme-border: #a7f3d0;
|
||||
--editor-theme-radius: 10px;
|
||||
--editor-theme-shadow: 0 2px 10px rgb(5 150 105 / 0.08);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
color: #111827;
|
||||
border-bottom-color: #059669;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #fde68a;
|
||||
text-decoration-thickness: 0.22em;
|
||||
text-underline-offset: -0.08em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
border-left-width: 5px;
|
||||
border-left-color: #059669;
|
||||
background: linear-gradient(90deg, #ecfdf5, transparent);
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) .ProseMirror strong {
|
||||
|
||||
color: #059669;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #a7f3d0;
|
||||
text-decoration-thickness: 2px;
|
||||
text-underline-offset: 0.16em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
border: 1px dashed #6ee7b7;
|
||||
border-left: 5px solid #059669;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 3px 10px rgb(5 150 105 / 0.07);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* moyu-ticket editor theme */
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: #f0fdf4;
|
||||
--theme-block-border: #6ee7b7;
|
||||
--theme-block-shadow: 4px 4px 0 #a7f3d0;
|
||||
border-style: dashed;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #f7fffb;
|
||||
--editor-theme-text: #1f2937;
|
||||
--editor-theme-accent: #047857;
|
||||
--editor-theme-soft: #d1fae5;
|
||||
--editor-theme-border: #6ee7b7;
|
||||
--editor-theme-radius: 2px;
|
||||
--editor-theme-shadow: 4px 4px 0 #a7f3d0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror blockquote,
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror pre {
|
||||
|
||||
border: 2px solid var(--editor-theme-accent);
|
||||
box-shadow: 4px 4px 0 #a7f3d0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
border: 1px dashed #6ee7b7;
|
||||
background: #f0fdf4;
|
||||
padding: 0.65rem 0.8rem;
|
||||
box-shadow: 4px 4px 0 #a7f3d0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror strong {
|
||||
|
||||
color: #065f46;
|
||||
background: #d1fae5;
|
||||
padding: 0 0.25em;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/* olive-journal editor theme */
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: #eeefe9;
|
||||
--theme-block-border: #bfc1b7;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__toolbar {
|
||||
|
||||
background: #1e1f23;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #fffdf8;
|
||||
--editor-theme-text: #292a2d;
|
||||
--editor-theme-accent: #ed7b2f;
|
||||
--editor-theme-soft: #fff3e8;
|
||||
--editor-theme-border: #f3c7a6;
|
||||
--editor-theme-font: Georgia, "Songti SC", STSong, serif;
|
||||
--editor-theme-radius: 4px;
|
||||
--editor-theme-shadow: 0 2px 8px rgb(30 31 35 / 0.06);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
background: #292a2d;
|
||||
color: #fffdf8;
|
||||
border-bottom: 0;
|
||||
padding: 0.7rem 0.9rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
border-left-color: var(--editor-theme-accent);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
color: #23251d;
|
||||
border-bottom-color: #bfc1b7;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h3 {
|
||||
|
||||
color: #23251d;
|
||||
box-shadow: inset 0 -0.5em 0 rgb(245 78 0 / 18%);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror strong {
|
||||
|
||||
color: #23251d;
|
||||
border-bottom: 2px solid #ed7b2f;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
border: 1px solid #bfc1b7;
|
||||
border-left: 4px solid #ed7b2f;
|
||||
background: #eeefe9;
|
||||
color: #4d4f46;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/* red-white editor theme */
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: #fef2f2;
|
||||
--theme-block-border: #fca5a5;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block__toolbar {
|
||||
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #ffffff;
|
||||
--editor-theme-text: #262626;
|
||||
--editor-theme-accent: #dc2626;
|
||||
--editor-theme-soft: #fff1f2;
|
||||
--editor-theme-border: #fecaca;
|
||||
--editor-theme-radius: 6px;
|
||||
--editor-theme-shadow: 0 4px 18px rgb(220 38 38 / 0.1);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
border-bottom-width: 3px;
|
||||
border-bottom-color: #dc2626;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
|
||||
border-left: 5px solid #dc2626;
|
||||
border-bottom: 2px solid #fca5a5;
|
||||
background: #fef2f2;
|
||||
padding-top: 0.35rem;
|
||||
padding-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror strong {
|
||||
|
||||
color: #1c1917;
|
||||
background: #fee2e2;
|
||||
border-bottom: 2px solid #fecaca;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
border-left-color: #dc2626;
|
||||
background: #fef2f2;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* zen-whitespace editor theme */
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror .edgeever-theme-block {
|
||||
|
||||
--theme-block-bg: transparent;
|
||||
--theme-block-border: #b5c8bc;
|
||||
}
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) {
|
||||
|
||||
--editor-theme-bg: #fcfdfc;
|
||||
--editor-theme-text: #35443b;
|
||||
--editor-theme-accent: #4a5d52;
|
||||
--editor-theme-soft: #f1f6f2;
|
||||
--editor-theme-border: #b5c8bc;
|
||||
--editor-theme-font: Georgia, "Songti SC", STSong, serif;
|
||||
--editor-theme-radius: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror {
|
||||
|
||||
padding-left: clamp(2rem, 9vw, 7rem);
|
||||
padding-right: clamp(2rem, 9vw, 7rem);
|
||||
line-height: 1.85;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
|
||||
border-bottom: 1px solid var(--editor-theme-border);
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror p {
|
||||
|
||||
margin-bottom: 0.75rem;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
|
||||
border-left: 1px solid #b5c8bc;
|
||||
background: transparent;
|
||||
color: #4a5d52;
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@import "highlight.js/styles/github.css";
|
||||
@import "./editor-themes/index.css";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@@ -952,158 +953,6 @@ textarea {
|
||||
border-color: #334155;
|
||||
}
|
||||
|
||||
/* Editor reading themes inspired by the curated gzh-design-skill presets. */
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #ffffff;
|
||||
--editor-theme-text: #1f2937;
|
||||
--editor-theme-muted: #64748b;
|
||||
--editor-theme-accent: #059669;
|
||||
--editor-theme-soft: #ecfdf5;
|
||||
--editor-theme-border: #a7f3d0;
|
||||
background: var(--editor-theme-bg);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror {
|
||||
background: var(--editor-theme-bg);
|
||||
color: var(--editor-theme-text);
|
||||
font-family: var(--editor-theme-font, inherit);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h2,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h3 {
|
||||
color: var(--editor-theme-heading, var(--editor-theme-text));
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
border-bottom: 2px solid var(--editor-theme-accent);
|
||||
padding-bottom: 0.55rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
border-left: 4px solid var(--editor-theme-accent);
|
||||
padding-left: 0.7rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror blockquote {
|
||||
border-left: 4px solid var(--editor-theme-accent);
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-muted);
|
||||
padding: 0.8rem 1rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror hr {
|
||||
border-color: var(--editor-theme-border);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror code,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror pre,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror .edgeever-code-source {
|
||||
border-color: var(--editor-theme-border);
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-text);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror th {
|
||||
background: var(--editor-theme-soft);
|
||||
color: var(--editor-theme-heading, var(--editor-theme-text));
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror td,
|
||||
.edgeever-editor[data-editor-theme]:not([data-editor-theme="default"]) .ProseMirror th {
|
||||
border-color: var(--editor-theme-border);
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-green"]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #fbfefc;
|
||||
--editor-theme-text: #1f2937;
|
||||
--editor-theme-accent: #059669;
|
||||
--editor-theme-soft: #ecfdf5;
|
||||
--editor-theme-border: #a7f3d0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #ffffff;
|
||||
--editor-theme-text: #262626;
|
||||
--editor-theme-accent: #dc2626;
|
||||
--editor-theme-soft: #fff1f2;
|
||||
--editor-theme-border: #fecaca;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="red-white"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
border-bottom-width: 3px;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #fafafa;
|
||||
--editor-theme-text: #3f3f46;
|
||||
--editor-theme-accent: #52525b;
|
||||
--editor-theme-soft: #f4f4f5;
|
||||
--editor-theme-border: #d4d4d8;
|
||||
--editor-theme-font: Inter, ui-sans-serif, system-ui, sans-serif;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror h1,
|
||||
.edgeever-editor[data-editor-theme="graphite-minimal"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
border-left: 0;
|
||||
border-bottom: 1px solid #a1a1aa;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #fcfdfc;
|
||||
--editor-theme-text: #35443b;
|
||||
--editor-theme-accent: #4a5d52;
|
||||
--editor-theme-soft: #f1f6f2;
|
||||
--editor-theme-border: #b5c8bc;
|
||||
--editor-theme-font: Georgia, "Songti SC", STSong, serif;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror {
|
||||
padding-left: clamp(2rem, 9vw, 7rem);
|
||||
padding-right: clamp(2rem, 9vw, 7rem);
|
||||
line-height: 1.85;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="zen-whitespace"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
border-bottom: 1px solid var(--editor-theme-border);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #f7fffb;
|
||||
--editor-theme-text: #1f2937;
|
||||
--editor-theme-accent: #047857;
|
||||
--editor-theme-soft: #d1fae5;
|
||||
--editor-theme-border: #6ee7b7;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror blockquote,
|
||||
.edgeever-editor[data-editor-theme="moyu-ticket"]:not([data-editor-theme="default"]) .ProseMirror pre {
|
||||
border: 2px solid var(--editor-theme-accent);
|
||||
box-shadow: 4px 4px 0 #a7f3d0;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) {
|
||||
--editor-theme-bg: #fffdf8;
|
||||
--editor-theme-text: #292a2d;
|
||||
--editor-theme-accent: #ed7b2f;
|
||||
--editor-theme-soft: #fff3e8;
|
||||
--editor-theme-border: #f3c7a6;
|
||||
--editor-theme-font: Georgia, "Songti SC", STSong, serif;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h1 {
|
||||
background: #292a2d;
|
||||
color: #fffdf8;
|
||||
border-bottom: 0;
|
||||
padding: 0.7rem 0.9rem;
|
||||
}
|
||||
|
||||
.edgeever-editor[data-editor-theme="olive-journal"]:not([data-editor-theme="default"]) .ProseMirror h2 {
|
||||
border-left-color: var(--editor-theme-accent);
|
||||
}
|
||||
|
||||
:root.dark .markdown-content pre {
|
||||
background-color: #13261a;
|
||||
border-color: #166534;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.10",
|
||||
"@tanstack/react-query": "latest",
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/extension-image": "^3.27.1",
|
||||
"@tiptap/extension-placeholder": "latest",
|
||||
"@tiptap/extension-table": "3.27.1",
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
"@radix-ui/react-toggle-group": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.10",
|
||||
"@tanstack/react-query": "latest",
|
||||
"@tiptap/core": "3.27.1",
|
||||
"@tiptap/extension-image": "^3.27.1",
|
||||
"@tiptap/extension-placeholder": "latest",
|
||||
"@tiptap/extension-table": "3.27.1",
|
||||
|
||||
@@ -72,3 +72,33 @@ describe("Mermaid Markdown conversion", () => {
|
||||
expect(docToMarkdown(doc)).toBe(markdown);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Theme block compatibility", () => {
|
||||
test("keeps themed blocks in the richer JSON document when Markdown is also present", () => {
|
||||
const doc = {
|
||||
type: "doc",
|
||||
content: [{
|
||||
type: "edgeeverThemeBlock",
|
||||
attrs: { kind: "key-point" },
|
||||
content: [{ type: "paragraph", content: [{ type: "text", text: "Important" }] }],
|
||||
}],
|
||||
};
|
||||
|
||||
expect(resolveMemoContentDoc(doc, "Important")).toBe(doc);
|
||||
});
|
||||
|
||||
test("exports themed blocks as readable quoted Markdown instead of dropping their text", () => {
|
||||
const doc = {
|
||||
type: "doc",
|
||||
content: [{
|
||||
type: "edgeeverThemeBlock",
|
||||
attrs: { kind: "intro" },
|
||||
content: [{ type: "paragraph", content: [{ type: "text", text: "Read this first" }] }],
|
||||
}],
|
||||
};
|
||||
|
||||
const markdown = docToMarkdown(doc);
|
||||
expect(markdown).toContain("\\[intro\\]");
|
||||
expect(markdown).toContain("Read this first");
|
||||
});
|
||||
});
|
||||
@@ -72,7 +72,7 @@ export const resolveMemoContentDoc = (
|
||||
const currentDoc = contentJson && Array.isArray(contentJson.content)
|
||||
? upgradeLegacyAttachmentLinks(contentJson)
|
||||
: emptyDoc();
|
||||
if (!contentMarkdown?.trim() || docContainsNodeType(currentDoc, "table")) {
|
||||
if (!contentMarkdown?.trim() || docContainsNodeType(currentDoc, "table") || docContainsNodeType(currentDoc, "edgeeverThemeBlock")) {
|
||||
return currentDoc;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,36 @@ export const docToMarkdown = (doc: unknown): string => {
|
||||
return "";
|
||||
}
|
||||
|
||||
return markdownManager.serialize(doc as Parameters<typeof markdownManager.serialize>[0]);
|
||||
return markdownManager.serialize(stripEditorOnlyNodes(doc) as Parameters<typeof markdownManager.serialize>[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Theme blocks are richer editor-only nodes. Markdown has no portable equivalent,
|
||||
* so exports keep their text as a quoted section instead of silently dropping it.
|
||||
*/
|
||||
const stripEditorOnlyNodes = (doc: unknown): unknown => {
|
||||
if (!doc || typeof doc !== "object") {
|
||||
return doc;
|
||||
}
|
||||
|
||||
const node = doc as { type?: unknown; attrs?: Record<string, unknown>; content?: unknown };
|
||||
if (node.type === "edgeeverThemeBlock") {
|
||||
const label = getStringAttr(node.attrs, "kind");
|
||||
const content = Array.isArray(node.content) ? node.content : [];
|
||||
return {
|
||||
type: "blockquote",
|
||||
content: [
|
||||
{ type: "paragraph", content: [{ type: "text", text: label ? `[${label}]` : "[主题化组件]" }] },
|
||||
...content.map(stripEditorOnlyNodes),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
if (!Array.isArray(node.content)) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
return { ...node, content: node.content.map(stripEditorOnlyNodes) };
|
||||
};
|
||||
|
||||
const getStringAttr = (attrs: Record<string, unknown> | undefined, key: string) => {
|
||||
|
||||
@@ -157,6 +157,7 @@ export const enUS = {
|
||||
"zen-whitespace": "Zen Whitespace",
|
||||
"moyu-ticket": "Moyu Ticket",
|
||||
"olive-journal": "Olive Journal",
|
||||
"mdnice-nenqing": "Tender Green (MDNice)",
|
||||
},
|
||||
mermaidThemes: {
|
||||
"zinc-light": "Zinc Light",
|
||||
@@ -531,6 +532,9 @@ export const enUS = {
|
||||
typeInput: "Type",
|
||||
clipboardReadFailed: "Could not read the clipboard. Check that your browser allows clipboard access.",
|
||||
characterCount: "{{count}} chars",
|
||||
copyToWeChat: "Copy to WeChat",
|
||||
copiedToWeChat: "Copied",
|
||||
copyToWeChatFailed: "Copy failed",
|
||||
},
|
||||
editorToolbar: {
|
||||
toolbar: "Editor toolbar",
|
||||
@@ -557,6 +561,14 @@ export const enUS = {
|
||||
mermaidEmpty: "Enter Mermaid source below to generate a diagram.",
|
||||
mermaidSource: "Mermaid source",
|
||||
horizontalRule: "Divider",
|
||||
themeBlock: "Themed block",
|
||||
deleteThemeBlock: "Delete themed block",
|
||||
themeBlocks: {
|
||||
intro: "Intro card",
|
||||
"key-point": "Key point card",
|
||||
callout: "Callout block",
|
||||
chapter: "Chapter heading",
|
||||
},
|
||||
table: "Table",
|
||||
insertTable: "Insert 3 × 3 table",
|
||||
addTableRow: "Add row below",
|
||||
|
||||
@@ -157,6 +157,7 @@ export const zhCN = {
|
||||
"zen-whitespace": "留白禅意风",
|
||||
"moyu-ticket": "摸鱼票据风",
|
||||
"olive-journal": "橄榄手记",
|
||||
"mdnice-nenqing": "嫩青(MDNice)",
|
||||
},
|
||||
mermaidThemes: {
|
||||
"zinc-light": "Zinc 浅色",
|
||||
@@ -531,6 +532,9 @@ export const zhCN = {
|
||||
typeInput: "输入",
|
||||
clipboardReadFailed: "读取剪贴板失败。请确认浏览器允许剪贴板权限。",
|
||||
characterCount: "{{count}} 字",
|
||||
copyToWeChat: "复制到公众号",
|
||||
copiedToWeChat: "已复制",
|
||||
copyToWeChatFailed: "复制失败",
|
||||
},
|
||||
editorToolbar: {
|
||||
toolbar: "编辑器工具栏",
|
||||
@@ -557,6 +561,14 @@ export const zhCN = {
|
||||
mermaidEmpty: "在下方输入 Mermaid 源码以生成图表。",
|
||||
mermaidSource: "Mermaid 源码",
|
||||
horizontalRule: "分割线",
|
||||
themeBlock: "主题化组件",
|
||||
deleteThemeBlock: "删除主题化组件",
|
||||
themeBlocks: {
|
||||
intro: "引言卡片",
|
||||
"key-point": "重点观点卡",
|
||||
callout: "提示块",
|
||||
chapter: "章节标题块",
|
||||
},
|
||||
table: "表格",
|
||||
insertTable: "插入 3 × 3 表格",
|
||||
addTableRow: "在下方添加行",
|
||||
|
||||
Reference in new issue
Block a user