release: v0.4.0 — MetonaEditor 集成与架构重构
feat(editor): 将 Milkdown/ProseMirror 替换为 @metona-team/metona-editor v0.1.3 - 三模式视图 (edit/split/preview) 由编辑器内置工具栏切换 - searchReplace + imagePaste 预设插件 - unified/rehype 渲染管线通过 render 钩子集成 - 主题双向同步 (应用暗色模式 ↔ 编辑器主题) feat(toast): metona-toast 迁移为 @metona-team/metona-toast v2.0.1 refactor: 删除冗余组件与代码 - 移除 SourceEditor、Preview、SearchReplace、EditorToolbar、useMilkdown - 移除 StatusBar 组件及状态栏扩展架构(编辑器内置底栏替代) - 移除 useSettings、useStatusBarItem、useStatusBarItems、statusBarStore - 移除 EditMode/PreviewMode/SourceMode 图标 refactor(ui): 简化布局 - 工具栏移除模式切换按钮,新增自动保存开关 - useKeyboard 移除 Ctrl+1/2/3/B/I 快捷键 - Editor 三模式统一由 MetonaEditor 容器渲染 chore: 版本号 v0.3.13 → v0.4.0 docs: 全面更新 README/DESIGN/CONTRIBUTING/DEVSETUP
This commit is contained in:
@@ -121,236 +121,13 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Editor Toolbar */
|
||||
.editor-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
padding: 4px 8px;
|
||||
background: var(--bg-secondary);
|
||||
border-bottom: 1px solid var(--border-light);
|
||||
flex-shrink: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.editor-toolbar::-webkit-scrollbar {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.toolbar-btn-sm {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 28px;
|
||||
height: 26px;
|
||||
padding: 0 6px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-family: var(--font-ui);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.toolbar-btn-sm:hover {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.toolbar-divider-sm {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: var(--border);
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
/* Milkdown Wrapper */
|
||||
.milkdown-wrapper {
|
||||
/* MetonaEditor Wrapper */
|
||||
.metona-editor-wrapper {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown {
|
||||
height: 100%;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 13px;
|
||||
color: var(--text);
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor {
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
padding: 12px 16px;
|
||||
outline: none;
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor p {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor h1,
|
||||
.milkdown-wrapper .milkdown .editor h2,
|
||||
.milkdown-wrapper .milkdown .editor h3,
|
||||
.milkdown-wrapper .milkdown .editor h4,
|
||||
.milkdown-wrapper .milkdown .editor h5,
|
||||
.milkdown-wrapper .milkdown .editor h6 {
|
||||
font-family: var(--font-ui);
|
||||
font-weight: 600;
|
||||
margin: 1em 0 0.5em;
|
||||
line-height: 1.3;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor h1 {
|
||||
font-size: 1.6em;
|
||||
}
|
||||
.milkdown-wrapper .milkdown .editor h2 {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
.milkdown-wrapper .milkdown .editor h3 {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor blockquote {
|
||||
border-left: 3px solid var(--primary);
|
||||
padding-left: 12px;
|
||||
margin: 0.5em 0;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor code {
|
||||
font-family: var(--font-mono);
|
||||
background: var(--bg-tertiary);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor pre {
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border-light);
|
||||
border-radius: var(--radius);
|
||||
padding: 12px 16px;
|
||||
overflow-x: auto;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor pre code {
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor ul,
|
||||
.milkdown-wrapper .milkdown .editor ol {
|
||||
padding-left: 1.5em;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor li {
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--border);
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor a {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor img {
|
||||
max-width: 100%;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
/* ProseMirror selection */
|
||||
.milkdown-wrapper .milkdown .editor .ProseMirror-selectednode {
|
||||
outline: 2px solid var(--primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.milkdown-wrapper .milkdown .editor ::selection {
|
||||
background: rgba(26, 115, 232, 0.3);
|
||||
}
|
||||
|
||||
:root.dark .milkdown-wrapper .milkdown .editor ::selection {
|
||||
background: rgba(100, 160, 255, 0.35);
|
||||
}
|
||||
|
||||
/* ProseMirror cursor */
|
||||
.milkdown-wrapper .milkdown .editor .ProseMirror-focused {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Dark mode styles for Milkdown */
|
||||
.milkdown-wrapper.milkdown-dark .milkdown {
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.milkdown-wrapper.milkdown-dark .milkdown .editor blockquote {
|
||||
border-left-color: var(--primary);
|
||||
}
|
||||
|
||||
/* Preview Panel */
|
||||
#preview-panel {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
min-width: 0;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
#preview {
|
||||
padding: 24px 32px;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* Source Editor */
|
||||
.source-editor-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.source-editor-textarea {
|
||||
flex: 1;
|
||||
border: none;
|
||||
outline: none;
|
||||
resize: none;
|
||||
padding: 16px 20px;
|
||||
font-family: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
tab-size: 2;
|
||||
color: #1e1e1e;
|
||||
background: #fafafa;
|
||||
user-select: text;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.source-editor-dark .source-editor-textarea {
|
||||
color: #d4d4d4;
|
||||
background: #1e1e1e;
|
||||
}
|
||||
|
||||
/* Tab Bar */
|
||||
#tab-bar {
|
||||
height: 36px;
|
||||
@@ -571,53 +348,21 @@ body {
|
||||
color: #ffd54f;
|
||||
}
|
||||
|
||||
/* Status Bar */
|
||||
#statusbar {
|
||||
height: var(--statusbar-height);
|
||||
background: var(--bg-secondary);
|
||||
border-top: 1px solid var(--border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-left,
|
||||
.status-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.status-divider {
|
||||
color: var(--border);
|
||||
}
|
||||
|
||||
.status-stat {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.status-auto-save {
|
||||
white-space: nowrap;
|
||||
/* Toolbar auto-save button */
|
||||
.toolbar-autosave {
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
color: var(--text-tertiary);
|
||||
transition: color 0.2s ease;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-family: var(--font-ui);
|
||||
padding: 0;
|
||||
padding: 4px 10px;
|
||||
}
|
||||
|
||||
.status-auto-save:hover {
|
||||
.toolbar-autosave:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.status-auto-save.saving {
|
||||
color: var(--primary, #1a73e8);
|
||||
.toolbar-autosave.saving {
|
||||
color: var(--primary);
|
||||
animation: auto-save-pulse 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@@ -990,14 +735,6 @@ body {
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
/* View Modes */
|
||||
#app.mode-preview #editor-panel {
|
||||
display: none;
|
||||
}
|
||||
#app.mode-editor #preview-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
@@ -1321,19 +1058,6 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
/* Status bar loading indicator */
|
||||
.status-loading {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: var(--primary);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-loading .loading-spinner-svg {
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
/* ===== UX-07: 通用可访问性增强 ===== */
|
||||
|
||||
/* Focus visible 为所有交互元素提供清晰的焦点指示 */
|
||||
@@ -1420,149 +1144,6 @@ button:focus-visible,
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
/* ===== Search & Replace Panel ===== */
|
||||
|
||||
.search-replace-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 8px 12px;
|
||||
background: var(--bg-secondary);
|
||||
border-bottom: 1px solid var(--border);
|
||||
flex-shrink: 0;
|
||||
animation: slideDown 0.15s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.search-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.search-input-group {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
height: 28px;
|
||||
padding: 0 8px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
font-family: var(--font-ui);
|
||||
outline: none;
|
||||
transition: border-color 0.15s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.search-input::placeholder {
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.search-count {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
font-size: 11px;
|
||||
color: var(--text-tertiary);
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* D6: 正则语法错误提示 */
|
||||
.search-input-group .search-count {
|
||||
color: #c5221f;
|
||||
}
|
||||
.search-input-group .search-count:not(:empty) {
|
||||
/* 仅当有正则错误时变红 */
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 28px;
|
||||
height: 28px;
|
||||
padding: 0 6px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-family: var(--font-ui);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.search-btn:hover {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.search-btn:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.search-btn.active {
|
||||
background: var(--primary-light);
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.search-close:hover {
|
||||
background: #e74c3c20;
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.replace-btn {
|
||||
font-size: 11px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
/* Search match highlights */
|
||||
.search-match-highlight {
|
||||
background: rgba(255, 213, 0, 0.4);
|
||||
color: inherit;
|
||||
border-radius: 2px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.search-match-active {
|
||||
background: rgba(255, 150, 0, 0.6);
|
||||
outline: 1px solid rgba(255, 150, 0, 0.8);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
:root.dark .search-match-highlight {
|
||||
background: rgba(255, 213, 0, 0.25);
|
||||
}
|
||||
|
||||
:root.dark .search-match-active {
|
||||
background: rgba(255, 180, 0, 0.4);
|
||||
outline-color: rgba(255, 180, 0, 0.6);
|
||||
}
|
||||
|
||||
/* ===== Outline Panel (Table of Contents) ===== */
|
||||
|
||||
.sidebar-outline-section {
|
||||
|
||||
Reference in New Issue
Block a user