feat(web): add M0 live preview editor prototype
- CodeMirror 6 editor with Obsidian/Typora-style live preview: block markup revealed per line, inline markup revealed per element - Fenced code highlighting via Shiki (github-dark, JS regex engine) in a Web Worker, languages loaded on demand - Lezer syntax tree to HTML renderer for share pages, checked against the CommonMark 0.31.2 spec (640/652; 12 known parser deviations) - Use markdownLanguage directly to avoid bundling lang-html/css/js
This commit is contained in:
1 parent
4636649576
commit
a1597697e5
19 files changed
+3870
No files matched your search
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 基础主题。--rm-* 变量即主题 API,第三方主题只需覆盖这些变量。
|
||||
* 代码块与行内代码配色取自 vuejs.org(@vue/theme + Shiki github-dark)。
|
||||
*/
|
||||
:root {
|
||||
--rm-font-text: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', 'Hiragino Sans GB',
|
||||
'Microsoft YaHei', 'Noto Sans CJK SC', 'Helvetica Neue', sans-serif;
|
||||
--rm-font-mono: ui-monospace, 'SF Mono', 'SFMono-Regular', Menlo, Monaco, 'Cascadia Mono', Consolas,
|
||||
'Liberation Mono', 'Noto Sans Mono', 'DejaVu Sans Mono', 'Roboto Mono', 'Courier New', monospace;
|
||||
--rm-font-size: 16px;
|
||||
--rm-line-height: 1.7;
|
||||
--rm-content-width: 760px;
|
||||
|
||||
--rm-bg: #ffffff;
|
||||
--rm-text: #213547;
|
||||
--rm-text-muted: rgba(60, 60, 60, 0.7);
|
||||
--rm-divider: rgba(60, 60, 60, 0.12);
|
||||
--rm-accent: #42b883;
|
||||
--rm-accent-strong: #33a06f;
|
||||
--rm-selection: rgba(66, 184, 131, 0.22);
|
||||
|
||||
--rm-inline-code-bg: #f1f1f1;
|
||||
--rm-inline-code-text: #476582;
|
||||
--rm-code-bg: #292d3e;
|
||||
--rm-code-text: #e1e4e8;
|
||||
--rm-code-font-size: 14px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--rm-bg: #1a1a1a;
|
||||
--rm-text: rgba(255, 255, 255, 0.87);
|
||||
--rm-text-muted: rgba(235, 235, 235, 0.6);
|
||||
--rm-divider: rgba(84, 84, 84, 0.48);
|
||||
--rm-accent: #42d392;
|
||||
--rm-accent-strong: #42b883;
|
||||
--rm-inline-code-bg: #2f2f2f;
|
||||
--rm-inline-code-text: #aac8e4;
|
||||
--rm-code-bg: #242424;
|
||||
}
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
background: var(--rm-bg);
|
||||
color: var(--rm-text);
|
||||
font-family: var(--rm-font-text);
|
||||
}
|
||||
|
||||
.cm-editor {
|
||||
font-size: var(--rm-font-size);
|
||||
line-height: var(--rm-line-height);
|
||||
background: var(--rm-bg);
|
||||
color: var(--rm-text);
|
||||
}
|
||||
.cm-editor.cm-focused {
|
||||
outline: none;
|
||||
}
|
||||
.cm-editor .cm-scroller {
|
||||
font-family: var(--rm-font-text);
|
||||
}
|
||||
.cm-editor .cm-content {
|
||||
max-width: var(--rm-content-width);
|
||||
margin: 0 auto;
|
||||
padding: 32px 24px 40vh;
|
||||
caret-color: var(--rm-accent-strong);
|
||||
}
|
||||
.cm-editor .cm-cursor {
|
||||
border-left: 2px solid var(--rm-accent-strong);
|
||||
}
|
||||
.cm-editor .cm-selectionBackground,
|
||||
.cm-editor.cm-focused .cm-selectionBackground {
|
||||
background: var(--rm-selection) !important;
|
||||
}
|
||||
|
||||
/* 标题 */
|
||||
.cm-line.cm-rm-h1 { font-size: 2em; line-height: 1.3; padding-top: 0.6em; }
|
||||
.cm-line.cm-rm-h2 { font-size: 1.6em; line-height: 1.35; padding-top: 0.5em; }
|
||||
.cm-line.cm-rm-h3 { font-size: 1.3em; line-height: 1.4; padding-top: 0.4em; }
|
||||
.cm-line.cm-rm-h4 { font-size: 1.15em; padding-top: 0.3em; }
|
||||
.cm-line.cm-rm-h5,
|
||||
.cm-line.cm-rm-h6 { font-size: 1em; padding-top: 0.2em; }
|
||||
.cm-line.cm-rm-h6 { color: var(--rm-text-muted); }
|
||||
|
||||
/* Markdown 标记(激活行显示源码时) */
|
||||
.cm-rm-markup,
|
||||
.cm-rm-url { color: var(--rm-text-muted); }
|
||||
.cm-rm-link,
|
||||
.cm-rm-link .cm-rm-url { color: var(--rm-accent-strong); text-decoration: none; cursor: text; }
|
||||
|
||||
/* 行内代码 */
|
||||
.cm-rm-inline-code {
|
||||
font-family: var(--rm-font-mono);
|
||||
font-size: 0.875em;
|
||||
background: var(--rm-inline-code-bg);
|
||||
color: var(--rm-inline-code-text);
|
||||
padding: 0.15em 0.4em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 代码块 */
|
||||
.cm-line.cm-rm-code {
|
||||
font-family: var(--rm-font-mono);
|
||||
font-size: var(--rm-code-font-size);
|
||||
line-height: 1.5;
|
||||
background: var(--rm-code-bg);
|
||||
color: var(--rm-code-text);
|
||||
padding: 0 24px;
|
||||
tab-size: 4;
|
||||
}
|
||||
.cm-line.cm-rm-code .cm-rm-mono { font-family: inherit; }
|
||||
.cm-line.cm-rm-code-begin { border-radius: 8px 8px 0 0; padding-top: 10px; }
|
||||
.cm-line.cm-rm-code-end { border-radius: 0 0 8px 8px; padding-bottom: 10px; }
|
||||
.cm-line.cm-rm-code-begin.cm-rm-code-end { border-radius: 8px; }
|
||||
/* 未激活时的围栏行:压低行高,只显示右上角语言标签 */
|
||||
.cm-line.cm-rm-code-fence { font-size: 12px; line-height: 1.2; text-align: right; }
|
||||
.cm-rm-code-lang {
|
||||
color: rgba(235, 235, 235, 0.38);
|
||||
user-select: none;
|
||||
}
|
||||
.cm-rm-code .cm-rm-markup { color: rgba(235, 235, 235, 0.38); }
|
||||
|
||||
/* 引用 */
|
||||
.cm-line.cm-rm-quote {
|
||||
border-left: 3px solid var(--rm-divider);
|
||||
padding-left: 16px;
|
||||
color: var(--rm-text-muted);
|
||||
}
|
||||
|
||||
/* 列表 */
|
||||
.cm-rm-bullet { color: var(--rm-text-muted); display: inline-block; width: 1ch; }
|
||||
.cm-rm-task { margin: 0 0.4em 0 0; vertical-align: -0.1em; accent-color: var(--rm-accent); cursor: pointer; }
|
||||
|
||||
/* 分隔线 */
|
||||
.cm-rm-hr { display: inline-block; width: 100%; border-top: 1px solid var(--rm-divider); vertical-align: middle; }
|
||||
|
||||
/* 图片 */
|
||||
.cm-rm-image { display: block; }
|
||||
.cm-rm-image img { max-width: 100%; border-radius: 4px; }
|
||||
.cm-rm-image-error { color: var(--rm-text-muted); font-style: italic; }
|
||||
|
||||
/* 表格(M2 前以等宽源码显示) */
|
||||
.cm-line.cm-rm-table { font-family: var(--rm-font-mono); font-size: 0.9em; }
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.cm-editor .cm-content { padding: 16px 16px 40vh; }
|
||||
.cm-line.cm-rm-code { padding: 0 12px; }
|
||||
}
|
||||
Reference in new issue
Block a user