Compare commits

...

10 commits
1.0.16 ... main

Author SHA1 Message Date
Yeban8090
5a68d36341
Merge pull request #29 from Yeban8090/1.0.19
1.0.19
2025-08-21 10:59:56 +08:00
yeban
e8651dd050 插件视图创建优化 2025-08-21 10:54:54 +08:00
yeban
5400e81d85 插件视图创建优化 2025-08-21 10:53:55 +08:00
Yeban8090
b900096ad5 发布1.0.18 2025-06-15 13:00:38 +08:00
Yeban8090
66073354a1
Merge pull request #26 from bushnerd/main
Add heading level option for content splitting
2025-06-15 12:36:00 +08:00
bushnerd
1b6e0a1bb0 Add heading level option for content splitting 2025-06-15 11:59:59 +08:00
bushnerd
aa1e14d586 Change content divider from h2(##) to h1(#) and update related prompt messages 2025-06-15 11:24:43 +08:00
Yeban8090
8b339e833f
Merge pull request #23 from Yeban8090/1.0.17
1.0.17
2025-06-03 23:15:59 +08:00
Yeban8090
bcf6def0e8 新增头像圆角设置 2025-06-03 23:05:21 +08:00
Yeban8090
f2075f421e 调整整体视窗布局,使低分辨率机器更加舒适 2025-06-03 22:46:15 +08:00
13 changed files with 156 additions and 74 deletions

View file

@ -12,7 +12,7 @@
</p>
## 功能特点
- 📝 使用二级标题分割内容,每个标题自动生成一张配图
- 📝 可设置使用一级或二级标题分割内容,每个标题自动生成一张配图
- 🎨 提供多种精美模板,支持自定义字体和字号
- 🎯 支持自定义主题,可调整颜色、字体、间距等样式
- 👤 可自定义用户头像、昵称和页脚文案
@ -21,7 +21,7 @@
- 🔒 锁定功能避免预览刷新打断书写
## 使用方法
1. 核心用法:用二级标题(##)分割内容,每个标题生成一张小红书配图
1. 核心用法:在设置中选择标题级别(一级#或二级##),用对应标题分割内容,每个标题生成一张小红书配图
2. 首图制作单独调整首节字号至20-24px使用【下载当前页】导出
3. 长文优化内容较多的章节可调小字号至14-16px后单独导出
4. 批量操作:保持统一字号时,用【导出全部页】批量生成
@ -44,7 +44,8 @@
4. 在设置中启用插件
## 使用技巧
- 使用二级标题来分割不同的图片内容
- 在设置中选择适合的标题级别(一级#或二级##)来分割不同的图片内容
- 一级标题适合大章节分割,二级标题适合小章节分割
- 调整字号大小以适应不同长度的内容
- 可以自定义头像和用户信息
- 支持实时预览和编辑

View file

@ -1,7 +1,7 @@
{
"id": "note-to-red",
"name": "Note to RED",
"version": "1.0.16",
"version": "1.0.19",
"minAppVersion": "0.15.0",
"description": "Convert Markdown notes to RED (Xiaohongshu) style images",
"author": "Yeban",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 845 KiB

After

Width:  |  Height:  |  Size: 705 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 987 KiB

After

Width:  |  Height:  |  Size: 676 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 879 KiB

After

Width:  |  Height:  |  Size: 688 KiB

View file

@ -1,27 +1,34 @@
import { App } from 'obsidian';
import RedPlugin from './main';
export class RedConverter {
private static app: App;
private static plugin: RedPlugin;
static initialize(app: App) {
static initialize(app: App, plugin: RedPlugin) {
this.app = app;
this.plugin = plugin;
}
static hasValidContent(element: HTMLElement): boolean {
const headers = element.querySelectorAll('h2');
const settings = this.plugin?.settingsManager?.getSettings();
const headingLevel = settings?.headingLevel || 'h1';
const headers = element.querySelectorAll(headingLevel);
return headers.length > 0;
}
static formatContent(element: HTMLElement): void {
const headers = Array.from(element.querySelectorAll('h2'));
const settings = this.plugin?.settingsManager?.getSettings();
const headingLevel = settings?.headingLevel || 'h1';
const headers = Array.from(element.querySelectorAll(headingLevel));
if (headers.length === 0) {
element.empty();
const tip = element.createEl('div', {
cls: 'red-empty-message',
text: `⚠️ 温馨提示
使(##)
使${headingLevel === 'h1' ? '一级标题(#)' : '二级标题(##)'}
${headingLevel === 'h1' ? '一级标题' : '二级标题'}
`
});
// 触发自定义事件
@ -98,11 +105,14 @@ export class RedConverter {
}
private static createContentSection(header: Element, index: number): HTMLElement | null {
const settings = this.plugin?.settingsManager?.getSettings();
const headingLevel = settings?.headingLevel || 'h1';
// 获取当前标题到下一个标题之间的所有内容
let content: Element[] = [];
let current = header.nextElementSibling;
while (current && current.tagName !== 'H2') {
while (current && current.tagName !== headingLevel.toUpperCase()) {
content.push(current.cloneNode(true) as Element);
current = current.nextElementSibling;
}

View file

@ -7,71 +7,79 @@ import { DonateManager } from './donateManager';
import { RedSettingTab } from './settings/SettingTab';
export default class RedPlugin extends Plugin {
settingsManager: SettingsManager;
themeManager: ThemeManager;
settingsManager: SettingsManager;
themeManager: ThemeManager;
async onload() {
// 初始化设置管理器
this.settingsManager = new SettingsManager(this);
await this.settingsManager.loadSettings();
async onload() {
// 初始化设置管理器
this.settingsManager = new SettingsManager(this);
await this.settingsManager.loadSettings();
// 初始化主题管理器
this.themeManager = new ThemeManager(this.app, this.settingsManager);
// 初始化主题管理器
this.themeManager = new ThemeManager(this.app, this.settingsManager);
// 初始化转换器
RedConverter.initialize(this.app);
// 初始化转换器
RedConverter.initialize(this.app, this);
DonateManager.initialize(this.app, this);
DonateManager.initialize(this.app, this);
// 注册视图
this.registerView(
VIEW_TYPE_RED,
(leaf) => new RedView(leaf, this.themeManager, this.settingsManager)
);
// 注册视图
this.registerView(
VIEW_TYPE_RED,
(leaf) => new RedView(leaf, this.themeManager, this.settingsManager)
);
// 添加首次加载自动打开视图的逻辑
this.app.workspace.onLayoutReady(() => {
if (this.app.workspace.getLeavesOfType(VIEW_TYPE_RED).length === 0) {
const leaf = this.app.workspace.getRightLeaf(false);
if (leaf) {
leaf.setViewState({
type: VIEW_TYPE_RED,
active: false // 设置为 false 表示不聚焦
});
}
}
});
// 添加首次加载自动打开视图的逻辑
// this.app.workspace.onLayoutReady(() => {
// this.app.workspace.on("layout-change", () => {
// const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_RED);
// if (leaves.length === 0) {
// const rightLeaf = this.app.workspace.getRightLeaf(false);
// if (rightLeaf) {
// rightLeaf.setViewState({
// type: VIEW_TYPE_RED,
// active: false,
// });
// }
// }
// });
// });
// 添加命令到命令面板
this.addCommand({
// 添加命令到命令面板
this.addCommand({
id: 'open-mp-preview',
name: '打开小红书图片预览',
callback: async () => {
await this.activateView();
}
});
callback: async () => {
await this.activateView();
},
});
// 在插件的 onload 方法中添加:
this.addSettingTab(new RedSettingTab(this.app, this));
}
// 添加一个功能按钮用于打开所有面板
this.addRibbonIcon("image", "打开小红书图片预览", () => {
this.activateView();
});
async activateView() {
// 如果视图已经存在,激活它
// 在插件的 onload 方法中添加:
this.addSettingTab(new RedSettingTab(this.app, this));
}
async activateView() {
// 如果视图已经存在,激活它
const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_RED); // 使用原来的视图类型
if (leaves.length > 0) {
this.app.workspace.revealLeaf(leaves[0]);
return;
}
// 创建新视图
const rightLeaf = this.app.workspace.getRightLeaf(false);
if (rightLeaf) {
await rightLeaf.setViewState({
type: VIEW_TYPE_RED,
active: true,
});
} else {
new Notice('无法创建视图面板');
}
if (leaves.length > 0) {
this.app.workspace.revealLeaf(leaves[0]);
return;
}
}
// 创建新视图
const rightLeaf = this.app.workspace.getRightLeaf(false);
if (rightLeaf) {
await rightLeaf.setViewState({
type: VIEW_TYPE_RED,
active: true,
});
} else {
new Notice('无法创建视图面板');
}
}
}

View file

@ -566,6 +566,34 @@ export class CreateThemeModal extends Modal {
.replace(/border:\s*1px solid\s*#[a-fA-F0-9]+80/, `border: 1px solid ${value}80`);
});
});
// 添加头像圆角设置
new Setting(headerSection)
.setName('头像圆角')
.setDesc('设置头像的圆角大小单位px。设置为-1表示圆形大于1则有圆角')
.addText(text => {
// 获取当前圆角值
const currentRadius = styles.avatar.container.match(/border-radius:\s*([\d-]+)px/)?.[1] || '12';
text.setValue(currentRadius)
.setPlaceholder('输入圆角大小')
.onChange(value => {
// 解析输入值
let radius: string;
if (value === '-1') {
// 设置为圆形50%
radius = '50%';
} else {
// 设置为具体的像素值
const pixelValue = parseInt(value) || 12;
radius = `${pixelValue}px`;
}
// 更新样式
styles.avatar.container = styles.avatar.container
.replace(/border-radius:\s*[^;]+/, `border-radius: ${radius}`);
});
});
new Setting(headerSection)
.setName('认证图标颜色')
.setDesc('设置认证图标的颜色')

View file

@ -58,6 +58,39 @@ export class RedSettingTab extends PluginSettingTab {
}
private renderBasicSettings(containerEl: HTMLElement): void {
// 排版管理区域
const typographySection = containerEl.createDiv('red-settings-subsection');
const typographyHeader = typographySection.createDiv('red-settings-subsection-header');
const typographyToggle = typographyHeader.createSpan('red-settings-subsection-toggle');
setIcon(typographyToggle, 'chevron-right');
typographyHeader.createEl('h3', { text: '排版管理' });
const typographyContent = typographySection.createDiv('red-settings-subsection-content');
// 折叠/展开逻辑
typographyHeader.addEventListener('click', () => {
const isExpanded = !typographySection.hasClass('is-expanded');
typographySection.toggleClass('is-expanded', isExpanded);
setIcon(typographyToggle, isExpanded ? 'chevron-down' : 'chevron-right');
});
// 内容分割标题级别设置
new Setting(typographyContent)
.setName('内容分割标题级别')
.setDesc('选择用于分割内容生成图片的标题级别:')
.addDropdown(dropdown => dropdown
.addOption('h1', '一级标题(#) - 按大章节分割')
.addOption('h2', '二级标题(##) - 按小章节分割')
.setValue(this.plugin.settingsManager.getSettings().headingLevel)
.onChange(async (value: 'h1' | 'h2') => {
await this.plugin.settingsManager.updateSettings({
headingLevel: value
});
new Notice('标题级别设置已更新,请重启 Obsidian 或重新加载以使更改生效');
})
);
// 字体管理区域
const fontSection = containerEl.createDiv('red-settings-subsection');
const fontHeader = fontSection.createDiv('red-settings-subsection-header');
@ -353,4 +386,4 @@ export class RedSettingTab extends PluginSettingTab {
).open();
}));
}
}
}

View file

@ -21,6 +21,7 @@ interface RedSettings {
showFooter?: boolean;
footerLeftText: string;
footerRightText: string;
headingLevel: 'h1' | 'h2'; // 标题级别选项
customFonts: { value: string; label: string; isPreset?: boolean }[]; // 添加自定义字体配置
backgroundSettings: {
imageUrl: string;
@ -44,6 +45,7 @@ export const DEFAULT_SETTINGS: RedSettings = {
userId: '@Yeban',
showTime: true,
timeFormat: 'zh-CN',
headingLevel: 'h2', // 默认使用二级标题
footerLeftText: '夜半过后,光明便启程',
footerRightText: '欢迎关注公众号:夜半',
customFonts: [

View file

@ -244,7 +244,7 @@
/* 设置子区域折叠样式 */
.red-settings .red-settings-subsection {
margin: 0 12px;
margin: 0 12px 12px 12px;
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
overflow-y: auto;

View file

@ -23,7 +23,7 @@
.red-preview-container {
position: relative;
min-width: 490px;
height: 100%;
aspect-ratio: 3/4;
display: flex;
justify-content: center;
align-items: flex-start;
@ -90,7 +90,7 @@
/* 导航容器 */
.red-nav-container {
position: fixed;
bottom: 120px; /* 调整位置避免与底部工具栏重叠 */
bottom: 110px; /* 调整位置避免与底部工具栏重叠 */
left: 50%;
transform: translateX(-50%);
display: flex;

View file

@ -316,12 +316,12 @@ export class RedView extends ItemView {
attr: { 'aria-label': '使用指南' }
});
setIcon(helpButton, 'help');
const headingLevel = this.settingsManager.getSettings().headingLevel || 'h1';
parent.createEl('div', {
cls: 'red-help-tooltip',
text: `使用指南:
1. (##)
2. 使 ---
1. ${headingLevel === 'h1' ? '一级标题(#)' : '二级标题(##)'}
2. ${headingLevel === 'h1' ? '一级标题(#)' : '二级标题(##)'}使 ---
3. 20-24px使
4. 14-16px后单独导出
5.
@ -553,7 +553,7 @@ export class RedView extends ItemView {
this.updateControlsState(hasValidContent);
if (!hasValidContent) {
this.copyButton.setAttribute('title', '请先添加级标题内容');
this.copyButton.setAttribute('title', '请先添加级标题内容');
} else {
this.copyButton.removeAttribute('title');
}
@ -737,4 +737,4 @@ export class RedView extends ItemView {
return false;
}
}
}