232 lines
6.7 KiB
TypeScript
232 lines
6.7 KiB
TypeScript
/**
|
||
* 文件:platform-chooser.ts
|
||
* 作用:平台选择器组件,负责渲染平台选择 UI 并处理平台切换事件
|
||
*
|
||
* 这是一个公共组件,独立于具体平台实现,便于未来扩展新平台
|
||
*/
|
||
|
||
import { Platform as ObsidianPlatform } from 'obsidian';
|
||
|
||
export type PlatformType = 'wechat' | 'xiaohongshu';
|
||
|
||
/**
|
||
* 平台选择器配置
|
||
*/
|
||
export interface PlatformChooserOptions {
|
||
/** 默认选中的平台 */
|
||
defaultPlatform?: PlatformType;
|
||
/** 平台切换回调 */
|
||
onPlatformChange?: (platform: PlatformType) => Promise<void>;
|
||
}
|
||
|
||
export interface PlatformActionLabels {
|
||
refresh: string;
|
||
publish: string;
|
||
}
|
||
|
||
export interface PlatformChooserActions {
|
||
onRefresh?: () => void | Promise<void>;
|
||
onPublish?: () => void | Promise<void>;
|
||
getLabels?: (platform: PlatformType) => PlatformActionLabels;
|
||
}
|
||
|
||
/**
|
||
* 平台信息接口
|
||
*/
|
||
interface PlatformInfo {
|
||
value: PlatformType;
|
||
label: string;
|
||
icon?: string;
|
||
}
|
||
|
||
/**
|
||
* 支持的平台列表
|
||
*/
|
||
const SUPPORTED_PLATFORMS: PlatformInfo[] = [
|
||
{ value: 'wechat', label: '微信公众号', icon: '📱' },
|
||
{ value: 'xiaohongshu', label: '小红书', icon: '📔' }
|
||
];
|
||
|
||
/**
|
||
* 平台选择器类
|
||
*
|
||
* 职责:
|
||
* 1. 渲染平台选择 UI
|
||
* 2. 处理用户的平台切换操作
|
||
* 3. 触发平台切换回调
|
||
* 4. 维护当前选中的平台状态
|
||
*/
|
||
export class PlatformChooser {
|
||
private container: HTMLElement;
|
||
private selectElement: HTMLSelectElement | null = null;
|
||
private refreshButton: HTMLButtonElement | null = null;
|
||
private publishButton: HTMLButtonElement | null = null;
|
||
private currentPlatform: PlatformType;
|
||
private onChange?: (platform: PlatformType) => void;
|
||
private actions: PlatformChooserActions | null = null;
|
||
|
||
constructor(container: HTMLElement, options: PlatformChooserOptions = {}) {
|
||
this.container = container;
|
||
this.currentPlatform = options.defaultPlatform || 'xiaohongshu';
|
||
if (options.onPlatformChange) {
|
||
this.onChange = (platform) => {
|
||
options.onPlatformChange!(platform);
|
||
};
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置平台切换回调
|
||
*/
|
||
setOnChange(callback: (platform: PlatformType) => void): void {
|
||
this.onChange = callback;
|
||
}
|
||
|
||
/**
|
||
* 渲染平台选择器 UI
|
||
*/
|
||
render(): void {
|
||
// 将容器作为单层 Grid 行使用
|
||
this.container.addClass('platform-selector-line');
|
||
this.container.addClass('platform-chooser-grid');
|
||
|
||
// 创建标签
|
||
const platformLabel = this.container.createDiv({ cls: 'style-label' });
|
||
platformLabel.innerText = '发布平台';
|
||
|
||
// 创建选择器
|
||
const platformSelect = this.container.createEl('select', { cls: 'platform-select' });
|
||
this.selectElement = platformSelect;
|
||
|
||
// 添加平台选项
|
||
SUPPORTED_PLATFORMS.forEach(platform => {
|
||
const option = platformSelect.createEl('option');
|
||
option.value = platform.value;
|
||
option.text = platform.icon ? `${platform.icon} ${platform.label}` : platform.label;
|
||
|
||
// 设置默认选中
|
||
if (platform.value === this.currentPlatform) {
|
||
option.selected = true;
|
||
}
|
||
});
|
||
|
||
// 绑定切换事件
|
||
platformSelect.onchange = () => {
|
||
const newPlatform = platformSelect.value as PlatformType;
|
||
this.switchPlatformInternal(newPlatform);
|
||
};
|
||
|
||
// 刷新按钮
|
||
this.refreshButton = this.container.createEl('button', { cls: 'toolbar-button purple-gradient' });
|
||
this.refreshButton.onclick = () => this.handleRefreshClick();
|
||
|
||
// 发布按钮
|
||
this.publishButton = this.container.createEl('button', { cls: 'toolbar-button' });
|
||
this.publishButton.onclick = () => this.handlePublishClick();
|
||
|
||
this.updateActionLabels();
|
||
}
|
||
|
||
/**
|
||
* 切换平台(内部方法)
|
||
*/
|
||
private switchPlatformInternal(platform: PlatformType): void {
|
||
if (platform === this.currentPlatform) {
|
||
return; // 相同平台,不需要切换
|
||
}
|
||
|
||
console.log(`[PlatformChooser] 切换平台: ${this.currentPlatform} -> ${platform}`);
|
||
|
||
this.currentPlatform = platform;
|
||
|
||
// 触发平台切换回调
|
||
if (this.onChange) {
|
||
try {
|
||
this.onChange(platform);
|
||
} catch (error) {
|
||
console.error('[PlatformChooser] 平台切换失败:', error);
|
||
}
|
||
}
|
||
|
||
this.updateActionLabels();
|
||
}
|
||
|
||
/**
|
||
* 切换平台(公共方法,供 PreviewManager 调用)
|
||
*/
|
||
switchPlatform(platform: PlatformType): void {
|
||
this.currentPlatform = platform;
|
||
if (this.selectElement) {
|
||
this.selectElement.value = platform;
|
||
}
|
||
this.updateActionLabels();
|
||
}
|
||
|
||
/**
|
||
* 获取当前选中的平台
|
||
*/
|
||
getCurrentPlatform(): PlatformType {
|
||
return this.currentPlatform;
|
||
}
|
||
|
||
/**
|
||
* 程序化设置平台(不触发回调)
|
||
*/
|
||
setPlatform(platform: PlatformType): void {
|
||
this.currentPlatform = platform;
|
||
if (this.selectElement) {
|
||
this.selectElement.value = platform;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清理资源
|
||
*/
|
||
destroy(): void {
|
||
if (this.selectElement) {
|
||
this.selectElement.onchange = null;
|
||
this.selectElement = null;
|
||
}
|
||
if (this.refreshButton) {
|
||
this.refreshButton.onclick = null;
|
||
this.refreshButton = null;
|
||
}
|
||
if (this.publishButton) {
|
||
this.publishButton.onclick = null;
|
||
this.publishButton = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 设置通用操作按钮
|
||
*/
|
||
setActions(actions: PlatformChooserActions): void {
|
||
this.actions = actions;
|
||
this.updateActionLabels();
|
||
}
|
||
|
||
private handleRefreshClick(): void {
|
||
if (!this.actions?.onRefresh) return;
|
||
Promise.resolve(this.actions.onRefresh()).catch((error) => {
|
||
console.error('[PlatformChooser] 刷新操作失败:', error);
|
||
});
|
||
}
|
||
|
||
private handlePublishClick(): void {
|
||
if (!this.actions?.onPublish) return;
|
||
Promise.resolve(this.actions.onPublish()).catch((error) => {
|
||
console.error('[PlatformChooser] 发布操作失败:', error);
|
||
});
|
||
}
|
||
|
||
private updateActionLabels(): void {
|
||
if (!this.refreshButton || !this.publishButton) return;
|
||
const labels = this.actions?.getLabels?.(this.currentPlatform) ?? {
|
||
refresh: '🔄 刷新',
|
||
publish: '📤 发布',
|
||
};
|
||
this.refreshButton.innerText = labels.refresh;
|
||
this.publishButton.innerText = labels.publish;
|
||
}
|
||
}
|