From 8d40fbb01ffd7515d03dff06a4299d217ec4a997 Mon Sep 17 00:00:00 2001 From: douboer Date: Thu, 16 Oct 2025 18:10:27 +0800 Subject: [PATCH] update at 2025-10-16 18:10:27 --- assets/themes.json | 12 + assets/themes/xhs-philosophy.css | 386 ++++++++++++++++++++++++ assets/themes/xhs-philosophy2.css | 467 ++++++++++++++++++++++++++++++ src/core/progress-indicator.ts | 75 ++++- src/preview-manager.ts | 16 + src/preview-view.ts | 10 +- src/wechat/wechat-preview.ts | 18 +- src/xiaohongshu/xhs-preview.ts | 63 ++++ styles.css | 7 +- todolist.md | 5 +- 10 files changed, 1030 insertions(+), 29 deletions(-) create mode 100644 assets/themes/xhs-philosophy.css create mode 100644 assets/themes/xhs-philosophy2.css diff --git a/assets/themes.json b/assets/themes.json index 36bec79..8961725 100644 --- a/assets/themes.json +++ b/assets/themes.json @@ -1,4 +1,16 @@ [ + { + "name": "小红书哲学风2", + "className": "xhs-philosophy2", + "desc": "项飙访谈风格,大号标题+序号章节+引号装饰,适合深度思辨文章", + "author": "gavin" + }, + { + "name": "小红书哲学风", + "className": "xhs-philosophy", + "desc": "适合哲学思辨类文章的现代排版风格,具有小红书平台特色", + "author": "gavin" + }, { "name": "微信专业版", "className": "wx-mp-pro", diff --git a/assets/themes/xhs-philosophy.css b/assets/themes/xhs-philosophy.css new file mode 100644 index 0000000..67682b1 --- /dev/null +++ b/assets/themes/xhs-philosophy.css @@ -0,0 +1,386 @@ +/* xhs-philosophy.css + * 小红书哲学类文章主题样式 + * 设计理念: + * - 现代简洁的排版风格 + * - 适合哲学、思辨类长文阅读 + * - 突出引用和重点内容 + * - 舒适的阅读体验 + * 特色: + * - 大标题设计,层次分明 + * - 特色引用样式,带引号装饰 + * - 适合小红书平台的视觉风格 + */ + +.note2any { + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + font-size: 17px; + line-height: 1.8; + color: #2c2c2c; + background: #ffffff; + margin: 0; + padding: 20px; + max-width: 750px; + margin: 0 auto; +} + +/* 段落 */ +.note2any p { + margin: 1.5em 0; + letter-spacing: 0.5px; + text-align: justify; + color: #333333; +} + +/* 标题层级设计 */ +.note2any h1, +.note2any h2, +.note2any h3, +.note2any h4, +.note2any h5, +.note2any h6 { + margin: 2.5em 0 1.2em; + line-height: 1.3; + color: #1a1a1a; + font-weight: 700; + letter-spacing: 1px; +} + +/* H1:主标题 - 大号粗体 */ +.note2any h1 { + font-size: 32px; + font-weight: 800; + margin: 1.5em 0 1em; + text-align: center; + position: relative; + padding: 0 20px; +} + +.note2any h1::before { + content: ""; + position: absolute; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + width: 60px; + height: 3px; + background: linear-gradient(90deg, #ff6b6b, #4ecdc4); + border-radius: 2px; +} + +/* H2:章节标题 - 带数字序号 */ +.note2any h2 { + font-size: 24px; + font-weight: 800; + position: relative; + padding: 15px 0 15px 60px; + margin: 2em 0 1.5em; + counter-increment: section; +} + +.note2any h2::before { + content: counter(section, decimal); + position: absolute; + left: 0; + top: 50%; + transform: translateY(-50%); + width: 40px; + height: 40px; + background: #2c2c2c; + color: white; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 18px; + font-weight: 700; +} + +/* H3:小节标题 */ +.note2any h3 { + font-size: 20px; + font-weight: 700; + border-left: 4px solid #ff6b6b; + padding-left: 15px; + margin: 2em 0 1em; +} + +/* H4-H6:次级标题 */ +.note2any h4 { + font-size: 18px; + font-weight: 600; + color: #444444; +} + +.note2any h5 { + font-size: 16px; + font-weight: 600; + color: #555555; +} + +.note2any h6 { + font-size: 15px; + font-weight: 600; + color: #666666; +} + +/* 初始化计数器 */ +.note2any { + counter-reset: section; +} + +/* 引用样式 - 仿小红书风格 */ +.note2any blockquote { + position: relative; + margin: 2em 0; + padding: 25px 30px 25px 60px; + background: #f8f9fa; + border: none; + border-radius: 12px; + border-left: 5px solid #4ecdc4; + font-size: 16px; + line-height: 1.7; + color: #2c2c2c; + box-shadow: 0 2px 10px rgba(0,0,0,0.05); +} + +.note2any blockquote::before { + content: "\201C"; + position: absolute; + left: 15px; + top: 10px; + font-size: 40px; + color: #4ecdc4; + font-family: Georgia, serif; + font-weight: bold; + line-height: 1; +} + +.note2any blockquote::after { + content: "\201D"; + position: absolute; + right: 15px; + bottom: 5px; + font-size: 40px; + color: #4ecdc4; + font-family: Georgia, serif; + font-weight: bold; + line-height: 1; +} + +.note2any blockquote p { + margin: 0.8em 0; + font-style: normal; +} + +/* 加粗文本 */ +.note2any strong, +.note2any b { + font-weight: 700; + color: #1a1a1a; + background: linear-gradient(180deg, transparent 60%, #fff2cc 60%); + padding: 2px 4px; + border-radius: 3px; +} + +/* 斜体 */ +.note2any em, +.note2any i { + font-style: italic; + color: #666666; +} + +/* 列表样式 */ +.note2any ul, +.note2any ol { + margin: 1.5em 0; + padding-left: 2em; +} + +.note2any ul li { + list-style: none; + position: relative; + margin: 0.8em 0; + padding-left: 1.5em; +} + +.note2any ul li::before { + content: "▪"; + position: absolute; + left: 0; + color: #4ecdc4; + font-size: 18px; + font-weight: bold; +} + +.note2any ol li { + margin: 0.8em 0; + padding-left: 0.5em; +} + +/* 分隔线 */ +.note2any hr { + border: none; + height: 2px; + background: linear-gradient(90deg, transparent, #e0e0e0, transparent); + margin: 3em 0; +} + +/* 代码样式 */ +.note2any code { + background: #f1f3f4; + color: #d73a49; + padding: 3px 6px; + border-radius: 4px; + font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Code", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; + font-size: 0.9em; +} + +.note2any pre { + background: #f8f8f8; + border: 1px solid #e1e4e8; + border-radius: 8px; + padding: 20px; + margin: 2em 0; + overflow-x: auto; + line-height: 1.5; +} + +.note2any pre code { + background: none; + color: #24292e; + padding: 0; + border-radius: 0; + font-size: 14px; +} + +/* 表格样式 */ +.note2any table { + width: 100%; + border-collapse: collapse; + margin: 2em 0; + background: white; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); +} + +.note2any th, +.note2any td { + padding: 12px 15px; + text-align: left; + border-bottom: 1px solid #e1e4e8; +} + +.note2any th { + background: #f6f8fa; + font-weight: 600; + color: #24292e; +} + +.note2any tr:hover { + background: #f6f8fa; +} + +/* 图片样式 */ +.note2any img { + max-width: 100%; + height: auto; + border-radius: 8px; + margin: 1.5em 0; + box-shadow: 0 4px 15px rgba(0,0,0,0.1); + display: block; + margin-left: auto; + margin-right: auto; +} + +/* 链接样式 */ +.note2any a { + color: #4ecdc4; + text-decoration: none; + border-bottom: 1px solid transparent; + transition: all 0.3s ease; +} + +.note2any a:hover { + color: #ff6b6b; + border-bottom-color: #ff6b6b; +} + +/* 高亮标记 */ +.note2any mark { + background: linear-gradient(180deg, transparent 50%, #ffeb3b 50%); + color: #2c2c2c; + padding: 2px 4px; + border-radius: 3px; +} + +/* 删除线 */ +.note2any del, +.note2any s { + color: #999999; + text-decoration: line-through; +} + +/* 特殊样式:次仁群宗风格的标题 */ +.note2any .philosophy-title { + font-size: 28px; + font-weight: 800; + text-align: center; + margin: 2em 0 1.5em; + padding: 20px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border-radius: 12px; + box-shadow: 0 8px 25px rgba(0,0,0,0.15); +} + +/* 特殊引用:专家观点 */ +.note2any .expert-quote { + position: relative; + background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); + color: white; + padding: 25px 30px; + border-radius: 15px; + margin: 2em 0; + box-shadow: 0 8px 25px rgba(0,0,0,0.15); +} + +.note2any .expert-quote::before { + content: "专家观点"; + position: absolute; + top: -12px; + left: 20px; + background: #2c2c2c; + color: white; + padding: 5px 15px; + border-radius: 20px; + font-size: 12px; + font-weight: 600; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + .note2any { + padding: 15px; + font-size: 16px; + } + + .note2any h1 { + font-size: 28px; + } + + .note2any h2 { + font-size: 22px; + padding-left: 50px; + } + + .note2any h2::before { + width: 35px; + height: 35px; + font-size: 16px; + } + + .note2any blockquote { + padding: 20px 25px 20px 50px; + } +} \ No newline at end of file diff --git a/assets/themes/xhs-philosophy2.css b/assets/themes/xhs-philosophy2.css new file mode 100644 index 0000000..3302d72 --- /dev/null +++ b/assets/themes/xhs-philosophy2.css @@ -0,0 +1,467 @@ +/* xhs-philosophy2.css + * 小红书哲学思辨类文章主题 v2 + * 设计灵感:项飙、哲学对话访谈风格 + * 特点: + * - 大号标题,强烈视觉冲击 + * - 带序号的章节设计(❶❷❸...) + * - 引用块带引号装饰 + * - 灰色调背景,适合长文阅读 + * - 现代简约,适合小红书平台 + */ + +.note2any { + font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Arial, sans-serif; + font-size: 16px; + line-height: 1.75; + color: #1a1a1a; + background: #f5f5f5; + margin: 0; + padding: 20px; + max-width: 750px; + margin: 0 auto; +} + +/* 段落 */ +.note2any p { + margin: 1.2em 0; + letter-spacing: 0.3px; + text-align: justify; + color: #2c2c2c; + line-height: 1.8; +} + +/* 标题通用样式 */ +.note2any h1, +.note2any h2, +.note2any h3, +.note2any h4, +.note2any h5, +.note2any h6 { + margin: 2em 0 1em; + line-height: 1.3; + color: #000000; + font-weight: 800; + letter-spacing: 0.5px; +} + +/* H1:超大标题 - 主标题 */ +.note2any h1 { + font-size: 42px; + font-weight: 900; + margin: 1em 0 0.8em; + line-height: 1.2; + letter-spacing: 1px; + word-break: keep-all; +} + +/* H2:带数字序号的章节标题 */ +.note2any h2 { + font-size: 28px; + font-weight: 900; + position: relative; + padding: 12px 0 12px 0; + margin: 2em 0 1.2em; + background: #ffffff; + border-radius: 8px; + padding: 20px 24px; + box-shadow: 0 2px 8px rgba(0,0,0,0.08); + counter-increment: section; +} + +/* H2序号样式 - 使用圆形数字 */ +.note2any h2::before { + content: counter(section) " "; + display: inline-block; + width: 36px; + height: 36px; + line-height: 36px; + text-align: center; + background: #000000; + color: white; + border-radius: 50%; + font-size: 18px; + font-weight: 700; + margin-right: 12px; + vertical-align: middle; +} + +/* H3:小节标题 */ +.note2any h3 { + font-size: 22px; + font-weight: 700; + color: #1a1a1a; + padding-left: 16px; + border-left: 4px solid #000000; + margin: 1.8em 0 1em; +} + +/* H4-H6:次级标题 */ +.note2any h4 { + font-size: 18px; + font-weight: 600; + color: #2c2c2c; +} + +.note2any h5 { + font-size: 16px; + font-weight: 600; + color: #3c3c3c; +} + +.note2any h6 { + font-size: 15px; + font-weight: 600; + color: #4c4c4c; +} + +/* 初始化计数器 */ +.note2any { + counter-reset: section; +} + +/* 引用样式 - 带引号装饰 */ +.note2any blockquote { + position: relative; + margin: 2em 0; + padding: 24px 30px 24px 70px; + background: #ffffff; + border: none; + border-left: 5px solid #000000; + font-size: 15px; + line-height: 1.75; + color: #2c2c2c; + box-shadow: 0 2px 8px rgba(0,0,0,0.06); + border-radius: 4px; +} + +/* 左上引号 */ +.note2any blockquote::before { + content: "\201C"; + position: absolute; + left: 20px; + top: 15px; + font-size: 48px; + color: #000000; + font-family: Georgia, serif; + font-weight: bold; + line-height: 1; + opacity: 0.3; +} + +/* 右下引号 */ +.note2any blockquote::after { + content: "\201D"; + position: absolute; + right: 20px; + bottom: 10px; + font-size: 48px; + color: #000000; + font-family: Georgia, serif; + font-weight: bold; + line-height: 1; + opacity: 0.3; +} + +.note2any blockquote p { + margin: 0.8em 0; + font-style: normal; +} + +.note2any blockquote p:first-child { + margin-top: 0; +} + +.note2any blockquote p:last-child { + margin-bottom: 0; +} + +/* 加粗文本 - 黑色高亮 */ +.note2any strong, +.note2any b { + font-weight: 700; + color: #000000; +} + +/* 斜体 */ +.note2any em, +.note2any i { + font-style: italic; + color: #4c4c4c; +} + +/* 列表样式 */ +.note2any ul, +.note2any ol { + margin: 1.5em 0; + padding-left: 2em; +} + +.note2any ul li { + list-style: none; + position: relative; + margin: 0.8em 0; + padding-left: 1.5em; +} + +.note2any ul li::before { + content: "▸"; + position: absolute; + left: 0; + color: #000000; + font-size: 16px; + font-weight: bold; +} + +.note2any ol li { + margin: 0.8em 0; + padding-left: 0.5em; +} + +/* 分隔线 */ +.note2any hr { + border: none; + height: 1px; + background: #d0d0d0; + margin: 3em 0; +} + +/* 代码样式 */ +.note2any code { + background: #e8e8e8; + color: #000000; + padding: 3px 6px; + border-radius: 3px; + font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Code", monospace; + font-size: 0.9em; + font-weight: 500; +} + +.note2any pre { + background: #ffffff; + border: 1px solid #d0d0d0; + border-radius: 6px; + padding: 20px; + margin: 2em 0; + overflow-x: auto; + line-height: 1.5; + box-shadow: 0 2px 6px rgba(0,0,0,0.05); +} + +.note2any pre code { + background: none; + color: #2c2c2c; + padding: 0; + border-radius: 0; + font-size: 14px; +} + +/* 表格样式 */ +.note2any table { + width: 100%; + border-collapse: collapse; + margin: 2em 0; + background: white; + border-radius: 6px; + overflow: hidden; + box-shadow: 0 2px 8px rgba(0,0,0,0.08); +} + +.note2any th, +.note2any td { + padding: 12px 16px; + text-align: left; + border-bottom: 1px solid #e0e0e0; +} + +.note2any th { + background: #f5f5f5; + font-weight: 600; + color: #000000; +} + +.note2any tr:last-child td { + border-bottom: none; +} + +.note2any tr:hover { + background: #fafafa; +} + +/* 图片样式 */ +.note2any img { + max-width: 100%; + height: auto; + border-radius: 6px; + margin: 2em 0; + display: block; + margin-left: auto; + margin-right: auto; + box-shadow: 0 4px 12px rgba(0,0,0,0.15); +} + +/* 链接样式 */ +.note2any a { + color: #000000; + text-decoration: none; + border-bottom: 2px solid #000000; + transition: all 0.3s ease; + font-weight: 500; +} + +.note2any a:hover { + color: #4c4c4c; + border-bottom-color: #4c4c4c; +} + +/* 高亮标记 */ +.note2any mark { + background: #ffeb3b; + color: #000000; + padding: 2px 4px; + border-radius: 2px; + font-weight: 500; +} + +/* 删除线 */ +.note2any del, +.note2any s { + color: #888888; + text-decoration: line-through; +} + +/* 特殊样式:访谈对话框 */ +.note2any .interview-question { + background: #ffffff; + border-left: 6px solid #000000; + padding: 16px 20px; + margin: 2em 0; + border-radius: 4px; + box-shadow: 0 2px 6px rgba(0,0,0,0.06); +} + +.note2any .interview-question::before { + content: "次仁群宗:"; + display: block; + font-weight: 700; + color: #000000; + margin-bottom: 0.5em; + font-size: 14px; +} + +.note2any .interview-answer { + background: #f8f8f8; + padding: 16px 20px; + margin: 1em 0; + border-radius: 4px; + border-left: 4px solid #666666; +} + +.note2any .interview-answer::before { + content: "项飙:"; + display: block; + font-weight: 700; + color: #000000; + margin-bottom: 0.5em; + font-size: 14px; +} + +/* 特殊标注:观点卡片 */ +.note2any .viewpoint-card { + position: relative; + background: linear-gradient(135deg, #1a1a1a 0%, #2c2c2c 100%); + color: white; + padding: 30px; + border-radius: 8px; + margin: 2.5em 0; + box-shadow: 0 8px 20px rgba(0,0,0,0.2); +} + +.note2any .viewpoint-card::before { + content: "VIEWPOINT"; + position: absolute; + top: -12px; + right: 20px; + background: #000000; + color: white; + padding: 5px 15px; + border-radius: 20px; + font-size: 11px; + font-weight: 600; + letter-spacing: 1px; +} + +/* 带三角形装饰的引用块 */ +.note2any .quote-triangle { + position: relative; + background: #ffffff; + padding: 20px 25px; + margin: 2em 0; + border-radius: 6px; + box-shadow: 0 3px 10px rgba(0,0,0,0.1); +} + +.note2any .quote-triangle::before { + content: "▶"; + position: absolute; + left: -10px; + top: 20px; + color: #000000; + font-size: 20px; +} + +/* 响应式设计 */ +@media (max-width: 768px) { + .note2any { + padding: 15px; + font-size: 15px; + } + + .note2any h1 { + font-size: 32px; + } + + .note2any h2 { + font-size: 24px; + padding: 16px 20px; + } + + .note2any h2::before { + width: 32px; + height: 32px; + line-height: 32px; + font-size: 16px; + margin-right: 10px; + } + + .note2any blockquote { + padding: 20px 25px 20px 60px; + } + + .note2any blockquote::before, + .note2any blockquote::after { + font-size: 36px; + } +} + +/* 确保在小红书平台的兼容性 */ +.note2any * { + box-sizing: border-box; +} + +/* 打印样式优化 */ +@media print { + .note2any { + background: white; + color: black; + } + + .note2any blockquote { + page-break-inside: avoid; + } + + .note2any h1, + .note2any h2, + .note2any h3 { + page-break-after: avoid; + } +} diff --git a/src/core/progress-indicator.ts b/src/core/progress-indicator.ts index acbdbd5..e649ef4 100644 --- a/src/core/progress-indicator.ts +++ b/src/core/progress-indicator.ts @@ -11,28 +11,41 @@ export interface ProgressOptions { autoHide?: boolean; } -export class ProgressIndicator { - private notice: Notice | null = null; +class GlobalProgressManager { + private static instance: GlobalProgressManager | null = null; + private currentNotice: Notice | null = null; private startTime: number = 0; + static getInstance(): GlobalProgressManager { + if (!GlobalProgressManager.instance) { + GlobalProgressManager.instance = new GlobalProgressManager(); + } + return GlobalProgressManager.instance; + } + start(message: string, options: ProgressOptions = {}): void { - this.startTime = Date.now(); - const { duration = 0 } = options; + // 如果已有通知,先关闭 + if (this.currentNotice) { + this.currentNotice.hide(); + } - this.notice = new Notice(`🔄 ${message}...`, duration); + this.startTime = Date.now(); + const { duration = 10000 } = options; // 默认10秒自动消失,防止卡住 + + this.currentNotice = new Notice(`🔄 ${message}...`, duration); } update(message: string, progress?: number): void { - if (!this.notice) return; + if (!this.currentNotice) return; - const progressText = progress ? ` (${Math.round(progress)}%)` : ''; - this.notice.setMessage(`🔄 ${message}${progressText}...`); + const progressText = progress !== undefined ? ` (${Math.round(progress)}%)` : ''; + this.currentNotice.setMessage(`🔄 ${message}${progressText}...`); } finish(message: string, success: boolean = true): void { - if (this.notice) { - this.notice.hide(); - this.notice = null; + if (this.currentNotice) { + this.currentNotice.hide(); + this.currentNotice = null; } const duration = Date.now() - this.startTime; @@ -43,17 +56,49 @@ export class ProgressIndicator { } error(message: string): void { - this.finish(message, false); + if (this.currentNotice) { + this.currentNotice.hide(); + this.currentNotice = null; + } + + const duration = Date.now() - this.startTime; + const durationText = duration > 1000 ? ` (${(duration / 1000).toFixed(1)}s)` : ''; + + new Notice(`❌ ${message}${durationText}`, 5000); } hide(): void { - if (this.notice) { - this.notice.hide(); - this.notice = null; + if (this.currentNotice) { + this.currentNotice.hide(); + this.currentNotice = null; } } } +export class ProgressIndicator { + private manager = GlobalProgressManager.getInstance(); + + start(message: string, options: ProgressOptions = {}): void { + this.manager.start(message, options); + } + + update(message: string, progress?: number): void { + this.manager.update(message, progress); + } + + finish(message: string, success: boolean = true): void { + this.manager.finish(message, success); + } + + error(message: string): void { + this.manager.error(message); + } + + hide(): void { + this.manager.hide(); + } +} + export class BatchProgressIndicator { private currentProgress: ProgressIndicator | null = null; private totalItems: number = 0; diff --git a/src/preview-manager.ts b/src/preview-manager.ts index 25b16dc..ca30bb8 100644 --- a/src/preview-manager.ts +++ b/src/preview-manager.ts @@ -204,6 +204,14 @@ export class PreviewManager { this.showWechat(); this.hideXiaohongshu(); + // 同步主题设置 + if (this.wechatPreview) { + this.wechatPreview.updateStyleAndHighlight( + this.settings.defaultStyle, + this.settings.defaultHighlight + ); + } + // 如果有当前文件且是从其他平台切换过来,重新渲染 if (this.currentFile && previousPlatform !== 'wechat') { await this.renderForWechat(this.currentFile); @@ -213,6 +221,14 @@ export class PreviewManager { this.showXiaohongshu(); this.hideWechat(); + // 同步主题设置 + if (this.xhsPreview) { + this.xhsPreview.updateStyleAndHighlight( + this.settings.defaultStyle, + this.settings.defaultHighlight + ); + } + // 如果有当前文件且是从其他平台切换过来,重新渲染 if (this.currentFile && previousPlatform !== 'xiaohongshu') { await this.renderForXiaohongshu(this.currentFile); diff --git a/src/preview-view.ts b/src/preview-view.ts index 57abcbb..42af38b 100644 --- a/src/preview-view.ts +++ b/src/preview-view.ts @@ -106,9 +106,6 @@ export class PreviewView extends ItemView { async onOpen(): Promise { console.log('[PreviewView] 视图打开 layoutReady=', this.app.workspace.layoutReady); - const progress = new ProgressIndicator(); - progress.start('初始化预览视图'); - try { // 不在未完成 layoutReady 时做重初始化,改为延迟 if (!this.app.workspace.layoutReady) { @@ -121,15 +118,14 @@ export class PreviewView extends ItemView { return; } await this.performInitialization(); - progress.finish('预览视图初始化完成'); } catch (error) { - progress.error('预览视图初始化失败'); ErrorHandler.handle(error as Error, 'PreviewView.onOpen'); } } private async performInitialization(): Promise { const progress = new ProgressIndicator(); + progress.start('初始化预览视图'); try { const start = performance.now(); @@ -162,10 +158,10 @@ export class PreviewView extends ItemView { } console.log('[PreviewView] 初始化耗时(ms):', (performance.now() - start).toFixed(1)); - progress.finish('视图初始化完成'); + progress.finish('预览视图初始化完成'); uevent('open'); } catch (error) { - progress.error('视图初始化失败'); + progress.error('预览视图初始化失败'); ErrorHandler.handle(error as Error, 'PreviewView.performInitialization'); console.error('[PreviewView] 初始化失败', error); this.showError('预览视图初始化失败,请检查插件设置'); diff --git a/src/wechat/wechat-preview.ts b/src/wechat/wechat-preview.ts index f8d2147..bc64b3b 100644 --- a/src/wechat/wechat-preview.ts +++ b/src/wechat/wechat-preview.ts @@ -71,9 +71,7 @@ export class WechatPreview { this.board = this.container.createDiv({ cls: 'wechat-board' }); this.buildAccountRow(); - - //this.buildCoverRow(); - //this.buildStyleRow(); + this.buildStyleRow(); this.contentCell = this.createCell('content'); this.contentCell.addClass('wechat-cell-content'); @@ -203,7 +201,14 @@ export class WechatPreview { const selectBtn = styleSelectCell.createEl('select', { cls: 'style-select wechat-style-select' }) as HTMLSelectElement; selectBtn.onchange = async () => { this.currentTheme = selectBtn.value; + // 更新全局设置 + this.settings.defaultStyle = selectBtn.value; this.render.updateStyle(selectBtn.value); + // 保存设置 + const plugin = (this.app as any)?.plugins?.getPlugin?.('note2any'); + if (plugin?.saveSettings) { + await plugin.saveSettings(); + } }; for (let s of this.assetsManager.themes) { @@ -221,7 +226,14 @@ export class WechatPreview { const highlightStyleBtn = highlightSelectCell.createEl('select', { cls: 'style-select wechat-style-select' }) as HTMLSelectElement; highlightStyleBtn.onchange = async () => { this.currentHighlight = highlightStyleBtn.value; + // 更新全局设置 + this.settings.defaultHighlight = highlightStyleBtn.value; this.render.updateHighLight(highlightStyleBtn.value); + // 保存设置 + const plugin = (this.app as any)?.plugins?.getPlugin?.('note2any'); + if (plugin?.saveSettings) { + await plugin.saveSettings(); + } }; const highlights = this.assetsManager.highlights; diff --git a/src/xiaohongshu/xhs-preview.ts b/src/xiaohongshu/xhs-preview.ts index 6d7a7fe..4daad37 100644 --- a/src/xiaohongshu/xhs-preview.ts +++ b/src/xiaohongshu/xhs-preview.ts @@ -37,6 +37,8 @@ export class XiaohongshuPreview { templateSelect!: HTMLSelectElement; fontSizeInput!: HTMLInputElement; previewWidthSelect!: HTMLSelectElement; + themeSelect!: HTMLSelectElement; + highlightSelect!: HTMLSelectElement; pageContainer!: HTMLDivElement; pageNumberInput!: HTMLInputElement; @@ -132,6 +134,54 @@ export class XiaohongshuPreview { const increaseBtn = fontSizeGroup.createEl('button', { text: '+', cls: 'font-size-btn' }); increaseBtn.onclick = () => this.changeFontSize(1); + // 主题选择器 + const themeCard = this.createGridCard(board, 'xhs-area-theme'); + const themeLabel = themeCard.createDiv({ cls: 'xhs-label', text: '主题' }); + this.themeSelect = themeCard.createEl('select', { cls: 'xhs-select' }); + this.themeSelect.onchange = async () => { + // 更新全局设置 + this.settings.defaultStyle = this.themeSelect.value; + this.applyThemeCSS(); + await this.repaginateAndRender(); + // 保存设置 + const plugin = (this.app as any)?.plugins?.getPlugin?.('note2any'); + if (plugin?.saveSettings) { + await plugin.saveSettings(); + } + }; + + // 填充主题选项 + for (let theme of this.assetsManager.themes) { + const option = this.themeSelect.createEl('option'); + option.value = theme.className; + option.text = theme.name; + option.selected = theme.className === this.settings.defaultStyle; + } + + // 高亮选择器 + const highlightCard = this.createGridCard(board, 'xhs-area-highlight'); + const highlightLabel = highlightCard.createDiv({ cls: 'xhs-label', text: '代码高亮' }); + this.highlightSelect = highlightCard.createEl('select', { cls: 'xhs-select' }); + this.highlightSelect.onchange = async () => { + // 更新全局设置 + this.settings.defaultHighlight = this.highlightSelect.value; + this.applyThemeCSS(); + await this.repaginateAndRender(); + // 保存设置 + const plugin = (this.app as any)?.plugins?.getPlugin?.('note2any'); + if (plugin?.saveSettings) { + await plugin.saveSettings(); + } + }; + + // 填充高亮选项 + for (let highlight of this.assetsManager.highlights) { + const option = this.highlightSelect.createEl('option'); + option.value = highlight.url; + option.text = highlight.name; + option.selected = highlight.url === this.settings.defaultHighlight; + } + const contentWrapper = board.createDiv({ cls: 'xhs-area-content' }); this.pageContainer = contentWrapper.createDiv({ cls: 'xhs-page-container' }); @@ -547,4 +597,17 @@ export class XiaohongshuPreview { document.body.removeChild(tempContainer); } } + + /** + * 更新主题和高亮选择器的值 + */ + updateStyleAndHighlight(theme: string, highlight: string): void { + if (this.themeSelect) { + this.themeSelect.value = theme; + } + if (this.highlightSelect) { + this.highlightSelect.value = highlight; + } + this.applyThemeCSS(); + } } diff --git a/styles.css b/styles.css index ee6c919..72b4baa 100644 --- a/styles.css +++ b/styles.css @@ -591,7 +591,7 @@ label:hover { color: var(--c-primary); } grid-template-rows: auto auto auto 1fr auto; grid-template-areas: "template template preview preview font font" - "content content content content content content" + "theme theme highlight highlight highlight highlight" "content content content content content content" "content content content content content content" "pagination pagination pagination slice slice slice"; @@ -629,7 +629,8 @@ label:hover { color: var(--c-primary); } background: white; font-size: 13px; cursor: pointer; - max-width: 100px; + min-width: 80px; + max-width: 140px; transition: border-color 0.2s ease; } @@ -683,6 +684,8 @@ label:hover { color: var(--c-primary); } grid-area: font; flex-wrap: nowrap; } +.xhs-area-theme { grid-area: theme; } +.xhs-area-highlight { grid-area: highlight; } .xhs-area-pagination { grid-area: pagination; justify-content: center; gap: 16px; } .xhs-area-slice { grid-area: slice; justify-content: center; gap: 16px; } diff --git a/todolist.md b/todolist.md index e2cc793..1c0f5a8 100644 --- a/todolist.md +++ b/todolist.md @@ -161,7 +161,9 @@ SOLVE:obsidian控制台打印信息,定位在哪里阻塞,AI修复。 1. 全量扫描系统,从设计、结构、冗余度、优雅、可维护性方便,检查是否有优化的地方。 ✅ -2. 后续在主题切换和使用上的独立性和便捷性。 +2. 后续在主题切换和使用上的独立性和便捷性。统一样式。 +统一CSS处理流程。 +添加平台无关的基础样式。 ## 思路 1. 网上图片模版,让AI快速生成css themes主题。快速套用。‼️ @@ -169,4 +171,3 @@ SOLVE:obsidian控制台打印信息,定位在哪里阻塞,AI修复。 -