update at 2025-10-09 21:19:57
This commit is contained in:
@@ -9,7 +9,7 @@ import { UploadImageToWx } from './imagelib';
|
||||
import { NMPSettings } from './settings';
|
||||
import AssetsManager from './assets';
|
||||
import InlineCSS from './inline-css';
|
||||
import { wxGetToken, wxAddDraft, wxBatchGetMaterial, DraftArticle, DraftImageMediaId, DraftImages, wxAddDraftImages } from './weixin-api';
|
||||
import { wxGetToken, wxAddDraft, wxBatchGetMaterial, DraftArticle, DraftImageMediaId, DraftImages, wxAddDraftImages } from './wechat/weixin-api';
|
||||
import { MDRendererCallback } from './markdown/extension';
|
||||
import { MarkedParser } from './markdown/parser';
|
||||
import { LocalImageManager, LocalFile } from './markdown/local-file';
|
||||
@@ -855,4 +855,4 @@ export class ArticleRender implements MDRendererCallback {
|
||||
const key = category + ':' + id;
|
||||
this.cachedElements.set(key, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
*/
|
||||
|
||||
import { getBlobArrayBuffer } from "obsidian";
|
||||
import { wxUploadImage } from "./weixin-api";
|
||||
import { wxUploadImage } from "./wechat/weixin-api";
|
||||
import { NMPSettings } from "./settings";
|
||||
import { IsWasmReady, LoadWasm } from "./wasm/wasm";
|
||||
import AssetsManager from "./assets";
|
||||
import AssetsManager from "./assets";
|
||||
|
||||
declare function GoWebpToJPG(data: Uint8Array): Uint8Array; // wasm 返回 Uint8Array
|
||||
declare function GoWebpToPNG(data: Uint8Array): Uint8Array;
|
||||
@@ -51,4 +51,4 @@ export async function UploadImageToWx(data: Blob, filename: string, token: strin
|
||||
data = new Blob([bufferPart], { type: data.type });
|
||||
}
|
||||
return await wxUploadImage(data, filename, token, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Tokens, MarkedExtension} from "marked";
|
||||
import { Extension } from "./extension";
|
||||
import AssetsManager from "src/assets";
|
||||
import { wxWidget } from "src/weixin-api";
|
||||
import { wxWidget } from 'src/wechat/weixin-api';
|
||||
|
||||
const icon_note = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-pencil"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"></path><path d="m15 5 4 4"></path></svg>`
|
||||
const icon_abstract = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-clipboard-list"><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><path d="M12 11h4"></path><path d="M12 16h4"></path><path d="M8 11h.01"></path><path d="M8 16h.01"></path></svg>`
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MathRendererQueue } from "./math";
|
||||
import { Extension } from "./extension";
|
||||
import { UploadImageToWx } from "../imagelib";
|
||||
import AssetsManager from "src/assets";
|
||||
import { wxWidget } from "src/weixin-api";
|
||||
import { wxWidget } from 'src/wechat/weixin-api';
|
||||
|
||||
export class CardDataManager {
|
||||
private cardData: Map<string, string>;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Tokens, MarkedExtension } from "marked";
|
||||
import { Extension } from "./extension";
|
||||
import AssetsManager from "src/assets";
|
||||
import { ExpertSettings } from "src/expert-settings";
|
||||
import { wxWidget } from "src/weixin-api";
|
||||
import { wxWidget } from 'src/wechat/weixin-api';
|
||||
|
||||
export class HeadingRenderer extends Extension {
|
||||
index = [0, 0, 0, 0];
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Tokens, MarkedExtension } from "marked";
|
||||
import { Extension } from "./extension";
|
||||
import { NMPSettings } from "src/settings";
|
||||
import { uevent } from "src/utils";
|
||||
import { wxWidget } from "src/weixin-api";
|
||||
import { wxWidget } from 'src/wechat/weixin-api';
|
||||
|
||||
const widgetCache = new Map<string, string>();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { App, TextAreaComponent, PluginSettingTab, Setting, Notice, sanitizeHTMLToDom } from 'obsidian';
|
||||
import NoteToMpPlugin from './main';
|
||||
import { wxGetToken,wxEncrypt } from './weixin-api';
|
||||
import { wxGetToken, wxEncrypt } from './wechat/weixin-api';
|
||||
import { cleanMathCache } from './markdown/math';
|
||||
import { NMPSettings } from './settings';
|
||||
import { DocModal } from './doc-modal';
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* - 批量发布预设 / 图片处理 / 样式控制等选项
|
||||
*/
|
||||
|
||||
import { wxKeyInfo } from './weixin-api';
|
||||
import { wxKeyInfo } from './wechat/weixin-api';
|
||||
|
||||
export class NMPSettings {
|
||||
defaultStyle: string;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { App, sanitizeHTMLToDom, requestUrl, Platform } from "obsidian";
|
||||
import * as postcss from "./postcss/postcss";
|
||||
import * as postcss from "./postcss/postcss"; // 内置 PostCSS runtime,解析主题 CSS 用于内联样式
|
||||
|
||||
let PluginVersion = "0.0.0";
|
||||
let PlugPlatform = "obsidian";
|
||||
|
||||
@@ -17,6 +17,8 @@ import { sliceCurrentPage, sliceAllPages } from './slice';
|
||||
|
||||
const XHS_PREVIEW_DEFAULT_WIDTH = 540;
|
||||
const XHS_PREVIEW_WIDTH_OPTIONS = [1080, 720, 540, 360];
|
||||
|
||||
// 字号控制常量:一处修改即可同步 UI 显示、输入校验和渲染逻辑
|
||||
const XHS_FONT_SIZE_MIN = 18;
|
||||
const XHS_FONT_SIZE_MAX = 45;
|
||||
const XHS_FONT_SIZE_DEFAULT = 36;
|
||||
@@ -32,14 +34,11 @@ export class XiaohongshuPreview {
|
||||
currentFile: TFile | null = null;
|
||||
|
||||
// UI 元素
|
||||
topToolbar!: HTMLDivElement;
|
||||
templateSelect!: HTMLSelectElement;
|
||||
fontSizeInput!: HTMLInputElement;
|
||||
previewWidthSelect!: HTMLSelectElement;
|
||||
|
||||
pageContainer!: HTMLDivElement;
|
||||
bottomToolbar!: HTMLDivElement;
|
||||
pageNavigation!: HTMLDivElement;
|
||||
pageNumberInput!: HTMLInputElement;
|
||||
pageTotalLabel!: HTMLSpanElement;
|
||||
styleEl: HTMLStyleElement | null = null; // 主题样式注入节点
|
||||
@@ -78,49 +77,28 @@ export class XiaohongshuPreview {
|
||||
this.container.appendChild(this.styleEl);
|
||||
}
|
||||
|
||||
// 顶部工具栏
|
||||
this.buildTopToolbar();
|
||||
|
||||
// 页面容器
|
||||
this.pageContainer = this.container.createDiv({ cls: 'xhs-page-container' });
|
||||
|
||||
// 分页导航
|
||||
this.buildPageNavigation();
|
||||
|
||||
// 底部操作栏
|
||||
this.buildBottomToolbar();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建顶部工具栏
|
||||
*/
|
||||
private buildTopToolbar(): void {
|
||||
this.topToolbar = this.container.createDiv({ cls: 'xhs-top-toolbar' });
|
||||
|
||||
// 刷新按钮
|
||||
const refreshBtn = this.topToolbar.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' });
|
||||
refreshBtn.onclick = () => this.onRefresh();
|
||||
|
||||
// 发布按钮
|
||||
const publishBtn = this.topToolbar.createEl('button', { text: '📤 发布', cls: 'toolbar-button' });
|
||||
publishBtn.onclick = () => this.onPublish();
|
||||
|
||||
// 分隔线
|
||||
const separator2 = this.topToolbar.createDiv({ cls: 'toolbar-separator' });
|
||||
|
||||
// 模板选择
|
||||
const templateLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' });
|
||||
templateLabel.innerText = '模板';
|
||||
this.templateSelect = this.topToolbar.createEl('select', { cls: 'xhs-select' });
|
||||
const board = this.container.createDiv({ cls: 'xhs-board' });
|
||||
|
||||
const templateCard = this.createGridCard(board, 'xhs-area-template');
|
||||
const templateLabel = templateCard.createDiv({ cls: 'xhs-label', text: '模板' });
|
||||
this.templateSelect = templateCard.createEl('select', { cls: 'xhs-select' });
|
||||
['默认模板', '简约模板', '杂志模板'].forEach(name => {
|
||||
const option = this.templateSelect.createEl('option');
|
||||
option.value = name;
|
||||
option.text = name;
|
||||
});
|
||||
|
||||
const previewWidthLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' });
|
||||
previewWidthLabel.innerText = '预览宽度';
|
||||
this.previewWidthSelect = this.topToolbar.createEl('select', { cls: 'xhs-select' });
|
||||
|
||||
const refreshCard = this.createGridCard(board, 'xhs-area-refresh');
|
||||
const refreshBtn = refreshCard.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' });
|
||||
refreshBtn.onclick = () => this.onRefresh();
|
||||
|
||||
const publishCard = this.createGridCard(board, 'xhs-area-publish');
|
||||
const publishBtn = publishCard.createEl('button', { text: '📤 发布', cls: 'toolbar-button' });
|
||||
publishBtn.onclick = () => this.onPublish();
|
||||
|
||||
const previewCard = this.createGridCard(board, 'xhs-area-preview');
|
||||
const previewLabel = previewCard.createDiv({ cls: 'xhs-label', text: '预览宽度' });
|
||||
this.previewWidthSelect = previewCard.createEl('select', { cls: 'xhs-select' });
|
||||
const currentPreviewWidth = this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH;
|
||||
XHS_PREVIEW_WIDTH_OPTIONS.forEach(value => {
|
||||
const option = this.previewWidthSelect.createEl('option');
|
||||
@@ -141,12 +119,11 @@ export class XiaohongshuPreview {
|
||||
this.previewWidthSelect.value = String(this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH);
|
||||
}
|
||||
};
|
||||
|
||||
// 字号控制(可直接编辑)
|
||||
const fontSizeLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' });
|
||||
fontSizeLabel.innerText = '字号';
|
||||
const fontSizeGroup = this.topToolbar.createDiv({ cls: 'font-size-group' });
|
||||
|
||||
|
||||
const fontCard = this.createGridCard(board, 'xhs-area-font');
|
||||
fontCard.createDiv({ cls: 'xhs-label', text: '字号' });
|
||||
const fontSizeGroup = fontCard.createDiv({ cls: 'font-size-group' });
|
||||
|
||||
const decreaseBtn = fontSizeGroup.createEl('button', { text: '−', cls: 'font-size-btn' });
|
||||
decreaseBtn.onclick = () => this.changeFontSize(-1);
|
||||
|
||||
@@ -159,24 +136,19 @@ export class XiaohongshuPreview {
|
||||
value: String(XHS_FONT_SIZE_DEFAULT)
|
||||
}
|
||||
});
|
||||
this.fontSizeInput.style.width = '50px';
|
||||
this.fontSizeInput.style.textAlign = 'center';
|
||||
this.fontSizeInput.onchange = () => this.onFontSizeInputChanged();
|
||||
|
||||
const increaseBtn = fontSizeGroup.createEl('button', { text: '+', cls: 'font-size-btn' });
|
||||
increaseBtn.onclick = () => this.changeFontSize(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建分页导航
|
||||
*/
|
||||
private buildPageNavigation(): void {
|
||||
this.pageNavigation = this.container.createDiv({ cls: 'xhs-page-navigation' });
|
||||
|
||||
const prevBtn = this.pageNavigation.createEl('button', { text: '‹', cls: 'xhs-nav-btn' });
|
||||
|
||||
const contentWrapper = board.createDiv({ cls: 'xhs-area-content' });
|
||||
this.pageContainer = contentWrapper.createDiv({ cls: 'xhs-page-container' });
|
||||
|
||||
const paginationCard = this.createGridCard(board, 'xhs-area-pagination xhs-pagination');
|
||||
const prevBtn = paginationCard.createEl('button', { text: '‹', cls: 'xhs-nav-btn' });
|
||||
prevBtn.onclick = () => this.previousPage();
|
||||
|
||||
const indicator = this.pageNavigation.createDiv({ cls: 'xhs-page-indicator' });
|
||||
|
||||
const indicator = paginationCard.createDiv({ cls: 'xhs-page-indicator' });
|
||||
this.pageNumberInput = indicator.createEl('input', {
|
||||
cls: 'xhs-page-number-input',
|
||||
attr: { type: 'text', value: '1', inputmode: 'numeric', 'aria-label': '当前页码' }
|
||||
@@ -197,22 +169,20 @@ export class XiaohongshuPreview {
|
||||
this.pageNumberInput.onblur = () => this.handlePageNumberInput();
|
||||
|
||||
this.pageTotalLabel = indicator.createEl('span', { cls: 'xhs-page-number-total', text: '/1' });
|
||||
|
||||
const nextBtn = this.pageNavigation.createEl('button', { text: '›', cls: 'xhs-nav-btn' });
|
||||
|
||||
const nextBtn = paginationCard.createEl('button', { text: '›', cls: 'xhs-nav-btn' });
|
||||
nextBtn.onclick = () => this.nextPage();
|
||||
|
||||
const sliceCard = this.createGridCard(board, 'xhs-area-slice');
|
||||
const sliceCurrentBtn = sliceCard.createEl('button', { text: '⬇ 当前页切图', cls: 'xhs-slice-btn' });
|
||||
sliceCurrentBtn.onclick = () => this.sliceCurrentPage();
|
||||
|
||||
const sliceAllBtn = sliceCard.createEl('button', { text: '⇓ 全部页切图', cls: 'xhs-slice-btn secondary' });
|
||||
sliceAllBtn.onclick = () => this.sliceAllPages();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建底部操作栏
|
||||
*/
|
||||
private buildBottomToolbar(): void {
|
||||
this.bottomToolbar = this.container.createDiv({ cls: 'xhs-bottom-toolbar' });
|
||||
|
||||
const currentPageBtn = this.bottomToolbar.createEl('button', { text: '⬇ 当前页切图', cls: 'xhs-slice-btn' });
|
||||
currentPageBtn.onclick = () => this.sliceCurrentPage();
|
||||
|
||||
const allPagesBtn = this.bottomToolbar.createEl('button', { text: '⇓ 全部页切图', cls: 'xhs-slice-btn secondary' });
|
||||
allPagesBtn.onclick = () => this.sliceAllPages();
|
||||
private createGridCard(parent: HTMLElement, areaClass: string): HTMLDivElement {
|
||||
return parent.createDiv({ cls: `xhs-card ${areaClass}` });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,6 +306,7 @@ export class XiaohongshuPreview {
|
||||
pageElement.style.width = `${actualWidth}px`;
|
||||
pageElement.style.height = `${actualHeight}px`;
|
||||
pageElement.style.transform = `scale(${scale})`;
|
||||
pageElement.style.transformOrigin = 'top left';
|
||||
pageElement.style.position = 'absolute';
|
||||
pageElement.style.top = '0';
|
||||
pageElement.style.left = '0';
|
||||
@@ -521,13 +492,10 @@ export class XiaohongshuPreview {
|
||||
* 清理资源
|
||||
*/
|
||||
destroy(): void {
|
||||
this.topToolbar = null as any;
|
||||
this.templateSelect = null as any;
|
||||
this.previewWidthSelect = null as any;
|
||||
this.fontSizeInput = null as any;
|
||||
this.pageContainer = null as any;
|
||||
this.bottomToolbar = null as any;
|
||||
this.pageNavigation = null as any;
|
||||
this.pageNumberInput = null as any;
|
||||
this.pageTotalLabel = null as any;
|
||||
this.pages = [];
|
||||
|
||||
Reference in New Issue
Block a user