diff --git a/build.sh b/build.sh index 613dcca..54aef03 100755 --- a/build.sh +++ b/build.sh @@ -11,7 +11,7 @@ FILES=("main.js" "styles.css" "manifest.json") # 3. 遍历文件,逐一备份并覆盖 for FILE in "${FILES[@]}"; do TARGET="$PLUGIN_DIR/$FILE" - BACKUP="$PLUGIN_DIR/$FILE.bk" + BACKUP="$PLUGIN_DIR/backup/$FILE.bk" if [ -f "$TARGET" ]; then cp -f "$TARGET" "$BACKUP" diff --git a/images/xhs/note2mdtest_1.png b/images/xhs/note2mdtest_1.png index 885f8da..28b299b 100644 Binary files a/images/xhs/note2mdtest_1.png and b/images/xhs/note2mdtest_1.png differ diff --git a/images/xhs/note2mdtest_3.png b/images/xhs/note2mdtest_3.png index 4ba366f..dc986ac 100644 Binary files a/images/xhs/note2mdtest_3.png and b/images/xhs/note2mdtest_3.png differ diff --git a/images/xhs/note2mdtest_7.png b/images/xhs/note2mdtest_7.png index 9151f5e..17d1102 100644 Binary files a/images/xhs/note2mdtest_7.png and b/images/xhs/note2mdtest_7.png differ diff --git a/images/xhs/note2mdtest_8.png b/images/xhs/note2mdtest_8.png index dfb2613..1a95302 100644 Binary files a/images/xhs/note2mdtest_8.png and b/images/xhs/note2mdtest_8.png differ diff --git a/images/xhs/note2mdtest_9.png b/images/xhs/note2mdtest_9.png index f1b61ff..f62b16c 100644 Binary files a/images/xhs/note2mdtest_9.png and b/images/xhs/note2mdtest_9.png differ diff --git a/src/doc-modal.ts b/src/doc-modal.ts index e08683b..e569607 100644 --- a/src/doc-modal.ts +++ b/src/doc-modal.ts @@ -19,26 +19,21 @@ export class DocModal extends Modal { onOpen() { let { contentEl, modalEl } = this; - modalEl.style.width = '640px'; - modalEl.style.height = '720px'; - contentEl.style.display = 'flex'; - contentEl.style.flexDirection = 'column'; + modalEl.addClass('doc-modal'); + contentEl.addClass('doc-modal-content'); - const titleEl = contentEl.createEl('h2', { text: this.title }); - titleEl.style.marginTop = '0.5em'; - const content = contentEl.createEl('div'); - content.setAttr('style', 'margin-bottom:1em;-webkit-user-select: text; user-select: text;'); + const titleEl = contentEl.createEl('h2', { text: this.title, cls: 'doc-modal-title' }); + const content = contentEl.createEl('div', { cls: 'doc-modal-desc' }); content.appendChild(sanitizeHTMLToDom(this.content)); const iframe = contentEl.createEl('iframe', { + cls: 'doc-modal-iframe', attr: { src: this.url, width: '100%', allow: 'clipboard-read; clipboard-write', }, }); - - iframe.style.flex = '1'; } onClose() { diff --git a/src/note-preview.ts b/src/note-preview.ts index c226610..4fedc8d 100644 --- a/src/note-preview.ts +++ b/src/note-preview.ts @@ -200,14 +200,11 @@ export class NotePreview extends ItemView { // 平台选择器(新增)- 始终显示 lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line platform-selector-line' }); - lineDiv.style.cssText = 'display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: linear-gradient(135deg, #fff3e0 0%, #ffffff 100%); border-left: 4px solid #1e88e5; border-radius: 6px; margin: 8px 10px;'; const platformLabel = lineDiv.createDiv({ cls: 'style-label' }); platformLabel.innerText = '发布平台'; - platformLabel.style.cssText = 'font-size: 13px; color: #5f6368; font-weight: 500; white-space: nowrap;'; - const platformSelect = lineDiv.createEl('select', { cls: 'style-select' }); - platformSelect.style.cssText = 'padding: 6px 12px; border: 1px solid #dadce0; border-radius: 6px; background: white; font-size: 13px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.1); min-width: 150px; font-weight: 500;'; + const platformSelect = lineDiv.createEl('select', { cls: 'platform-select' }); // 添加平台选项 const wechatOption = platformSelect.createEl('option'); @@ -229,14 +226,11 @@ export class NotePreview extends ItemView { // 公众号 if (this.settings.wxInfo.length > 1 || Platform.isDesktop) { lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line wechat-only' }); - lineDiv.style.cssText = 'display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: white; border-radius: 6px; margin: 8px 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.08);'; const wxLabel = lineDiv.createDiv({ cls: 'style-label' }); wxLabel.innerText = '公众号'; - wxLabel.style.cssText = 'font-size: 13px; color: #5f6368; font-weight: 500; white-space: nowrap;'; - const wxSelect = lineDiv.createEl('select', { cls: 'style-select' }); - wxSelect.style.cssText = 'padding: 6px 12px; border: 1px solid #dadce0; border-radius: 6px; background: white; font-size: 13px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.1); min-width: 200px;'; + const wxSelect = lineDiv.createEl('select', { cls: 'wechat-select' }); wxSelect.onchange = async () => { this.currentAppId = wxSelect.value; this.onAppIdChanged(); @@ -258,13 +252,9 @@ export class NotePreview extends ItemView { if (Platform.isDesktop) { // 分隔线 - const separator = lineDiv.createDiv(); - separator.style.cssText = 'width: 1px; height: 24px; background: #dadce0; margin: 0 4px;'; + const separator = lineDiv.createDiv({ cls: 'toolbar-separator' }); - const openBtn = lineDiv.createEl('button', { text: '🌐 去公众号后台' }); - openBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3);'; - openBtn.onmouseenter = () => openBtn.style.transform = 'translateY(-1px)'; - openBtn.onmouseleave = () => openBtn.style.transform = 'translateY(0)'; + const openBtn = lineDiv.createEl('button', { text: '🌐 去公众号后台', cls: 'toolbar-button purple-gradient' }); openBtn.onclick = async () => { const { shell } = require('electron'); @@ -278,13 +268,9 @@ export class NotePreview extends ItemView { } // 复制,刷新,带图片复制,发草稿箱 - lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line wechat-only' }); - lineDiv.style.cssText = 'display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: white; border-radius: 6px; margin: 8px 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); flex-wrap: wrap;'; + lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line wechat-only flex-wrap' }); - const refreshBtn = lineDiv.createEl('button', { text: '🔄 刷新' }); - refreshBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3);'; - refreshBtn.onmouseenter = () => refreshBtn.style.transform = 'translateY(-1px)'; - refreshBtn.onmouseleave = () => refreshBtn.style.transform = 'translateY(0)'; + const refreshBtn = lineDiv.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' }); refreshBtn.onclick = async () => { await this.assetsManager.loadCustomCSS(); @@ -294,10 +280,7 @@ export class NotePreview extends ItemView { uevent('refresh'); } if (Platform.isDesktop) { - const copyBtn = lineDiv.createEl('button', { text: '📋 复制' }); - copyBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - copyBtn.onmouseenter = () => copyBtn.style.transform = 'translateY(-1px)'; - copyBtn.onmouseleave = () => copyBtn.style.transform = 'translateY(0)'; + const copyBtn = lineDiv.createEl('button', { text: '📋 复制', cls: 'toolbar-button' }); copyBtn.onclick = async() => { try { @@ -311,30 +294,21 @@ export class NotePreview extends ItemView { } } - const uploadImgBtn = lineDiv.createEl('button', { text: '📤 上传图片' }); - uploadImgBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - uploadImgBtn.onmouseenter = () => uploadImgBtn.style.transform = 'translateY(-1px)'; - uploadImgBtn.onmouseleave = () => uploadImgBtn.style.transform = 'translateY(0)'; + const uploadImgBtn = lineDiv.createEl('button', { text: '📤 上传图片', cls: 'toolbar-button' }); uploadImgBtn.onclick = async() => { await this.uploadImages(); uevent('upload'); } - const postBtn = lineDiv.createEl('button', { text: '📝 发草稿' }); - postBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - postBtn.onmouseenter = () => postBtn.style.transform = 'translateY(-1px)'; - postBtn.onmouseleave = () => postBtn.style.transform = 'translateY(0)'; + const postBtn = lineDiv.createEl('button', { text: '📝 发草稿', cls: 'toolbar-button' }); postBtn.onclick = async() => { await this.postArticle(); uevent('pub'); } - const imagesBtn = lineDiv.createEl('button', { text: '🖼️ 图片/文字' }); - imagesBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - imagesBtn.onmouseenter = () => imagesBtn.style.transform = 'translateY(-1px)'; - imagesBtn.onmouseleave = () => imagesBtn.style.transform = 'translateY(0)'; + const imagesBtn = lineDiv.createEl('button', { text: '🖼️ 图片/文字', cls: 'toolbar-button' }); imagesBtn.onclick = async() => { await this.postImages(); @@ -342,10 +316,7 @@ export class NotePreview extends ItemView { } if (Platform.isDesktop && this.settings.isAuthKeyVaild()) { - const htmlBtn = lineDiv.createEl('button', { text: '💾 导出HTML' }); - htmlBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - htmlBtn.onmouseenter = () => htmlBtn.style.transform = 'translateY(-1px)'; - htmlBtn.onmouseleave = () => htmlBtn.style.transform = 'translateY(0)'; + const htmlBtn = lineDiv.createEl('button', { text: '💾 导出HTML', cls: 'toolbar-button' }); htmlBtn.onclick = async() => { await this.exportHTML(); @@ -355,11 +326,9 @@ export class NotePreview extends ItemView { // 封面 lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line wechat-only' }); - lineDiv.style.cssText = 'display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: white; border-radius: 6px; margin: 8px 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.08);'; const coverTitle = lineDiv.createDiv({ cls: 'style-label' }); coverTitle.innerText = '封面'; - coverTitle.style.cssText = 'font-size: 13px; color: #5f6368; font-weight: 500; white-space: nowrap;'; this.useDefaultCover = lineDiv.createEl('input', { cls: 'input-style' }); this.useDefaultCover.setAttr('type', 'radio'); @@ -378,7 +347,6 @@ export class NotePreview extends ItemView { const defaultLable = lineDiv.createEl('label'); defaultLable.innerText = '默认'; defaultLable.setAttr('for', 'default-cover'); - defaultLable.style.cssText = 'font-size: 13px; color: #5f6368; cursor: pointer; user-select: none;'; this.useLocalCover = lineDiv.createEl('input', { cls: 'input-style' }); this.useLocalCover.setAttr('type', 'radio'); @@ -398,7 +366,6 @@ export class NotePreview extends ItemView { const localLabel = lineDiv.createEl('label'); localLabel.setAttr('for', 'local-cover'); localLabel.innerText = '上传'; - localLabel.style.cssText = 'font-size: 13px; color: #5f6368; cursor: pointer; user-select: none;'; this.coverEl = lineDiv.createEl('input', { cls: 'upload-input' }); this.coverEl.setAttr('type', 'file'); @@ -409,15 +376,12 @@ export class NotePreview extends ItemView { // 样式 if (this.settings.showStyleUI) { - lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line wechat-only' }); - lineDiv.style.cssText = 'display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: white; border-radius: 6px; margin: 8px 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); flex-wrap: wrap;'; + lineDiv = this.toolbar.createDiv({ cls: 'toolbar-line wechat-only flex-wrap' }); const cssStyle = lineDiv.createDiv({ cls: 'style-label' }); cssStyle.innerText = '样式'; - cssStyle.style.cssText = 'font-size: 13px; color: #5f6368; font-weight: 500; white-space: nowrap;'; const selectBtn = lineDiv.createEl('select', { cls: 'style-select' }); - selectBtn.style.cssText = 'padding: 6px 12px; border: 1px solid #dadce0; border-radius: 6px; background: white; font-size: 13px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.1); min-width: 120px;'; selectBtn.onchange = async () => { this.currentTheme = selectBtn.value; @@ -434,15 +398,12 @@ export class NotePreview extends ItemView { this.themeSelect = selectBtn; // 分隔线 - const separator = lineDiv.createDiv(); - separator.style.cssText = 'width: 1px; height: 24px; background: #dadce0; margin: 0 4px;'; + const separator = lineDiv.createDiv({ cls: 'toolbar-separator' }); const highlightStyle = lineDiv.createDiv({ cls: 'style-label' }); highlightStyle.innerText = '代码高亮'; - highlightStyle.style.cssText = 'font-size: 13px; color: #5f6368; font-weight: 500; white-space: nowrap;'; const highlightStyleBtn = lineDiv.createEl('select', { cls: 'style-select' }); - highlightStyleBtn.style.cssText = 'padding: 6px 12px; border: 1px solid #dadce0; border-radius: 6px; background: white; font-size: 13px; cursor: pointer; transition: all 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.1); min-width: 120px;'; highlightStyleBtn.onchange = async () => { this.currentHighlight = highlightStyleBtn.value; @@ -472,7 +433,6 @@ export class NotePreview extends ItemView { this.renderDiv = this.mainDiv.createDiv({cls: 'render-div'}); this.renderDiv.id = 'render-div'; - this.renderDiv.setAttribute('style', '-webkit-user-select: text; user-select: text;'); this.styleEl = this.renderDiv.createEl('style'); this.styleEl.setAttr('title', 'note-to-mp-style'); this.articleDiv = this.renderDiv.createEl('div'); @@ -558,7 +518,7 @@ export class NotePreview extends ItemView { if (this.currentPlatform === 'xiaohongshu') { // 切换到小红书预览模式 - this.switchToXiaohongshuMode(); + await this.switchToXiaohongshuMode(); } else { // 切换到微信公众号模式 this.switchToWechatMode(); @@ -568,7 +528,7 @@ export class NotePreview extends ItemView { /** * 切换到小红书预览模式 */ - private switchToXiaohongshuMode() { + private async switchToXiaohongshuMode() { // 隐藏微信相关的工具栏行和平台选择器 if (this.toolbar) { const wechatLines = this.toolbar.querySelectorAll('.wechat-only'); @@ -589,7 +549,6 @@ export class NotePreview extends ItemView { // 创建或显示小红书预览视图 if (!this._xiaohongshuPreview) { const xhsContainer = this.mainDiv.createDiv({ cls: 'xiaohongshu-preview-container' }); - xhsContainer.style.cssText = 'width: 100%; height: 100%;'; this._xiaohongshuPreview = new XiaohongshuPreviewView(xhsContainer, this.app); // 设置回调函数 @@ -613,8 +572,17 @@ export class NotePreview extends ItemView { } // 如果有当前文件,渲染小红书预览 - if (this.currentFile && this.articleHTML) { - this._xiaohongshuPreview.renderArticle(this.articleHTML, this.currentFile); + if (this.currentFile) { + // 如果还没有生成 articleHTML,先生成它 + if (!this.articleHTML) { + await this.render.renderMarkdown(this.currentFile); + this.articleHTML = this.render.articleHTML; + } + + // 渲染到小红书预览 + if (this.articleHTML) { + await this._xiaohongshuPreview.renderArticle(this.articleHTML, this.currentFile); + } } } diff --git a/src/setting-tab.ts b/src/setting-tab.ts index 9d119ad..afb76c6 100644 --- a/src/setting-tab.ts +++ b/src/setting-tab.ts @@ -160,9 +160,8 @@ export class NoteToMpSettingTab extends PluginSettingTab { this.wxInfo = this.parseWXInfo(); - const helpEl = containerEl.createEl('div'); - helpEl.style.cssText = 'display: flex;flex-direction: row;align-items: center;'; - helpEl.createEl('h2', {text: '帮助文档'}).style.cssText = 'margin-right: 10px;'; + const helpEl = containerEl.createEl('div', { cls: 'setting-help-section' }); + helpEl.createEl('h2', {text: '帮助文档', cls: 'setting-help-title'}); helpEl.createEl('a', {text: 'https://sunboshi.tech/doc', attr: {href: 'https://sunboshi.tech/doc'}}); containerEl.createEl('h2', {text: '插件设置'}); diff --git a/src/xiaohongshu/api.ts b/src/xiaohongshu/api.ts index 13b9af6..2ab7e19 100644 --- a/src/xiaohongshu/api.ts +++ b/src/xiaohongshu/api.ts @@ -76,9 +76,7 @@ export class XiaohongshuWebAPI implements XiaohongshuAPI { private initializeWebview(): void { // 创建隐藏的webview元素 this.webview = document.createElement('webview'); - this.webview.style.display = 'none'; - this.webview.style.width = '1200px'; - this.webview.style.height = '800px'; + this.webview.addClass('xhs-webview'); // 设置webview属性 this.webview.setAttribute('nodeintegration', 'false'); diff --git a/src/xiaohongshu/login-modal.ts b/src/xiaohongshu/login-modal.ts index 78c112f..03425db 100644 --- a/src/xiaohongshu/login-modal.ts +++ b/src/xiaohongshu/login-modal.ts @@ -67,20 +67,16 @@ export class XiaohongshuLoginModal extends Modal { contentEl.empty(); contentEl.addClass('xiaohongshu-login-modal'); - // 设置对话框样式 - contentEl.style.width = '400px'; - contentEl.style.padding = '20px'; - // 标题 contentEl.createEl('h2', { text: '登录小红书', - attr: { style: 'text-align: center; margin-bottom: 20px; color: #ff4757;' } + cls: 'xhs-login-title' }); // 说明文字 const descEl = contentEl.createEl('p', { text: '请使用手机号码和验证码登录小红书', - attr: { style: 'text-align: center; color: #666; margin-bottom: 30px;' } + cls: 'xhs-login-desc' }); // 手机号输入 @@ -97,23 +93,16 @@ export class XiaohongshuLoginModal extends Modal { }); // 设置输入框样式 - text.inputEl.style.width = '100%'; - text.inputEl.style.fontSize = '16px'; + text.inputEl.addClass('xhs-input-full'); }); // 验证码输入和发送按钮 - const codeContainer = contentEl.createDiv({ cls: 'code-container' }); - codeContainer.style.display = 'flex'; - codeContainer.style.alignItems = 'center'; - codeContainer.style.gap = '10px'; - codeContainer.style.marginBottom = '20px'; + const codeContainer = contentEl.createDiv({ cls: 'xhs-code-container' }); - const codeLabel = codeContainer.createDiv({ cls: 'setting-item-name' }); + const codeLabel = codeContainer.createDiv({ cls: 'setting-item-name xhs-code-label' }); codeLabel.textContent = '验证码'; - codeLabel.style.minWidth = '80px'; - const codeInputWrapper = codeContainer.createDiv(); - codeInputWrapper.style.flex = '1'; + const codeInputWrapper = codeContainer.createDiv({ cls: 'xhs-code-input-wrapper' }); new Setting(codeInputWrapper) .addText(text => { @@ -125,8 +114,7 @@ export class XiaohongshuLoginModal extends Modal { this.updateLoginButtonState(); }); - text.inputEl.style.width = '100%'; - text.inputEl.style.fontSize = '16px'; + text.inputEl.addClass('xhs-input-full'); text.inputEl.disabled = true; // 初始禁用 // 回车键登录 @@ -142,22 +130,13 @@ export class XiaohongshuLoginModal extends Modal { .setButtonText('发送验证码') .onClick(() => this.handleSendCode()); - this.sendCodeButton.buttonEl.style.minWidth = '120px'; - this.sendCodeButton.buttonEl.style.marginLeft = '10px'; + this.sendCodeButton.buttonEl.addClass('xhs-send-code-btn'); // 状态显示区域 - this.statusDiv = contentEl.createDiv({ cls: 'status-message' }); - this.statusDiv.style.minHeight = '30px'; - this.statusDiv.style.marginBottom = '20px'; - this.statusDiv.style.textAlign = 'center'; - this.statusDiv.style.fontSize = '14px'; + this.statusDiv = contentEl.createDiv({ cls: 'xhs-status-message' }); // 按钮区域 - const buttonContainer = contentEl.createDiv({ cls: 'button-container' }); - buttonContainer.style.display = 'flex'; - buttonContainer.style.justifyContent = 'center'; - buttonContainer.style.gap = '15px'; - buttonContainer.style.marginTop = '20px'; + const buttonContainer = contentEl.createDiv({ cls: 'xhs-button-container' }); // 登录按钮 this.loginButton = new ButtonComponent(buttonContainer) @@ -166,7 +145,7 @@ export class XiaohongshuLoginModal extends Modal { .setDisabled(true) .onClick(() => this.handleLogin()); - this.loginButton.buttonEl.style.minWidth = '100px'; + this.loginButton.buttonEl.addClass('xhs-login-btn'); // 取消按钮 new ButtonComponent(buttonContainer) @@ -389,21 +368,7 @@ export class XiaohongshuLoginModal extends Modal { private showStatus(message: string, type: 'info' | 'success' | 'error' = 'info') { this.statusDiv.empty(); - const messageEl = this.statusDiv.createSpan({ text: message }); - - // 设置不同类型的样式 - switch (type) { - case 'success': - messageEl.style.color = '#27ae60'; - break; - case 'error': - messageEl.style.color = '#e74c3c'; - break; - case 'info': - default: - messageEl.style.color = '#3498db'; - break; - } + const messageEl = this.statusDiv.createSpan({ text: message, cls: type || 'info' }); } onClose() { diff --git a/src/xiaohongshu/preview-view.ts b/src/xiaohongshu/preview-view.ts index 1086e07..f4261ec 100644 --- a/src/xiaohongshu/preview-view.ts +++ b/src/xiaohongshu/preview-view.ts @@ -51,14 +51,13 @@ export class XiaohongshuPreviewView { */ build(): void { this.container.empty(); - this.container.style.cssText = 'display: flex; flex-direction: column; height: 100%; background: linear-gradient(135deg, #f5f7fa 0%, #e8eaf6 100%);'; + this.container.addClass('xhs-preview-container'); // 顶部工具栏 this.buildTopToolbar(); // 页面容器 this.pageContainer = this.container.createDiv({ cls: 'xhs-page-container' }); - this.pageContainer.style.cssText = 'flex: 1; overflow: auto; display: flex; justify-content: center; align-items: center; padding: 20px; background: radial-gradient(ellipse at top, rgba(255,255,255,0.1) 0%, transparent 70%);'; // 分页导航 this.buildPageNavigation(); @@ -72,32 +71,22 @@ export class XiaohongshuPreviewView { */ private buildTopToolbar(): void { this.topToolbar = this.container.createDiv({ cls: 'xhs-top-toolbar' }); - this.topToolbar.style.cssText = 'display: flex; align-items: center; gap: 12px; padding: 8px 12px; background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%); border-bottom: 1px solid #e8eaed; box-shadow: 0 2px 4px rgba(0,0,0,0.04); flex-wrap: wrap;'; // 刷新按钮 - const refreshBtn = this.topToolbar.createEl('button', { text: '🔄 刷新' }); - refreshBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3);'; - refreshBtn.onmouseenter = () => refreshBtn.style.transform = 'translateY(-1px)'; - refreshBtn.onmouseleave = () => refreshBtn.style.transform = 'translateY(0)'; + const refreshBtn = this.topToolbar.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' }); refreshBtn.onclick = () => this.onRefresh(); // 发布按钮 - const publishBtn = this.topToolbar.createEl('button', { text: '📤 发布' }); - publishBtn.style.cssText = 'padding: 6px 14px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - publishBtn.onmouseenter = () => publishBtn.style.transform = 'translateY(-1px)'; - publishBtn.onmouseleave = () => publishBtn.style.transform = 'translateY(0)'; + const publishBtn = this.topToolbar.createEl('button', { text: '📤 发布', cls: 'toolbar-button' }); publishBtn.onclick = () => this.onPublish(); // 分隔线 const separator2 = this.topToolbar.createDiv({ cls: 'toolbar-separator' }); - separator2.style.cssText = 'width: 1px; height: 24px; background: #dadce0; margin: 0 4px;'; // 模板选择 const templateLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' }); templateLabel.innerText = '模板'; - templateLabel.style.cssText = 'font-size: 11px; color: #5f6368; font-weight: 500; white-space: nowrap;'; - this.templateSelect = this.topToolbar.createEl('select'); - this.templateSelect.style.cssText = 'padding: 4px 8px; border: 1px solid #dadce0; border-radius: 4px; background: white; font-size: 11px; cursor: pointer; transition: border-color 0.2s ease;'; + this.templateSelect = this.topToolbar.createEl('select', { cls: 'xhs-select' }); ['默认模板', '简约模板', '杂志模板'].forEach(name => { const option = this.templateSelect.createEl('option'); option.value = name; @@ -107,9 +96,7 @@ export class XiaohongshuPreviewView { // 主题选择 const themeLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' }); themeLabel.innerText = '主题'; - themeLabel.style.cssText = 'font-size: 11px; color: #5f6368; font-weight: 500; white-space: nowrap;'; - this.themeSelect = this.topToolbar.createEl('select'); - this.themeSelect.style.cssText = 'padding: 4px 8px; border: 1px solid #dadce0; border-radius: 4px; background: white; font-size: 11px; cursor: pointer; transition: border-color 0.2s ease;'; + this.themeSelect = this.topToolbar.createEl('select', { cls: 'xhs-select' }); const themes = this.assetsManager.themes; themes.forEach(theme => { const option = this.themeSelect.createEl('option'); @@ -122,9 +109,7 @@ export class XiaohongshuPreviewView { // 字体选择 const fontLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' }); fontLabel.innerText = '字体'; - fontLabel.style.cssText = 'font-size: 11px; color: #5f6368; font-weight: 500; white-space: nowrap;'; - this.fontSelect = this.topToolbar.createEl('select'); - this.fontSelect.style.cssText = 'padding: 4px 8px; border: 1px solid #dadce0; border-radius: 4px; background: white; font-size: 11px; cursor: pointer; transition: border-color 0.2s ease;'; + this.fontSelect = this.topToolbar.createEl('select', { cls: 'xhs-select' }); ['系统默认', '宋体', '黑体', '楷体', '仿宋'].forEach(name => { const option = this.fontSelect.createEl('option'); option.value = name; @@ -135,23 +120,14 @@ export class XiaohongshuPreviewView { // 字号控制 const fontSizeLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' }); fontSizeLabel.innerText = '字号'; - fontSizeLabel.style.cssText = 'font-size: 11px; color: #5f6368; font-weight: 500; white-space: nowrap;'; const fontSizeGroup = this.topToolbar.createDiv({ cls: 'font-size-group' }); - fontSizeGroup.style.cssText = 'display: flex; align-items: center; gap: 6px; background: white; border: 1px solid #dadce0; border-radius: 4px; padding: 2px;'; - const decreaseBtn = fontSizeGroup.createEl('button', { text: '−' }); - decreaseBtn.style.cssText = 'width: 24px; height: 24px; border: none; background: transparent; border-radius: 3px; cursor: pointer; font-size: 16px; color: #5f6368; transition: background 0.2s ease;'; - decreaseBtn.onmouseenter = () => decreaseBtn.style.background = '#f1f3f4'; - decreaseBtn.onmouseleave = () => decreaseBtn.style.background = 'transparent'; + const decreaseBtn = fontSizeGroup.createEl('button', { text: '−', cls: 'font-size-btn' }); decreaseBtn.onclick = () => this.changeFontSize(-1); - this.fontSizeDisplay = fontSizeGroup.createEl('span', { text: '16' }); - this.fontSizeDisplay.style.cssText = 'min-width: 24px; text-align: center; font-size: 12px; color: #202124; font-weight: 500;'; + this.fontSizeDisplay = fontSizeGroup.createEl('span', { text: '16', cls: 'font-size-display' }); - const increaseBtn = fontSizeGroup.createEl('button', { text: '+' }); - increaseBtn.style.cssText = 'width: 24px; height: 24px; border: none; background: transparent; border-radius: 3px; cursor: pointer; font-size: 14px; color: #5f6368; transition: background 0.2s ease;'; - increaseBtn.onmouseenter = () => increaseBtn.style.background = '#f1f3f4'; - increaseBtn.onmouseleave = () => increaseBtn.style.background = 'transparent'; + const increaseBtn = fontSizeGroup.createEl('button', { text: '+', cls: 'font-size-btn' }); increaseBtn.onclick = () => this.changeFontSize(1); } @@ -160,37 +136,13 @@ export class XiaohongshuPreviewView { */ private buildPageNavigation(): void { this.pageNavigation = this.container.createDiv({ cls: 'xhs-page-navigation' }); - this.pageNavigation.style.cssText = 'display: flex; justify-content: center; align-items: center; gap: 16px; padding: 12px; background: white; border-bottom: 1px solid #e8eaed;'; - const prevBtn = this.pageNavigation.createEl('button', { text: '‹' }); - prevBtn.style.cssText = 'width: 36px; height: 36px; border: 1px solid #dadce0; border-radius: 50%; cursor: pointer; font-size: 20px; background: white; color: #5f6368; transition: all 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.08);'; - prevBtn.onmouseenter = () => { - prevBtn.style.background = 'linear-gradient(135deg, #1e88e5 0%, #1565c0 100%)'; - prevBtn.style.color = 'white'; - prevBtn.style.borderColor = '#1e88e5'; - }; - prevBtn.onmouseleave = () => { - prevBtn.style.background = 'white'; - prevBtn.style.color = '#5f6368'; - prevBtn.style.borderColor = '#dadce0'; - }; + const prevBtn = this.pageNavigation.createEl('button', { text: '‹', cls: 'xhs-nav-btn' }); prevBtn.onclick = () => this.previousPage(); - this.pageNumberDisplay = this.pageNavigation.createEl('span', { text: '1/1' }); - this.pageNumberDisplay.style.cssText = 'font-size: 14px; min-width: 50px; text-align: center; color: #202124; font-weight: 500;'; + this.pageNumberDisplay = this.pageNavigation.createEl('span', { text: '1/1', cls: 'xhs-page-number' }); - const nextBtn = this.pageNavigation.createEl('button', { text: '›' }); - nextBtn.style.cssText = 'width: 36px; height: 36px; border: 1px solid #dadce0; border-radius: 50%; cursor: pointer; font-size: 20px; background: white; color: #5f6368; transition: all 0.2s ease; box-shadow: 0 1px 3px rgba(0,0,0,0.08);'; - nextBtn.onmouseenter = () => { - nextBtn.style.background = 'linear-gradient(135deg, #1e88e5 0%, #1565c0 100%)'; - nextBtn.style.color = 'white'; - nextBtn.style.borderColor = '#1e88e5'; - }; - nextBtn.onmouseleave = () => { - nextBtn.style.background = 'white'; - nextBtn.style.color = '#5f6368'; - nextBtn.style.borderColor = '#dadce0'; - }; + const nextBtn = this.pageNavigation.createEl('button', { text: '›', cls: 'xhs-nav-btn' }); nextBtn.onclick = () => this.nextPage(); } @@ -199,30 +151,11 @@ export class XiaohongshuPreviewView { */ private buildBottomToolbar(): void { this.bottomToolbar = this.container.createDiv({ cls: 'xhs-bottom-toolbar' }); - this.bottomToolbar.style.cssText = 'display: flex; justify-content: center; gap: 12px; padding: 12px 16px; background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); border-top: 1px solid #e8eaed; box-shadow: 0 -2px 4px rgba(0,0,0,0.04);'; - const currentPageBtn = this.bottomToolbar.createEl('button', { text: '⬇ 当前页切图' }); - currentPageBtn.style.cssText = 'padding: 8px 20px; background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3);'; - currentPageBtn.onmouseenter = () => { - currentPageBtn.style.transform = 'translateY(-2px)'; - currentPageBtn.style.boxShadow = '0 4px 12px rgba(30, 136, 229, 0.4)'; - }; - currentPageBtn.onmouseleave = () => { - currentPageBtn.style.transform = 'translateY(0)'; - currentPageBtn.style.boxShadow = '0 2px 6px rgba(30, 136, 229, 0.3)'; - }; + const currentPageBtn = this.bottomToolbar.createEl('button', { text: '⬇ 当前页切图', cls: 'xhs-slice-btn' }); currentPageBtn.onclick = () => this.sliceCurrentPage(); - const allPagesBtn = this.bottomToolbar.createEl('button', { text: '⇓ 全部页切图' }); - allPagesBtn.style.cssText = 'padding: 8px 20px; background: linear-gradient(135deg, #42a5f5 0%, #1e88e5 100%); color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500; transition: all 0.2s ease; box-shadow: 0 2px 6px rgba(66, 165, 245, 0.3);'; - allPagesBtn.onmouseenter = () => { - allPagesBtn.style.transform = 'translateY(-2px)'; - allPagesBtn.style.boxShadow = '0 4px 12px rgba(66, 165, 245, 0.4)'; - }; - allPagesBtn.onmouseleave = () => { - allPagesBtn.style.transform = 'translateY(0)'; - allPagesBtn.style.boxShadow = '0 2px 6px rgba(66, 165, 245, 0.3)'; - }; + const allPagesBtn = this.bottomToolbar.createEl('button', { text: '⇓ 全部页切图', cls: 'xhs-slice-btn secondary' }); allPagesBtn.onclick = () => this.sliceAllPages(); } @@ -238,7 +171,7 @@ export class XiaohongshuPreviewView { // 创建临时容器用于分页 const tempContainer = document.createElement('div'); tempContainer.innerHTML = articleHTML; - tempContainer.style.cssText = `width: ${this.settings.sliceImageWidth}px;`; + tempContainer.style.width = `${this.settings.sliceImageWidth}px`; document.body.appendChild(tempContainer); try { diff --git a/styles.css b/styles.css index 93ed899..46f37ac 100644 --- a/styles.css +++ b/styles.css @@ -16,6 +16,8 @@ flex: 1; overflow-y: auto; padding: 10px; + -webkit-user-select: text; + user-select: text; } .preview-toolbar { @@ -245,4 +247,420 @@ label:hover { 100% { transform: rotate(360deg); } +} + +/* =========================================================== */ +/* Toolbar 行样式 */ +/* =========================================================== */ + +.toolbar-line { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 12px; + background: white; + border-radius: 6px; + margin: 8px 10px; + box-shadow: 0 1px 3px rgba(0,0,0,0.08); +} + +.toolbar-line.flex-wrap { + flex-wrap: wrap; +} + +.platform-selector-line { + background: linear-gradient(135deg, #fff3e0 0%, #ffffff 100%) !important; + border-left: 4px solid #1e88e5; +} + +/* =========================================================== */ +/* 平台选择器样式 */ +/* =========================================================== */ + +.platform-select { + padding: 6px 12px; + border: 1px solid #dadce0; + border-radius: 6px; + background: white; + font-size: 13px; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + min-width: 150px; + font-weight: 500; +} + +.platform-select:hover { + border-color: #1e88e5; +} + +.platform-select:focus { + outline: none; + border-color: #1e88e5; +} + +/* =========================================================== */ +/* 微信公众号选择器样式 */ +/* =========================================================== */ + +.wechat-select { + padding: 6px 12px; + border: 1px solid #dadce0; + border-radius: 6px; + background: white; + font-size: 13px; + cursor: pointer; + transition: all 0.2s ease; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); + min-width: 200px; +} + +.wechat-select:hover { + border-color: #1e88e5; +} + +.wechat-select:focus { + outline: none; + border-color: #1e88e5; +} + +/* =========================================================== */ +/* 按钮样式 */ +/* =========================================================== */ + +.toolbar-button { + padding: 6px 14px; + background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 13px; + font-weight: 500; + transition: all 0.2s ease; + box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3); +} + +.toolbar-button:hover { + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(30, 136, 229, 0.4); +} + +.toolbar-button.purple-gradient { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + box-shadow: 0 2px 6px rgba(102, 126, 234, 0.3); +} + +.toolbar-button.purple-gradient:hover { + box-shadow: 0 4px 8px rgba(102, 126, 234, 0.4); +} + +/* =========================================================== */ +/* 分隔线样式 */ +/* =========================================================== */ + +.toolbar-separator { + width: 1px; + height: 24px; + background: #dadce0; + margin: 0 4px; +} + +/* =========================================================== */ +/* Doc Modal 样式 */ +/* =========================================================== */ + +.doc-modal { + width: 640px; + height: 720px; +} + +.doc-modal-content { + display: flex; + flex-direction: column; +} + +.doc-modal-title { + margin-top: 0.5em; +} + +.doc-modal-desc { + margin-bottom: 1em; + -webkit-user-select: text; + user-select: text; +} + +.doc-modal-iframe { + flex: 1; +} + +/* =========================================================== */ +/* Setting Tab 帮助文档样式 */ +/* =========================================================== */ + +.setting-help-section { + display: flex; + flex-direction: row; + align-items: center; +} + +.setting-help-title { + margin-right: 10px; +} + +/* =========================================================== */ +/* Xiaohongshu WebView 样式 */ +/* =========================================================== */ + +.xhs-webview { + display: none; + width: 1200px; + height: 800px; +} + +/* =========================================================== */ +/* Xiaohongshu Preview View 样式 */ +/* =========================================================== */ + +.xiaohongshu-preview-container { + width: 100%; + height: 100%; +} + +.xhs-preview-container { + display: flex; + flex-direction: column; + height: 100%; + background: linear-gradient(135deg, #f5f7fa 0%, #e8eaf6 100%); +} + +.xhs-page-container { + flex: 1; + overflow: auto; + display: flex; + justify-content: center; + align-items: center; + padding: 20px; + background: radial-gradient(ellipse at top, rgba(255,255,255,0.1) 0%, transparent 70%); +} + +.xhs-top-toolbar { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 12px; + background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%); + border-bottom: 1px solid #e8eaed; + box-shadow: 0 2px 4px rgba(0,0,0,0.04); + flex-wrap: wrap; +} + +.toolbar-label { + font-size: 11px; + color: #5f6368; + font-weight: 500; + white-space: nowrap; +} + +.xhs-select { + padding: 4px 8px; + border: 1px solid #dadce0; + border-radius: 4px; + background: white; + font-size: 11px; + cursor: pointer; + transition: border-color 0.2s ease; +} + +.xhs-select:hover { + border-color: #1e88e5; +} + +.xhs-select:focus { + outline: none; + border-color: #1e88e5; +} + +.font-size-group { + display: flex; + align-items: center; + gap: 6px; + background: white; + border: 1px solid #dadce0; + border-radius: 4px; + padding: 2px; +} + +.font-size-btn { + width: 24px; + height: 24px; + border: none; + background: transparent; + border-radius: 3px; + cursor: pointer; + font-size: 16px; + color: #5f6368; + transition: background 0.2s ease; +} + +.font-size-btn:hover { + background: #f1f3f4; +} + +.font-size-display { + min-width: 24px; + text-align: center; + font-size: 12px; + color: #202124; + font-weight: 500; +} + +.xhs-page-navigation { + display: flex; + justify-content: center; + align-items: center; + gap: 16px; + padding: 12px; + background: white; + border-bottom: 1px solid #e8eaed; +} + +.xhs-nav-btn { + width: 36px; + height: 36px; + border: 1px solid #dadce0; + border-radius: 50%; + cursor: pointer; + font-size: 20px; + background: white; + color: #5f6368; + transition: all 0.2s ease; + box-shadow: 0 1px 3px rgba(0,0,0,0.08); +} + +.xhs-nav-btn:hover { + background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); + color: white; + border-color: #1e88e5; +} + +.xhs-page-number { + font-size: 14px; + min-width: 50px; + text-align: center; + color: #202124; + font-weight: 500; +} + +.xhs-bottom-toolbar { + display: flex; + justify-content: center; + gap: 12px; + padding: 12px 16px; + background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); + border-top: 1px solid #e8eaed; + box-shadow: 0 -2px 4px rgba(0,0,0,0.04); +} + +.xhs-slice-btn { + padding: 8px 20px; + background: linear-gradient(135deg, #1e88e5 0%, #1565c0 100%); + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 13px; + font-weight: 500; + transition: all 0.2s ease; + box-shadow: 0 2px 6px rgba(30, 136, 229, 0.3); +} + +.xhs-slice-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(30, 136, 229, 0.4); +} + +.xhs-slice-btn.secondary { + background: linear-gradient(135deg, #42a5f5 0%, #1e88e5 100%); + box-shadow: 0 2px 6px rgba(66, 165, 245, 0.3); +} + +.xhs-slice-btn.secondary:hover { + box-shadow: 0 4px 12px rgba(66, 165, 245, 0.4); +} + +/* =========================================================== */ +/* Xiaohongshu Login Modal 样式 */ +/* =========================================================== */ + +.xiaohongshu-login-modal { + width: 400px; + padding: 20px; +} + +.xhs-login-title { + text-align: center; + margin-bottom: 20px; + color: #ff4757; +} + +.xhs-login-desc { + text-align: center; + color: #666; + margin-bottom: 30px; +} + +.xhs-code-container { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 20px; +} + +.xhs-code-label { + min-width: 80px; +} + +.xhs-code-input-wrapper { + flex: 1; +} + +.xhs-input-full { + width: 100%; + font-size: 16px; +} + +.xhs-send-code-btn { + min-width: 120px; + margin-left: 10px; +} + +.xhs-status-message { + min-height: 30px; + margin-bottom: 20px; + text-align: center; + font-size: 14px; +} + +.xhs-status-message.success { + color: #27ae60; +} + +.xhs-status-message.error { + color: #e74c3c; +} + +.xhs-status-message.info { + color: #3498db; +} + +.xhs-button-container { + display: flex; + justify-content: center; + gap: 15px; + margin-top: 20px; +} + +.xhs-login-btn { + min-width: 100px; } \ No newline at end of file diff --git a/todolist.md b/todolist.md index ea056ba..9a63bc3 100644 --- a/todolist.md +++ b/todolist.md @@ -42,8 +42,10 @@ +------------------------------------------------------------+ | [⬇ 当前页切图] [⇓ 全部页切图] | ← 底部操作栏 +------------------------------------------------------------+ +✅ 效果参考附图。 +✅ - 先对html分页,在预览中分页显示。 - 页面适配切图比例的设置。 @@ -52,12 +54,15 @@ - 点击"+"所有字体加一号,点击"-"所有字体减一号。 - 点击"当前页切图",把当前html页面转为png图片,图片保存路径和命名按此前设置。 - 点击"全部页切图",把所有html页面转为png图片,图片保存路径和命名按此前设置。 - +✅ ## 问题 1. "发布平台"首次选“小红书”时,预览页面没有加载当前文章。 +✅ 2. 顶部按钮适应窗口宽度,超出窗口,折行显示。 -3. 页预览不完整,改为 +✅ +3. 小红书模式,页预览不完整 + 4. 修改: - 公共部分独立出来,如“发布平台”,放在新建platform-choose.ts中,“发布平台”选择切换平台逻辑放在该模块中,便于以后其他平台扩展。 - 其他所有组件独立。node-preview.ts改为mp-preview.ts, 专门用于处理微信公众号模式下的页面和逻辑处理;preview-view.ts改为xhs-preview.ts,专门用于小红书模式下的页面和逻辑处理。 @@ -69,6 +74,7 @@ 平台选择后,依据选择模式,调用mp-preview.ts(微信公众号mp)或xhs-preview.ts(小红书,xhs)中的方法。 - mp-preview.ts中保留微信公众号模式(micro-public,mp)相关的处理逻辑。 - mp-preview.ts中去掉小红书处理逻辑(移到xhs-preview.ts中)。 +5. 把代码逻辑中的所有css移到styles.css中。✅