update at 2025-10-10 17:00:09
This commit is contained in:
23
README.md
23
README.md
@@ -95,8 +95,6 @@
|
|||||||
|
|
||||||
检查样式无误后,点击**复制**按钮,然后到公众号粘贴即可。
|
检查样式无误后,点击**复制**按钮,然后到公众号粘贴即可。
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
**★ 公众号**
|
**★ 公众号**
|
||||||
插件支持多公众号,在下拉菜单中进行不同公众号的切换。该功能需要订阅才能使用。
|
插件支持多公众号,在下拉菜单中进行不同公众号的切换。该功能需要订阅才能使用。
|
||||||
|
|
||||||
@@ -158,6 +156,15 @@ c=+-sqrt(a^2+b^2)
|
|||||||
数学公式的渲染效果可以看这篇文章:[公众号文章里的数学公式排版秘籍](https://mp.weixin.qq.com/s/-kpT2U1gT_5W3TsDCAVgsw)👈️
|
数学公式的渲染效果可以看这篇文章:[公众号文章里的数学公式排版秘籍](https://mp.weixin.qq.com/s/-kpT2U1gT_5W3TsDCAVgsw)👈️
|
||||||
### 自定义CSS使用指南
|
### 自定义CSS使用指南
|
||||||
|
|
||||||
|
## 开发与构建
|
||||||
|
|
||||||
|
本仓库的构建脚本分为“未混淆”和“启用混淆”两个版本:
|
||||||
|
- `npm run build`:生成未混淆的 `main.js`,便于调试。
|
||||||
|
- `npm run build:obf`:在生产模式下启用 `javascript-obfuscator`,生成混淆后的 `main.js`。
|
||||||
|
- `./build.sh`:执行默认(未混淆)构建并同步到本地 Obsidian 插件目录。
|
||||||
|
- `./build.sh obf`:执行混淆构建后再进行同步。
|
||||||
|
|
||||||
|
如需自定义混淆行为,可在执行命令时设置环境变量(例如 `OBFUSCATE=1 npm run build:bundle`),详细参数见 `esbuild.config.mjs`。
|
||||||
新建一篇笔记,例如**自定义样式**,直接将如下内容粘贴进笔记:
|
新建一篇笔记,例如**自定义样式**,直接将如下内容粘贴进笔记:
|
||||||
|
|
||||||
````CSS
|
````CSS
|
||||||
@@ -356,7 +363,7 @@ NoteToMP插件支持该语法。
|
|||||||
- 你想要把所有标记为 `篆刻` 的文章筛选出来,批量上传到公众号草稿箱并逐条完善后发布。
|
- 你想要把所有标记为 `篆刻` 的文章筛选出来,批量上传到公众号草稿箱并逐条完善后发布。
|
||||||
- 按文件夹 `content/post` 筛选并批量发布该文件夹下的近期文章。
|
- 按文件夹 `content/post` 筛选并批量发布该文件夹下的近期文章。
|
||||||
|
|
||||||
### 详细使用指南(一步步)
|
### 使用指南
|
||||||
|
|
||||||
1. 打开模态
|
1. 打开模态
|
||||||
- 命令面板(Ctrl/Cmd+P)→ 输入“批量发布文章”,回车打开模态窗口。
|
- 命令面板(Ctrl/Cmd+P)→ 输入“批量发布文章”,回车打开模态窗口。
|
||||||
@@ -537,13 +544,6 @@ https://www.bilibili.com/video/BV15XWVeEEJa/
|
|||||||
---
|
---
|
||||||
```
|
```
|
||||||
|
|
||||||
视频教程:https://www.bilibili.com/video/BV15XWVeEEmA/
|
|
||||||
|
|
||||||
## 4、反馈交流群
|
|
||||||
|
|
||||||
**微信群:**
|
|
||||||
加微信:**Genius35Plus**,备注:**NoteToMP**
|
|
||||||
|
|
||||||
## 附:批量发布 - 快速交互速览与截图占位
|
## 附:批量发布 - 快速交互速览与截图占位
|
||||||
|
|
||||||
如果你想把功能教学放到 README 中,这里是推荐的简短速览(已在模态中实现):
|
如果你想把功能教学放到 README 中,这里是推荐的简短速览(已在模态中实现):
|
||||||
@@ -559,3 +559,6 @@ https://www.bilibili.com/video/BV15XWVeEEJa/
|
|||||||
2. 在 README 中替换占位为图片预览并附带关键交互标注说明。
|
2. 在 README 中替换占位为图片预览并附带关键交互标注说明。
|
||||||
|
|
||||||
如果你更愿意手动截屏,我也可以把一个标注模板(SVG 或说明)发给你,方便手动粘贴到 `images/` 目录。
|
如果你更愿意手动截屏,我也可以把一个标注模板(SVG 或说明)发给你,方便手动粘贴到 `images/` 目录。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
13
build.sh
13
build.sh
@@ -2,8 +2,17 @@
|
|||||||
set -e # 出错立即退出
|
set -e # 出错立即退出
|
||||||
|
|
||||||
# 1. 构建
|
# 1. 构建
|
||||||
echo "🏗️ 开始构建..."
|
MODE="$1"
|
||||||
if npm run build; then
|
BUILD_CMD=(npm run build)
|
||||||
|
|
||||||
|
if [[ "$MODE" == "obf" ]]; then
|
||||||
|
BUILD_CMD=(npm run build:obf)
|
||||||
|
echo "🏗️ 开始构建(启用混淆)..."
|
||||||
|
else
|
||||||
|
echo "🏗️ 开始构建(不启用混淆)..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if "${BUILD_CMD[@]}"; then
|
||||||
echo "✅ 构建成功"
|
echo "✅ 构建成功"
|
||||||
echo
|
echo
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -75,14 +75,17 @@ git checkout -b release/v1.3.0
|
|||||||
|
|
||||||
### 4. 构建项目
|
### 4. 构建项目
|
||||||
|
|
||||||
构建项目生成生产版本文件:
|
构建项目生成发布所需的产物:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 执行项目构建
|
# 执行未混淆构建(推荐用于验证与调试)
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
# 检查构建输出
|
# 检查构建输出
|
||||||
ls -la main.js manifest.json
|
ls -la main.js manifest.json
|
||||||
|
|
||||||
|
# 如需生成混淆后的发布包,可执行:
|
||||||
|
npm run build:obf
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5. 创建归档目录
|
### 5. 创建归档目录
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import esbuild from "esbuild";
|
import esbuild from "esbuild";
|
||||||
import process from "process";
|
import process from "process";
|
||||||
import builtins from "builtin-modules";
|
import builtins from "builtin-modules";
|
||||||
|
import javascriptObfuscatorPlugin from "./tools/esbuild-obfuscator-plugin.mjs";
|
||||||
|
|
||||||
const banner =
|
const banner =
|
||||||
`/*
|
`/*
|
||||||
@@ -10,6 +11,25 @@ if you want to view the source, please visit the github repository of this plugi
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const prod = (process.argv[2] === "production");
|
const prod = (process.argv[2] === "production");
|
||||||
|
const obfuscate = prod && process.env.OBFUSCATE === "1";
|
||||||
|
|
||||||
|
const plugins = [];
|
||||||
|
|
||||||
|
if (obfuscate) {
|
||||||
|
plugins.push(javascriptObfuscatorPlugin({
|
||||||
|
compact: false,
|
||||||
|
controlFlowFlattening: false,
|
||||||
|
deadCodeInjection: false,
|
||||||
|
debugProtection: false,
|
||||||
|
disableConsoleOutput: true,
|
||||||
|
identifierNamesGenerator: "hexadecimal",
|
||||||
|
log: false,
|
||||||
|
renameGlobals: false,
|
||||||
|
simplify: true,
|
||||||
|
splitStrings: false,
|
||||||
|
transformObjectKeys: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
const context = await esbuild.context({
|
const context = await esbuild.context({
|
||||||
banner: {
|
banner: {
|
||||||
@@ -38,6 +58,7 @@ const context = await esbuild.context({
|
|||||||
sourcemap: prod ? false : "inline",
|
sourcemap: prod ? false : "inline",
|
||||||
treeShaking: true,
|
treeShaking: true,
|
||||||
outfile: "main.js",
|
outfile: "main.js",
|
||||||
|
plugins,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (prod) {
|
if (prod) {
|
||||||
|
|||||||
1020
package-lock.json
generated
1020
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,9 @@
|
|||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node esbuild.config.mjs",
|
"dev": "node esbuild.config.mjs",
|
||||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
"build": "npm run build:bundle --",
|
||||||
|
"build:obf": "OBFUSCATE=1 npm run build:bundle --",
|
||||||
|
"build:bundle": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||||
"download": "node tools/download.mjs",
|
"download": "node tools/download.mjs",
|
||||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||||
},
|
},
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
"@typescript-eslint/parser": "5.29.0",
|
"@typescript-eslint/parser": "5.29.0",
|
||||||
"builtin-modules": "3.3.0",
|
"builtin-modules": "3.3.0",
|
||||||
"esbuild": "0.17.3",
|
"esbuild": "0.17.3",
|
||||||
|
"javascript-obfuscator": "^4.1.1",
|
||||||
"obsidian": "latest",
|
"obsidian": "latest",
|
||||||
"tslib": "2.4.0",
|
"tslib": "2.4.0",
|
||||||
"typescript": "4.7.4"
|
"typescript": "4.7.4"
|
||||||
|
|||||||
@@ -19,6 +19,17 @@ export interface PlatformChooserOptions {
|
|||||||
onPlatformChange?: (platform: PlatformType) => Promise<void>;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台信息接口
|
* 平台信息接口
|
||||||
*/
|
*/
|
||||||
@@ -48,8 +59,11 @@ const SUPPORTED_PLATFORMS: PlatformInfo[] = [
|
|||||||
export class PlatformChooser {
|
export class PlatformChooser {
|
||||||
private container: HTMLElement;
|
private container: HTMLElement;
|
||||||
private selectElement: HTMLSelectElement | null = null;
|
private selectElement: HTMLSelectElement | null = null;
|
||||||
|
private refreshButton: HTMLButtonElement | null = null;
|
||||||
|
private publishButton: HTMLButtonElement | null = null;
|
||||||
private currentPlatform: PlatformType;
|
private currentPlatform: PlatformType;
|
||||||
private onChange?: (platform: PlatformType) => void;
|
private onChange?: (platform: PlatformType) => void;
|
||||||
|
private actions: PlatformChooserActions | null = null;
|
||||||
|
|
||||||
constructor(container: HTMLElement, options: PlatformChooserOptions = {}) {
|
constructor(container: HTMLElement, options: PlatformChooserOptions = {}) {
|
||||||
this.container = container;
|
this.container = container;
|
||||||
@@ -101,6 +115,16 @@ export class PlatformChooser {
|
|||||||
const newPlatform = platformSelect.value as PlatformType;
|
const newPlatform = platformSelect.value as PlatformType;
|
||||||
this.switchPlatformInternal(newPlatform);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,6 +147,8 @@ export class PlatformChooser {
|
|||||||
console.error('[PlatformChooser] 平台切换失败:', error);
|
console.error('[PlatformChooser] 平台切换失败:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateActionLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,6 +159,7 @@ export class PlatformChooser {
|
|||||||
if (this.selectElement) {
|
if (this.selectElement) {
|
||||||
this.selectElement.value = platform;
|
this.selectElement.value = platform;
|
||||||
}
|
}
|
||||||
|
this.updateActionLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,5 +187,45 @@ export class PlatformChooser {
|
|||||||
this.selectElement.onchange = null;
|
this.selectElement.onchange = null;
|
||||||
this.selectElement = 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,18 @@ export class PreviewManager {
|
|||||||
|
|
||||||
// 构建 UI
|
// 构建 UI
|
||||||
this.platformChooser.render();
|
this.platformChooser.render();
|
||||||
|
|
||||||
|
// 共享操作按钮
|
||||||
|
this.platformChooser.setActions({
|
||||||
|
onRefresh: () => this.refresh(),
|
||||||
|
onPublish: () => this.publishCurrentPlatform(),
|
||||||
|
getLabels: (platform) => {
|
||||||
|
if (platform === 'wechat') {
|
||||||
|
return { refresh: '🔄 刷新', publish: '📝 发布' };
|
||||||
|
}
|
||||||
|
return { refresh: '🔄 刷新', publish: '📤 发布' };
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -125,6 +137,22 @@ export class PreviewManager {
|
|||||||
this.wechatPreview.build();
|
this.wechatPreview.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async publishCurrentPlatform(): Promise<void> {
|
||||||
|
if (this.currentPlatform === 'wechat') {
|
||||||
|
if (!this.wechatPreview) {
|
||||||
|
new Notice('微信预览未初始化');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.wechatPreview.publish();
|
||||||
|
} else if (this.currentPlatform === 'xiaohongshu') {
|
||||||
|
if (!this.xhsPreview) {
|
||||||
|
new Notice('小红书预览未初始化');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.xhsPreview.publish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建小红书预览组件
|
* 创建小红书预览组件
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* 作用:通用工具函数集合(事件、版本、字符串处理等)。
|
* 作用:通用工具函数集合(事件、版本、字符串处理等)。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { App, sanitizeHTMLToDom, requestUrl, Platform } from "obsidian";
|
import { App, sanitizeHTMLToDom, Platform } from "obsidian";
|
||||||
import * as postcss from "./postcss/postcss"; // 内置 PostCSS runtime,解析主题 CSS 用于内联样式
|
import * as postcss from "./postcss/postcss"; // 内置 PostCSS runtime,解析主题 CSS 用于内联样式
|
||||||
|
|
||||||
let PluginVersion = "0.0.0";
|
let PluginVersion = "0.0.0";
|
||||||
@@ -185,10 +185,7 @@ export function applyCSS(html: string, css: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function uevent(name: string) {
|
export function uevent(name: string) {
|
||||||
const url = `https://u.sunboshi.tech/event?name=${name}&platform=${PlugPlatform}&v=${PluginVersion}`;
|
console.debug(`[uevent] ${name} @${PlugPlatform} v${PluginVersion}`);
|
||||||
requestUrl(url).then().catch(error => {
|
|
||||||
console.error("Failed to send event: " + url, error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -134,19 +134,13 @@ export class WechatPreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 操作按钮(直接平铺在 Grid 中)
|
// 操作按钮(直接平铺在 Grid 中)
|
||||||
const refreshBtn = parent.createEl('button', { text: '🔄 刷新', cls: 'toolbar-button purple-gradient' });
|
|
||||||
refreshBtn.onclick = async () => { if (this.onRefreshCallback) await this.onRefreshCallback(); };
|
|
||||||
|
|
||||||
const postBtn = parent.createEl('button', { text: '📝 发布', cls: 'toolbar-button' });
|
|
||||||
postBtn.onclick = async () => await this.postArticle();
|
|
||||||
|
|
||||||
if (Platform.isDesktop && this.settings.isAuthKeyVaild()) {
|
if (Platform.isDesktop && this.settings.isAuthKeyVaild()) {
|
||||||
const htmlBtn = parent.createEl('button', { text: '💾 导出HTML', cls: 'toolbar-button' });
|
const htmlBtn = parent.createEl('button', { text: '💾 导出HTML', cls: 'toolbar-button' });
|
||||||
htmlBtn.onclick = async () => await this.exportHTML();
|
htmlBtn.onclick = async () => await this.exportHTML();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 封面选择
|
// 封面选择
|
||||||
this.buildCoverSelector(parent);
|
//this.buildCoverSelector(parent);
|
||||||
|
|
||||||
// 样式选择(如果启用)
|
// 样式选择(如果启用)
|
||||||
if (this.settings.showStyleUI) {
|
if (this.settings.showStyleUI) {
|
||||||
@@ -387,6 +381,16 @@ export class WechatPreview {
|
|||||||
/** 对外:发布草稿(供外层菜单调用) */
|
/** 对外:发布草稿(供外层菜单调用) */
|
||||||
async postDraft() { await this.postArticle(); }
|
async postDraft() { await this.postArticle(); }
|
||||||
|
|
||||||
|
async publish(): Promise<void> {
|
||||||
|
await this.postDraft();
|
||||||
|
}
|
||||||
|
|
||||||
|
async refresh(): Promise<void> {
|
||||||
|
if (this.onRefreshCallback) {
|
||||||
|
await this.onRefreshCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 由上层在切换/渲染时注入当前文件 */
|
/** 由上层在切换/渲染时注入当前文件 */
|
||||||
setFile(file: TFile | null) { this.currentFile = file; }
|
setFile(file: TFile | null) { this.currentFile = file; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,16 +88,8 @@ export class XiaohongshuPreview {
|
|||||||
option.text = name;
|
option.text = name;
|
||||||
});
|
});
|
||||||
|
|
||||||
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 previewCard = this.createGridCard(board, 'xhs-area-preview');
|
||||||
const previewLabel = previewCard.createDiv({ cls: 'xhs-label', text: '预览宽度' });
|
const previewLabel = previewCard.createDiv({ cls: 'xhs-label', text: '宽度' });
|
||||||
this.previewWidthSelect = previewCard.createEl('select', { cls: 'xhs-select' });
|
this.previewWidthSelect = previewCard.createEl('select', { cls: 'xhs-select' });
|
||||||
const currentPreviewWidth = this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH;
|
const currentPreviewWidth = this.settings.xhsPreviewWidth || XHS_PREVIEW_DEFAULT_WIDTH;
|
||||||
XHS_PREVIEW_WIDTH_OPTIONS.forEach(value => {
|
XHS_PREVIEW_WIDTH_OPTIONS.forEach(value => {
|
||||||
@@ -121,9 +113,8 @@ export class XiaohongshuPreview {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fontCard = this.createGridCard(board, 'xhs-area-font');
|
const fontCard = this.createGridCard(board, 'xhs-area-font');
|
||||||
fontCard.createDiv({ cls: 'xhs-label', text: '字号' });
|
//fontCard.createDiv({ cls: 'xhs-label', text: '字号' });
|
||||||
const fontSizeGroup = fontCard.createDiv({ cls: 'font-size-group' });
|
const fontSizeGroup = fontCard.createDiv({ cls: 'font-size-group' });
|
||||||
|
|
||||||
const decreaseBtn = fontSizeGroup.createEl('button', { text: '−', cls: 'font-size-btn' });
|
const decreaseBtn = fontSizeGroup.createEl('button', { text: '−', cls: 'font-size-btn' });
|
||||||
decreaseBtn.onclick = () => this.changeFontSize(-1);
|
decreaseBtn.onclick = () => this.changeFontSize(-1);
|
||||||
|
|
||||||
@@ -174,10 +165,10 @@ export class XiaohongshuPreview {
|
|||||||
nextBtn.onclick = () => this.nextPage();
|
nextBtn.onclick = () => this.nextPage();
|
||||||
|
|
||||||
const sliceCard = this.createGridCard(board, 'xhs-area-slice');
|
const sliceCard = this.createGridCard(board, 'xhs-area-slice');
|
||||||
const sliceCurrentBtn = sliceCard.createEl('button', { text: '⬇ 当前页切图', cls: 'xhs-slice-btn' });
|
const sliceCurrentBtn = sliceCard.createEl('button', { text: '当前页切图', cls: 'xhs-slice-btn' });
|
||||||
sliceCurrentBtn.onclick = () => this.sliceCurrentPage();
|
sliceCurrentBtn.onclick = () => this.sliceCurrentPage();
|
||||||
|
|
||||||
const sliceAllBtn = sliceCard.createEl('button', { text: '⇓ 全部页切图', cls: 'xhs-slice-btn secondary' });
|
const sliceAllBtn = sliceCard.createEl('button', { text: '全部页切图', cls: 'xhs-slice-btn secondary' });
|
||||||
sliceAllBtn.onclick = () => this.sliceAllPages();
|
sliceAllBtn.onclick = () => this.sliceAllPages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,6 +415,14 @@ export class XiaohongshuPreview {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async refresh(): Promise<void> {
|
||||||
|
await this.onRefresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
async publish(): Promise<void> {
|
||||||
|
await this.onPublish();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全部页切图
|
* 全部页切图
|
||||||
*/
|
*/
|
||||||
|
|||||||
42
styles.css
42
styles.css
@@ -337,7 +337,7 @@ label:hover { color: var(--c-primary); }
|
|||||||
/* 平台选择容器:单层 Grid 排列 */
|
/* 平台选择容器:单层 Grid 排列 */
|
||||||
.platform-chooser-container.platform-chooser-grid {
|
.platform-chooser-container.platform-chooser-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: column;
|
grid-template-columns: auto minmax(160px, 1fr) auto auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
@@ -347,6 +347,16 @@ label:hover { color: var(--c-primary); }
|
|||||||
box-shadow: var(--shadow-sm);
|
box-shadow: var(--shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.platform-chooser-container .toolbar-button {
|
||||||
|
justify-self: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.platform-chooser-container.platform-chooser-grid {
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(140px, max-content));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* =========================================================== */
|
/* =========================================================== */
|
||||||
/* 平台选择器样式 */
|
/* 平台选择器样式 */
|
||||||
/* =========================================================== */
|
/* =========================================================== */
|
||||||
@@ -467,14 +477,14 @@ label:hover { color: var(--c-primary); }
|
|||||||
|
|
||||||
.xhs-board {
|
.xhs-board {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||||
grid-template-rows: auto auto auto 1fr auto;
|
grid-template-rows: auto auto auto 1fr auto;
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"platform platform platform refresh publish"
|
"template template preview preview font font"
|
||||||
"template template preview preview font"
|
"content content content content content content"
|
||||||
"content content content content content"
|
"content content content content content content"
|
||||||
"content content content content content"
|
"content content content content content content"
|
||||||
"pagination pagination slice slice slice";
|
"pagination pagination pagination slice slice slice";
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--grad-xhs-bg);
|
background: var(--grad-xhs-bg);
|
||||||
@@ -509,6 +519,7 @@ label:hover { color: var(--c-primary); }
|
|||||||
background: white;
|
background: white;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
max-width: 100px;
|
||||||
transition: border-color 0.2s ease;
|
transition: border-color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +557,7 @@ label:hover { color: var(--c-primary); }
|
|||||||
.font-size-btn:hover { background: #eaf1fe; }
|
.font-size-btn:hover { background: #eaf1fe; }
|
||||||
|
|
||||||
.font-size-input {
|
.font-size-input {
|
||||||
width: 60px;
|
width: 35px;
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -556,17 +567,12 @@ label:hover { color: var(--c-primary); }
|
|||||||
|
|
||||||
.font-size-input:focus { outline: none; }
|
.font-size-input:focus { outline: none; }
|
||||||
|
|
||||||
.xhs-area-platform,
|
|
||||||
.xhs-board .platform-chooser-container,
|
|
||||||
.xhs-board .platform-selector-line {
|
|
||||||
grid-area: platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
.xhs-area-template { grid-area: template; }
|
.xhs-area-template { grid-area: template; }
|
||||||
.xhs-area-preview { grid-area: preview; }
|
.xhs-area-preview { grid-area: preview; }
|
||||||
.xhs-area-refresh { grid-area: refresh; justify-content: center; }
|
.xhs-area-font {
|
||||||
.xhs-area-publish { grid-area: publish; justify-content: center; }
|
grid-area: font;
|
||||||
.xhs-area-font { grid-area: font; flex-wrap: wrap; }
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
.xhs-area-pagination { grid-area: pagination; justify-content: center; gap: 16px; }
|
.xhs-area-pagination { grid-area: pagination; justify-content: center; gap: 16px; }
|
||||||
.xhs-area-slice { grid-area: slice; justify-content: center; gap: 16px; }
|
.xhs-area-slice { grid-area: slice; justify-content: center; gap: 16px; }
|
||||||
|
|
||||||
@@ -641,7 +647,7 @@ label:hover { color: var(--c-primary); }
|
|||||||
}
|
}
|
||||||
|
|
||||||
.xhs-page-number-input {
|
.xhs-page-number-input {
|
||||||
width: 56px;
|
width: 35px;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: 1px solid var(--c-border);
|
border: 1px solid var(--c-border);
|
||||||
|
|||||||
@@ -126,3 +126,4 @@ SOLVE:obsidian控制台打印信息,定位在哪里阻塞,AI修复。
|
|||||||
自己写布局demo原型,让codex参考布局修改(原来元素美化的css可保留)。
|
自己写布局demo原型,让codex参考布局修改(原来元素美化的css可保留)。
|
||||||
demo原型可以手绘后,拍照让chatgpt生成,在此基础上自己修改。
|
demo原型可以手绘后,拍照让chatgpt生成,在此基础上自己修改。
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
48
tools/esbuild-obfuscator-plugin.mjs
Normal file
48
tools/esbuild-obfuscator-plugin.mjs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { promises as fs } from "fs";
|
||||||
|
|
||||||
|
// Esbuild plugin that optionally obfuscates the emitted bundle with javascript-obfuscator.
|
||||||
|
export default function javascriptObfuscatorPlugin(obfuscatorOptions = {}) {
|
||||||
|
let obfuscatorPromise;
|
||||||
|
|
||||||
|
const loadObfuscator = async () => {
|
||||||
|
if (!obfuscatorPromise) {
|
||||||
|
obfuscatorPromise = import("javascript-obfuscator")
|
||||||
|
.then((module) => module.default ?? module)
|
||||||
|
.catch((error) => {
|
||||||
|
console.warn("[esbuild] javascript-obfuscator unavailable, skipping obfuscation.", error);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return obfuscatorPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default to preserving line breaks unless explicitly overridden.
|
||||||
|
if (typeof obfuscatorOptions.compact === "undefined") {
|
||||||
|
obfuscatorOptions.compact = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "javascript-obfuscator",
|
||||||
|
setup(build) {
|
||||||
|
build.onEnd(async (result) => {
|
||||||
|
if (result.errors.length) return;
|
||||||
|
const outfile = build.initialOptions.outfile;
|
||||||
|
if (!outfile) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const obfuscator = await loadObfuscator();
|
||||||
|
if (!obfuscator?.obfuscate) return;
|
||||||
|
|
||||||
|
const source = await fs.readFile(outfile, "utf8");
|
||||||
|
const obfuscatedCode = obfuscator
|
||||||
|
.obfuscate(source, obfuscatorOptions)
|
||||||
|
.getObfuscatedCode();
|
||||||
|
|
||||||
|
await fs.writeFile(outfile, obfuscatedCode, "utf8");
|
||||||
|
} catch (error) {
|
||||||
|
console.warn("[esbuild] javascript-obfuscator plugin failed, continuing without obfuscation.", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user