update at 2025-10-09 12:39:24

This commit is contained in:
douboer
2025-10-09 12:39:24 +08:00
parent a891153be0
commit 6f51916b50
44 changed files with 332 additions and 226 deletions

View File

@@ -15,6 +15,9 @@ import AssetsManager from '../assets';
import { paginateArticle, renderPage, PageInfo } from './paginator';
import { sliceCurrentPage, sliceAllPages } from './slice';
const XHS_PREVIEW_DEFAULT_WIDTH = 540;
const XHS_PREVIEW_WIDTH_OPTIONS = [1080, 720, 540, 360];
/**
* 小红书预览视图类
*/
@@ -29,6 +32,7 @@ export class XiaohongshuPreview {
topToolbar!: HTMLDivElement;
templateSelect!: HTMLSelectElement;
fontSizeInput!: HTMLInputElement;
previewWidthSelect!: HTMLSelectElement;
pageContainer!: HTMLDivElement;
bottomToolbar!: HTMLDivElement;
@@ -110,6 +114,30 @@ export class XiaohongshuPreview {
option.text = name;
});
const previewWidthLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' });
previewWidthLabel.innerText = '预览宽度';
this.previewWidthSelect = this.topToolbar.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');
option.value = String(value);
option.text = `${value}px`;
});
if (!XHS_PREVIEW_WIDTH_OPTIONS.includes(currentPreviewWidth)) {
const customOption = this.previewWidthSelect.createEl('option');
customOption.value = String(currentPreviewWidth);
customOption.text = `${currentPreviewWidth}px`;
}
this.previewWidthSelect.value = String(currentPreviewWidth);
this.previewWidthSelect.onchange = async () => {
const value = parseInt(this.previewWidthSelect.value, 10);
if (Number.isFinite(value) && value > 0) {
await this.onPreviewWidthChanged(value);
} else {
this.previewWidthSelect.value = String(this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH);
}
};
// 字号控制(可直接编辑)
const fontSizeLabel = this.topToolbar.createDiv({ cls: 'toolbar-label' });
fontSizeLabel.innerText = '字号';
@@ -205,6 +233,7 @@ export class XiaohongshuPreview {
if (this.currentThemeClass) classes.push('note-to-mp');
const pageElement = wrapper.createDiv({ cls: classes.join(' ') });
renderPage(pageElement, page.content, this.settings);
this.applyPreviewSizing(wrapper, pageElement);
// 应用字体设置
this.applyFontSettings(pageElement);
@@ -213,6 +242,49 @@ export class XiaohongshuPreview {
this.pageNumberDisplay.innerText = `${this.currentPageIndex + 1}/${this.pages.length}`;
}
/**
* 根据设置的宽度和横竖比应用预览尺寸与缩放
*/
private applyPreviewSizing(wrapper: HTMLElement, pageElement: HTMLElement): void {
const configuredWidth = this.settings.sliceImageWidth || 1080;
const actualWidth = Math.max(1, configuredWidth);
const ratio = this.parseAspectRatio(this.settings.sliceImageAspectRatio);
const actualHeight = Math.round((actualWidth * ratio.height) / ratio.width);
const previewWidthSetting = this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH;
const previewWidth = Math.max(1, previewWidthSetting);
const scale = Math.max(previewWidth / actualWidth, 0.01);
const previewHeight = Math.max(1, Math.round(actualHeight * scale));
wrapper.style.width = `${previewWidth}px`;
wrapper.style.height = `${previewHeight}px`;
pageElement.style.width = `${actualWidth}px`;
pageElement.style.height = `${actualHeight}px`;
pageElement.style.transform = `scale(${scale})`;
pageElement.style.position = 'absolute';
pageElement.style.top = '0';
pageElement.style.left = '0';
}
private async onPreviewWidthChanged(newWidth: number): Promise<void> {
if (newWidth <= 0) return;
if (this.settings.xhsPreviewWidth === newWidth) return;
this.settings.xhsPreviewWidth = newWidth;
await this.persistSettings();
this.renderCurrentPage();
}
/**
* 解析横竖比例字符串
*/
private parseAspectRatio(ratio: string | undefined): { width: number; height: number } {
const parts = (ratio ?? '').split(':').map(part => parseFloat(part.trim()));
if (parts.length === 2 && isFinite(parts[0]) && isFinite(parts[1]) && parts[0] > 0 && parts[1] > 0) {
return { width: parts[0], height: parts[1] };
}
return { width: 3, height: 4 };
}
/**
* 应用字体设置(仅字号,字体从主题读取)
*/
@@ -341,6 +413,17 @@ export class XiaohongshuPreview {
}
}
private async persistSettings(): Promise<void> {
try {
const plugin = (this.app as any)?.plugins?.getPlugin?.('note-to-mp');
if (plugin?.saveSettings) {
await plugin.saveSettings();
}
} catch (error) {
console.warn('[XiaohongshuPreview] 保存设置失败', error);
}
}
/**
* 显示小红书预览视图
*/
@@ -365,6 +448,7 @@ 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;