重构css

This commit is contained in:
Yeban8090 2025-04-12 18:56:37 +08:00
parent f4ad45669e
commit 682cde122b
20 changed files with 1224 additions and 1003 deletions

2
.gitignore vendored
View file

@ -7,7 +7,7 @@ npm-debug.log
main.js
*.js.map
data.json
styles.css
# macOS
.DS_Store

View file

@ -2,37 +2,64 @@ import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
const banner =
`/*
const banner = `/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;
const prod = process.argv[2] === "production";
const prod = (process.argv[2] === 'production');
const context = await esbuild.context({
const config = {
banner: {
js: banner,
},
entryPoints: ["src/main.ts"],
entryPoints: ['src/main.ts'],
bundle: true,
external: [
"obsidian",
"electron",
...builtins
],
format: "cjs",
target: "es2016",
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/search',
'@codemirror/state',
'@codemirror/view',
'@lezer/common',
'@lezer/highlight',
'@lezer/lr',
...builtins],
format: 'cjs',
target: 'es2018',
logLevel: "info",
sourcemap: prod ? false : "inline",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: "main.js",
});
outfile: 'main.js',
};
// 简化 CSS 配置
const cssConfig = {
entryPoints: ['src/styles/index.css'],
bundle: true,
outfile: 'styles.css', // 直接输出到项目根目录
allowOverwrite: true
};
if (prod) {
await context.rebuild();
process.exit(0);
await Promise.all([
esbuild.build(config),
esbuild.build(cssConfig)
]).catch(() => process.exit(1));
} else {
await context.watch();
const [context, cssContext] = await Promise.all([
esbuild.context(config),
esbuild.context(cssConfig)
]);
await Promise.all([
context.watch(),
cssContext.watch()
]);
console.log('⚡ esbuild is watching for changes...');
}

View file

@ -1,5 +1,5 @@
import type { ImgTemplate } from '../imgTemplateManager';
import type { SettingsManager } from '../settings';
import type { SettingsManager } from '../settings/settings';
import { Notice } from 'obsidian';
export class DefaultTemplate implements ImgTemplate {

View file

@ -1,6 +1,6 @@
import { DefaultTemplate } from './imgTelplate/defaultTemplate';
import { NotesTemplate } from './imgTelplate/notesTemplate';
import type { SettingsManager } from './settings';
import type { SettingsManager } from './settings/settings';
import type { ThemeManager } from './themeManager';
export interface ImgTemplate {
id: string;

View file

@ -1,12 +1,13 @@
import { Plugin, Notice } from 'obsidian';
import { RedView, VIEW_TYPE_RED } from './view'; // 暂时改回原来的导入
import { ThemeManager } from './themeManager';
import { SettingsManager } from './settings';
import { SettingsManager } from './settings/settings';
import { RedConverter } from './converter'; // 暂时使用原来的转换器
import { DonateManager } from './donateManager';
import { RedSettingTab } from './settings/SettingTab';
export default class RedPlugin extends Plugin {
private settingsManager: SettingsManager;
settingsManager: SettingsManager;
async onload() {
// 初始化设置管理器
@ -14,11 +15,11 @@ export default class RedPlugin extends Plugin {
await this.settingsManager.loadSettings();
// 初始化主题管理器
const themeManager = new ThemeManager(this.app);
const themeManager = new ThemeManager(this.app, this.settingsManager);
// 初始化转换器
RedConverter.initialize(this.app);
DonateManager.initialize(this.app, this);
// 注册视图
@ -48,8 +49,11 @@ export default class RedPlugin extends Plugin {
await this.activateView();
}
});
// 在插件的 onload 方法中添加:
this.addSettingTab(new RedSettingTab(this.app, this));
}
async activateView() {
// 如果视图已经存在,激活它
const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_RED); // 使用原来的视图类型

View file

@ -1,59 +0,0 @@
interface RedSettings {
templateId: string;
themeId: string;
fontFamily: string;
fontSize: number;
backgroundId: string;
// 添加用户信息设置
userAvatar: string;
userName: string;
userId: string;
showTime: boolean;
timeFormat: string;
footerLeftText: string;
footerRightText: string;
}
const DEFAULT_SETTINGS: RedSettings = {
templateId: 'default',
themeId: 'light',
fontFamily: 'Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC"',
fontSize: 16,
backgroundId: '',
// 修改默认用户信息
userAvatar: '', // 默认为空,提示用户上传
userName: '夜半',
userId: '@Yeban',
showTime: true,
timeFormat: 'zh-CN',
footerLeftText: '夜半过后,光明便启程',
footerRightText: '欢迎关注公众号:夜半'
}
export class SettingsManager {
private plugin: any;
private settings: RedSettings;
constructor(plugin: any) {
this.plugin = plugin;
this.settings = DEFAULT_SETTINGS;
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.plugin.loadData());
}
async saveSettings() {
await this.plugin.saveData(this.settings);
}
getSettings(): RedSettings {
return this.settings;
}
async updateSettings(settings: Partial<RedSettings>) {
this.settings = { ...this.settings, ...settings };
await this.saveSettings();
}
}

View file

@ -0,0 +1,54 @@
import { App, Modal, Setting } from 'obsidian';
import { Theme } from '../themeManager';
export class CreateThemeModal extends Modal {
theme: Theme;
onSubmit: (theme: Theme) => void;
isEditing: boolean;
constructor(app: App, onSubmit: (theme: Theme) => void, existingTheme?: Theme) {
super(app);
this.onSubmit = onSubmit;
this.isEditing = !!existingTheme;
if(existingTheme){
this.theme = existingTheme;
}
}
onOpen() {
const { contentEl } = this;
contentEl.empty();
contentEl.createEl('h2', { text: this.isEditing ? '编辑模板' : '新建模板' });
new Setting(contentEl)
.setName('模板名称')
.addText(text => text
.setPlaceholder('请输入模板名称')
.setValue(this.theme.name)
.onChange(value => {
this.theme.name = value;
}));
// 移除模板描述相关代码
const buttonContainer = contentEl.createEl('div', { cls: 'red-modal-buttons' });
const saveButton = buttonContainer.createEl('button', {
cls: 'red-modal-button red-modal-button-save',
text: '保存'
});
saveButton.addEventListener('click', () => {
if (this.theme.name) {
this.onSubmit(this.theme);
this.close();
}
});
const cancelButton = buttonContainer.createEl('button', {
cls: 'red-modal-button',
text: '取消'
});
cancelButton.addEventListener('click', () => {
this.close();
});
}
}

View file

@ -0,0 +1,98 @@
import { App, PluginSettingTab, Setting, setIcon } from 'obsidian';
import RedPlugin from '../main';
import { Theme } from '../themeManager';
import { CreateThemeModal } from './CreateThemeModal';
export class RedSettingTab extends PluginSettingTab {
plugin: RedPlugin;
private expandedSections: Set<string> = new Set();
constructor(app: App, plugin: RedPlugin) {
super(app, plugin);
this.plugin = plugin;
}
private createSection(containerEl: HTMLElement, title: string, renderContent: (contentEl: HTMLElement) => void) {
const section = containerEl.createDiv('red-settings-section');
const header = section.createDiv('red-settings-section-header');
const toggle = header.createSpan('red-settings-section-toggle');
setIcon(toggle, 'chevron-right');
header.createEl('h4', { text: title });
const content = section.createDiv('red-settings-section-content');
renderContent(content);
header.addEventListener('click', () => {
const isExpanded = !section.hasClass('is-expanded');
section.toggleClass('is-expanded', isExpanded);
setIcon(toggle, isExpanded ? 'chevron-down' : 'chevron-right');
if (isExpanded) {
this.expandedSections.add(title);
} else {
this.expandedSections.delete(title);
}
});
if (this.expandedSections.has(title) || (!containerEl.querySelector('.red-settings-section'))) {
section.addClass('is-expanded');
setIcon(toggle, 'chevron-down');
this.expandedSections.add(title);
}
return section;
}
display(): void {
const { containerEl } = this;
containerEl.empty();
containerEl.addClass('red-settings-container');
containerEl.createEl('h2', { text: 'Note to RED 设置' });
this.createSection(containerEl, '主题管理', (contentEl) => {
const themeList = contentEl.createDiv('red-theme-list');
const themes = this.plugin.settingsManager.getAllThemes();
themes.forEach(theme => {
const themeDiv = themeList.createDiv('red-theme-item');
new Setting(themeDiv)
.setName(theme.name)
.setDesc(theme.isPreset ? '(预设)' : '')
.addButton(btn => !theme.isPreset && btn
.setIcon('pencil')
.setTooltip('编辑')
.onClick(() => {
const fullTheme = {
...theme,
styles: theme.styles || {} // 确保 styles 属性存在
};
new CreateThemeModal(this.app, async (updatedTheme) => {
await this.plugin.settingsManager.updateTheme(theme.id, updatedTheme);
this.display();
}, fullTheme).open();
}))
.addButton(btn => !theme.isPreset && btn
.setIcon('trash')
.setTooltip('删除')
.onClick(async () => {
await this.plugin.settingsManager.removeTheme(theme.id);
this.display();
}));
});
// 添加新主题按钮
new Setting(contentEl)
.addButton(btn => btn
.setButtonText('添加新主题')
.setCta()
.onClick(() => {
new CreateThemeModal(this.app, (theme) => {
this.plugin.settingsManager.addCustomTheme(theme);
this.display();
}).open();
}));
});
}
}

126
src/settings/settings.ts Normal file
View file

@ -0,0 +1,126 @@
import { Theme } from '../themeManager';
interface RedSettings {
templateId: string;
themeId: string;
fontFamily: string;
fontSize: number;
backgroundId: string;
themes: Theme[]; // 添加主题列表
customThemes: Theme[]; // 添加自定义主题列表
// 添加用户信息设置
userAvatar: string;
userName: string;
userId: string;
showTime: boolean;
timeFormat: string;
footerLeftText: string;
footerRightText: string;
}
const DEFAULT_SETTINGS: RedSettings = {
templateId: 'default',
themeId: 'light',
fontFamily: 'Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC"',
fontSize: 16,
backgroundId: '',
themes: [],
customThemes: [],
// 修改默认用户信息
userAvatar: '', // 默认为空,提示用户上传
userName: '夜半',
userId: '@Yeban',
showTime: true,
timeFormat: 'zh-CN',
footerLeftText: '夜半过后,光明便启程',
footerRightText: '欢迎关注公众号:夜半'
}
export class SettingsManager {
private plugin: any;
private settings: RedSettings;
constructor(plugin: any) {
this.plugin = plugin;
this.settings = DEFAULT_SETTINGS;
}
async loadSettings() {
const savedData = await this.plugin.loadData();
// 如果是首次加载或 themes 为空,导入预设主题
if (!savedData?.themes || savedData.themes.length === 0) {
const { templates } = await import('../templates');
savedData.themes = Object.values(templates).map(theme => ({
...theme,
isPreset: true
}));
}
// 确保 customThemes 存在
if (!savedData.customThemes) {
savedData.customThemes = [];
}
this.settings = Object.assign({}, DEFAULT_SETTINGS, savedData);
}
// 主题相关方法
getAllThemes(): Theme[] {
return [...this.settings.themes, ...this.settings.customThemes];
}
getTheme(themeId: string): Theme | undefined {
return this.settings.themes.find(theme => theme.id === themeId)
|| this.settings.customThemes.find(theme => theme.id === themeId);
}
async addCustomTheme(theme: Theme) {
theme.isPreset = false;
this.settings.customThemes.push(theme);
await this.saveSettings();
}
async updateTheme(themeId: string, updatedTheme: Partial<Theme>) {
const theme = this.getTheme(themeId);
if (theme && !theme.isPreset) {
const index = this.settings.customThemes.findIndex(t => t.id === themeId);
if (index !== -1) {
this.settings.customThemes[index] = {
...this.settings.customThemes[index],
...updatedTheme
};
await this.saveSettings();
return true;
}
}
return false;
}
async removeTheme(themeId: string): Promise<boolean> {
const theme = this.getTheme(themeId);
if (theme && !theme.isPreset) {
this.settings.customThemes = this.settings.customThemes.filter(t => t.id !== themeId);
if (this.settings.themeId === themeId) {
this.settings.themeId = 'default';
}
await this.saveSettings();
return true;
}
return false;
}
async saveSettings() {
await this.plugin.saveData(this.settings);
}
getSettings(): RedSettings {
return this.settings;
}
async updateSettings(settings: Partial<RedSettings>) {
this.settings = { ...this.settings, ...settings };
await this.saveSettings();
}
}

View file

@ -0,0 +1,70 @@
/* 代码块样式 */
.red-code-dots {
margin: 8px 0 12px 0;
display: flex;
gap: 6px;
}
.red-code-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.red-code-dot-red { background-color: #ff5f56; }
.red-code-dot-yellow { background-color: #ffbd2e; }
.red-code-dot-green { background-color: #27c93f; }
/* 链接样式 */
.red-link {
color: var(--text-accent);
text-decoration: none;
}
/* 表格样式 */
.red-table {
border-collapse: collapse;
margin: 1em 0;
width: 100%;
}
.red-table th,
.red-table td {
border: 1px solid var(--background-modifier-border);
padding: 8px;
}
/* 分割线样式 */
.red-hr {
border: none;
border-top: 1px solid var(--background-modifier-border);
margin: 20px 0;
}
/* 删除线样式 */
.red-del {
text-decoration: line-through;
}
/* 任务列表样式 */
.red-task-list-item {
list-style: none;
}
.red-task-list-item input[type="checkbox"] {
margin-right: 6px;
}
/* 脚注样式 */
.red-footnote {
color: var(--text-accent);
text-decoration: none;
}
/* 图片样式 */
.red-image {
max-width: 100%;
height: auto;
display: block;
margin: 1em auto;
}

6
src/styles/index.css Normal file
View file

@ -0,0 +1,6 @@
@import url('./view/layout.css');
@import url('./view/tool-bar.css');
@import url('./view/about-modal.css');
@import url('./theme/theme-user-info.css');
@import url('./template/red-notes.css');
@import url('./element/markdown-element.css');

View file

@ -0,0 +1,42 @@
/* 备忘录风格样式 */
.red-notes-header .red-notes-bar {
position: relative;
height: 30px;
padding: 30px 0 0 0; /* 增加底部内边距 */
color: #f8c744;
font-size: 17px;
}
.red-notes-bar:before {
content: "备忘录";
position: absolute;
left: 0;
top: 3px;
height: 24px;
line-height: 28px;
padding-left: 24px;
width: 120px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='rgb(248, 199, 68)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 18-6-6 6-6'%3E%3C/path%3E%3C/svg%3E");
background-repeat: no-repeat;
}
.red-notes-bar:after {
content: "";
position: absolute;
right: 0;
top: 3px;
width: 24px;
height: 24px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(248, 199, 68)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpath d='M17 12h.01'%3E%3C/path%3E%3Cpath d='M12 12h.01'%3E%3C/path%3E%3Cpath d='M7 12h.01'%3E%3C/path%3E%3C/svg%3E");
background-repeat: no-repeat;
}
.red-notes-actions {
position: absolute;
right: 60px;
top: 2px;
width: 24px;
height: 24px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(248, 199, 68)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8'%3E%3C/path%3E%3Cpolyline points='16 6 12 2 8 6'%3E%3C/polyline%3E%3Cline x1='12' x2='12' y1='2' y2='15'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat;
}

View file

@ -0,0 +1,105 @@
/* 用户信息区域样式 */
.red-user-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px 3px 12px;
line-height: normal;
}
.red-user-left {
display: flex;
align-items: center;
gap: 12px;
}
.red-user-avatar {
width: 42px;
height: 42px;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.red-user-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}
.red-avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--background-primary-alt);
border-radius: 50%;
transition: all 0.3s ease;
}
.red-avatar-upload-icon {
font-size: 20px;
opacity: 0.6;
}
.red-avatar-placeholder:hover {
background-color: var(--background-modifier-border);
}
.red-avatar-placeholder:hover .red-avatar-upload-icon {
opacity: 0.8;
}
.red-user-meta {
display: flex;
flex-direction: column;
gap: 1px;
}
.red-user-name-container {
display: flex;
align-items: center;
gap: 4px;
}
.red-user-name {
font-size: 16px;
font-weight: 600;
color: var(--text-normal);
cursor: pointer;
}
.red-user-id {
font-size: 14px;
color: var(--text-muted);
cursor: pointer;
}
.red-user-right {
color: var(--text-muted);
font-size: 14px;
}
/* 编辑输入框样式 */
.red-user-edit-input {
border: none;
border-bottom: 1px solid var(--background-modifier-border);
outline: none;
padding: 2px 4px;
font-size: inherit;
font-family: inherit;
background: transparent;
color: var(--text-normal);
}
/* 悬停效果 */
.red-user-avatar:hover,
.red-user-name:hover,
.red-user-id:hover {
opacity: 0.8;
}

View file

@ -0,0 +1,202 @@
/* 关于作者的框 */
.red-about-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--background-modifier-cover);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
/* 弹框主体 */
.red-about-modal {
background: var(--background-primary);
border-radius: 12px;
padding: 20px 20px;
width: 520px;
max-height: 90vh;
position: relative;
display: flex;
flex-direction: column;
gap: 10px;
overflow-y: auto;
}
/* 自定义滚动条样式 */
.red-about-modal::-webkit-scrollbar {
width: 8px;
}
.red-about-modal::-webkit-scrollbar-track {
background: var(--background-primary-alt);
border-radius: 4px;
}
.red-about-modal::-webkit-scrollbar-thumb {
background: var(--background-modifier-border);
border-radius: 4px;
}
.red-about-modal::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* 关闭按钮 */
.red-about-close {
position: absolute;
top: 7px;
right: 7px;
width: 28px;
height: 28px;
background: transparent;
border: none;
border-radius: 6px;
font-size: 17px;
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
/* macOS 系统下的样式 */
@media screen and (-webkit-min-device-pixel-ratio: 0) and (min-color-index:0) {
.red-about-close {
right: auto;
left: 7px;
}
}
.red-about-close:hover {
background: var(--background-primary-alt);
color: var(--text-normal);
}
/* 内容区块 */
.red-about-section {
padding: 10px;
margin: 8px 20px 0 20px;
border-radius: 8px;
}
.red-about-intro-section {
background: #fafafa;
border: 1px solid #f0f0f0;
}
.red-about-donate-section {
background: #fff9f5;
border: 1px solid #ffe4d9;
}
.red-about-mp-section {
background: #f5fff7;
border: 1px solid #e6f7e9;
}
/* 文字样式 */
.red-about-title {
font-size: 20px;
font-weight: 600;
color: var(--text-normal);
margin: 0 0 1px;
text-align: center;
letter-spacing: 0.5px;
}
.red-about-name {
color: var(--text-accent);
font-weight: 600;
font-size: 16px;
padding: 0 2px;
}
.red-about-identity {
color: var(--text-normal);
font-weight: 500;
background: var(--background-primary-alt);
padding: 0 4px;
border-radius: 3px;
}
.red-about-highlight {
color: var(--text-accent);
font-weight: 500;
}
.red-about-value {
color: var(--text-accent);
font-weight: 500;
}
.red-about-subtitle {
font-size: 18px;
color: var(--text-accent);
margin: 8px 0 12px;
letter-spacing: 0.3px;
font-weight: 600;
}
.red-about-intro {
font-size: 15px;
color: var(--text-normal);
margin: 8px 0;
line-height: 1.8;
letter-spacing: 0.2px;
}
.red-about-role,
.red-about-desc {
font-size: 14.5px;
color: var(--text-muted);
margin: 6px 0;
line-height: 1.8;
letter-spacing: 0.2px;
}
.red-about-emphasis {
font-weight: 500;
color: var(--text-error);
}
.red-about-footer {
font-size: 15px;
color: var(--text-normal);
text-align: center;
margin: 1px 0 0;
padding: 1px 1px;
background: var(--background-primary-alt);
border-radius: 8px;
font-weight: 500;
letter-spacing: 0.3px;
line-height: 1.6;
}
.red-about-footer strong {
color: var(--text-accent);
font-weight: 600;
}
/* 二维码容器 */
.red-about-qr {
width: 100%;
height: 150px;
margin: 5px 0;
padding: 5px;
background: var(--background-primary);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.red-about-qr img {
width: 100%;
height: 100%;
object-fit: contain;
}

186
src/styles/view/layout.css Normal file
View file

@ -0,0 +1,186 @@
/* 预览区域 */
.red-preview-wrapper {
padding: 10px 20px 20px 20px;
margin: 10px;
height: calc(100% - 180px);
overflow-y: auto;
background: var(--background-primary);
flex: 1;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
border: 1px solid rgba(82, 144, 220, 0.1);
}
.red-empty-state {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #999;
font-size: 16px;
}
/* 小红书预览容器 */
.red-preview-container {
position: relative;
min-width: 490px;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
background: var(--background-primary-alt);
border-radius: 12px;
padding: 20px;
overflow: auto;
}
.red-preview-header{
padding-bottom: 10px;
}
/* 图片预览区域 */
.red-image-preview {
width: 100%;
max-width: 450px;
aspect-ratio: 3/4;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
padding: 20px;
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 内容区域容器 */
.red-content-wrapper {
flex: 1;
overflow: hidden;
}
/* 导航按钮 */
.red-nav-button {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 20px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.red-nav-button:hover {
background: white;
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 页码指示器 */
.red-page-indicator {
padding: 6px 12px;
background: rgba(255, 255, 255, 0.9);
border-radius: 16px;
font-size: 14px;
color: #333;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 导航容器 */
.red-nav-container {
position: fixed;
bottom: 120px; /* 调整位置避免与底部工具栏重叠 */
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
z-index: 100;
padding: 10px;
background: rgba(255, 255, 255, 0.1); /* 半透明背景 */
backdrop-filter: blur(8px); /* 毛玻璃效果 */
border-radius: 20px;
}
.red-nav-button {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 20px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(4px);
}
.red-nav-button:hover {
background: white;
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 内容区块样式 */
.red-content-section {
display: none;
margin: 0 13px;
}
.red-content-section[data-index="0"] {
display: block;
}
.red-section-active {
display: block;
}
.red-preview-container section:not(.red-section-active) {
display: none;
}
.red-nav-hidden {
visibility: hidden;
}
.red-section-visible {
display: block !important;
}
.red-section-hidden {
display: none !important;
}
/* 空状态提示 */
.red-empty-message {
text-align: center;
padding: 40px 20px;
color: var(--text-error);
font-size: 15px;
background: var(--background-primary-alt);
border: 1px dashed var(--background-modifier-border);
border-radius: 12px;
margin: 40px auto;
max-width: 320px;
line-height: 1.8;
white-space: pre-line;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View file

View file

@ -0,0 +1,253 @@
/* 状态栏样式覆盖 */
.red-view-content {
height: 100%;
padding: 10px 10px 0 10px;
overflow: auto;
background: var(--background-primary);
}
/* ===== 工具栏 ===== */
.red-toolbar, .red-bottom-bar {
padding: 15px 0;
max-width: 580px;
}
.red-toolbar {
top: 0;
border-radius: 8px;
border-bottom: 2px solid var(--background-modifier-border);
}
.red-bottom-bar {
bottom: 0;
border-radius: 8px;
border-top: 2px solid var(--background-modifier-border);
}
/* 控件组布局 */
.red-controls-group {
display: flex;
gap: 12px;
align-items: center;
width: 100%;
justify-content: flex-start; /* 改为靠左对齐 */
flex-wrap: nowrap;
min-width: 0;
}
/* ===== 按钮基础样式 ===== */
.red-controls-group button {
height: 36px;
border-radius: 8px;
border: 1px solid var(--background-modifier-border);
background: var(--background-primary);
color: var(--text-normal);
font-size: 14px;
box-shadow: 0 1px 3px var(--background-modifier-box-shadow);
flex: 1;
white-space: nowrap;
overflow: hidden;
}
/* 按钮文本样式 */
.red-controls-group button span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.red-controls-group button:hover {
background: var(--background-modifier-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--background-modifier-box-shadow);
}
.red-controls-group button:disabled {
opacity: 0.5;
background: var(--background-primary) !important;
color: var(--text-muted) !important;
cursor: not-allowed !important;
transform: none;
border-color: var(--background-modifier-border) !important;
box-shadow: none;
}
/* 特殊按钮样式 */
.red-controls-group .red-lock-button,
.red-controls-group .red-help-button {
width: 36px;
margin: 0 20px 0 10px;
flex: none ;
}
.red-controls-group .red-export-button {
background-color: var(--text-accent);
color: var(--text-on-accent);
border: none;
}
.red-controls-group .red-export-button:hover {
color: var(--text-on-accent);
background-color: var(--text-accent);
}
/* ===== 下拉选择器 ===== */
.red-select-container {
position: relative;
max-width: 200px;
flex: 1;
}
.red-select {
height: 36px;
padding: 0 12px;
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
background: var(--background-primary);
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
transition: all 0.2s ease;
color: var(--text-normal);
box-shadow: 0 1px 3px var(--background-modifier-box-shadow);
white-space: nowrap;
overflow: hidden;
}
.red-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
}
.red-select:hover {
background: var(--background-modifier-hover);
box-shadow: 0 2px 6px var(--background-modifier-box-shadow);
}
.red-select.disabled {
opacity: 0.5;
background: var(--background-secondary) !important;
color: var(--text-muted) !important;
border-color: var(--background-modifier-border) !important;
cursor: not-allowed;
box-shadow: none;
}
.red-select-arrow {
color: var(--text-normal);
font-size: 12px;
transition: transform 0.2s ease;
margin-left: 4px;
flex-shrink: 0;
}
.red-select-dropdown {
position: absolute;
top: calc(100% + 4px);
left: 0;
width: 100%;
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
box-shadow: 0 4px 12px var(--background-modifier-box-shadow);
display: none;
z-index: 1000;
overflow: hidden;
}
.red-select-dropdown.red-show {
display: block;
}
.red-select-item {
padding: 8px 12px;
cursor: pointer;
transition: all 0.2s ease;
color: var(--text-normal);
}
.red-select-item:hover {
background: var(--background-modifier-hover);
}
.red-select-item.red-selected {
background: var(--background-modifier-hover);
color: var(--text-accent);
}
/* ===== 字号调整组件 ===== */
.red-font-size-group {
height: 36px;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
padding: 0;
overflow: hidden;
box-shadow: 0 1px 3px var(--background-modifier-box-shadow);
}
.red-font-size-input {
width: 50px;
text-align: center;
}
/* ===== 帮助提示 ===== */
.red-help-tooltip {
position: absolute;
left: 30px;
bottom: 80px;
width: 450px;
padding: 12px 16px;
background: var(--background-primary);
border: 2px solid var(--background-modifier-border);
border-radius: 8px;
box-shadow: 0 4px 12px var(--background-modifier-box-shadow);
font-size: 13px;
line-height: 1.6;
color: var(--text-normal);
display: none;
white-space: pre-line;
z-index: 1000;
}
.red-help-button:hover + .red-help-tooltip {
display: block;
}
/* 复制按钮样式 */
.red-copy-button {
position: absolute;
top: 24px;
right: 30px;
z-index: 100;
background-color: var(--background-primary);
color: var(--text-normal);
border: none;
border-radius: 4px;
padding: 5px 8px;
font-size: 16px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease;
}
.red-preview-container:hover .red-copy-button {
opacity: 1;
}
.red-copy-button:hover {
background-color: var(--background-primary-alt);
}
.red-copy-button:disabled {
cursor: not-allowed;
opacity: 0.5;
}

View file

@ -1,9 +1,10 @@
import { App } from 'obsidian';
import { templates } from './templates';
import { SettingsManager } from './settings/settings';
interface Theme {
export interface Theme {
id: string;
name: string;
isPreset?: boolean; // 添加预设主题标识
styles: {
// 容器基础样式
imagePreview: string;
@ -80,64 +81,32 @@ interface Theme {
}
export class ThemeManager {
private themes: Map<string, Theme> = new Map();
private currentTheme: Theme;
private currentFont: string = '-apple-system';
private currentFontSize: number = 16;
private app: App;
private settingsManager: SettingsManager;
constructor(app: App) {
constructor(app: App, settingsManager: SettingsManager) {
this.app = app;
this.loadThemes(); // 加载主题
}
public async loadThemes() {
try {
Object.values(templates).forEach(theme => {
this.themes.set(theme.id, theme);
if (theme.id === 'default') {
this.currentTheme = theme;
}
});
} catch (error) {
console.error('加载主题失败:', error);
throw new Error('无法加载主题文件');
}
}
public getTheme(id: string): Theme | undefined {
return this.themes.get(id);
}
public getCurrentTheme(): Theme {
return this.currentTheme;
this.settingsManager = settingsManager;
}
public setCurrentTheme(id: string): boolean {
const theme = this.themes.get(id);
const theme = this.settingsManager.getTheme(id);
if (theme) {
this.currentTheme = theme;
return true;
}
console.error('主题未找到:', id);
return false;
}
public getAllThemes(): Theme[] {
return Array.from(this.themes.values());
}
public setFont(fontFamily: string) {
this.currentFont = fontFamily;
}
public setFontSize(size: number) {
this.currentFontSize = size;
}
// 修改 applyTheme 方法
public applyTheme(element: HTMLElement): void {
const styles = this.currentTheme.styles;
const styles = this.currentTheme.styles;
// 修改应用基础样式的方式
const imagePreview = element.querySelector('.red-image-preview');
if (imagePreview) {
@ -200,7 +169,7 @@ export class ThemeManager {
el.setAttribute('style', styles.footer.separator);
});
}
// 应用标题样式
['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(tag => {
element.querySelectorAll(tag).forEach(el => {
@ -208,12 +177,12 @@ export class ThemeManager {
if (!el.querySelector('.content')) {
const content = document.createElement('span');
content.className = 'content';
// 将原有内容移动到新的 span 中
while (el.firstChild) {
content.appendChild(el.firstChild);
}
el.appendChild(content);
const after = document.createElement('span');
@ -314,6 +283,15 @@ export class ThemeManager {
}
});
}
// 移除不再需要的方法
public setFont(fontFamily: string) {
this.currentFont = fontFamily;
}
public setFontSize(size: number) {
this.currentFontSize = size;
}
}
export const themeManager = (app: App) => new ThemeManager(app);
export const themeManager = (app: App, settingsManager: SettingsManager) => new ThemeManager(app, settingsManager);

View file

@ -3,7 +3,7 @@ import { RedConverter } from './converter';
import { DownloadManager } from './downloadManager';
import type { ThemeManager } from './themeManager';
import { DonateManager } from './donateManager';
import type { SettingsManager } from './settings';
import type { SettingsManager } from './settings/settings';
import { ClipboardManager } from './clipboardManager';
import { ImgTemplateManager } from './imgTemplateManager';
@ -595,9 +595,7 @@ export class RedView extends ItemView {
}
private async getThemeOptions() {
await this.themeManager.loadThemes();
const templates = this.themeManager.getAllThemes();
const templates = this.settingsManager.getAllThemes();
return templates.length > 0
? templates.map(t => ({ value: t.id, label: t.name }))
: [{ value: 'default', label: '默认主题' }];

View file

@ -1,869 +0,0 @@
/* 状态栏样式覆盖 */
.red-view-content {
height: 100%;
padding: 10px 10px 0 10px;
overflow: auto;
background: var(--background-primary);
}
/* ===== 工具栏 ===== */
.red-toolbar, .red-bottom-bar {
padding: 15px 0;
max-width: 580px;
}
.red-toolbar {
top: 0;
border-radius: 8px;
border-bottom: 2px solid var(--background-modifier-border);
}
.red-bottom-bar {
bottom: 0;
border-radius: 8px;
border-top: 2px solid var(--background-modifier-border);
}
/* 控件组布局 */
.red-controls-group {
display: flex;
gap: 12px;
align-items: center;
width: 100%;
justify-content: flex-start; /* 改为靠左对齐 */
flex-wrap: nowrap;
min-width: 0;
}
/* ===== 按钮基础样式 ===== */
.red-controls-group button {
height: 36px;
border-radius: 8px;
border: 1px solid var(--background-modifier-border);
background: var(--background-primary);
color: var(--text-normal);
font-size: 14px;
box-shadow: 0 1px 3px var(--background-modifier-box-shadow);
flex: 1;
white-space: nowrap;
overflow: hidden;
}
/* 按钮文本样式 */
.red-controls-group button span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.red-controls-group button:hover {
background: var(--background-modifier-hover);
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--background-modifier-box-shadow);
}
.red-controls-group button:disabled {
opacity: 0.5;
background: var(--background-primary) !important;
color: var(--text-muted) !important;
cursor: not-allowed !important;
transform: none;
border-color: var(--background-modifier-border) !important;
box-shadow: none;
}
/* 特殊按钮样式 */
.red-controls-group .red-lock-button,
.red-controls-group .red-help-button {
width: 36px;
margin: 0 20px 0 10px;
flex: none ;
}
.red-controls-group .red-export-button {
background-color: var(--text-accent);
color: var(--text-on-accent);
border: none;
}
.red-controls-group .red-export-button:hover {
color: var(--text-on-accent);
background-color: var(--text-accent);
}
/* ===== 下拉选择器 ===== */
.red-select-container {
position: relative;
max-width: 200px;
flex: 1;
}
.red-select {
height: 36px;
padding: 0 12px;
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
background: var(--background-primary);
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
user-select: none;
transition: all 0.2s ease;
color: var(--text-normal);
box-shadow: 0 1px 3px var(--background-modifier-box-shadow);
white-space: nowrap;
overflow: hidden;
}
.red-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
}
.red-select:hover {
background: var(--background-modifier-hover);
box-shadow: 0 2px 6px var(--background-modifier-box-shadow);
}
.red-select.disabled {
opacity: 0.5;
background: var(--background-secondary) !important;
color: var(--text-muted) !important;
border-color: var(--background-modifier-border) !important;
cursor: not-allowed;
box-shadow: none;
}
.red-select-arrow {
color: var(--text-normal);
font-size: 12px;
transition: transform 0.2s ease;
margin-left: 4px;
flex-shrink: 0;
}
.red-select-dropdown {
position: absolute;
top: calc(100% + 4px);
left: 0;
width: 100%;
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
box-shadow: 0 4px 12px var(--background-modifier-box-shadow);
display: none;
z-index: 1000;
overflow: hidden;
}
.red-select-dropdown.red-show {
display: block;
}
.red-select-item {
padding: 8px 12px;
cursor: pointer;
transition: all 0.2s ease;
color: var(--text-normal);
}
.red-select-item:hover {
background: var(--background-modifier-hover);
}
.red-select-item.red-selected {
background: var(--background-modifier-hover);
color: var(--text-accent);
}
/* ===== 字号调整组件 ===== */
.red-font-size-group {
height: 36px;
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
background: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: 8px;
padding: 0;
overflow: hidden;
box-shadow: 0 1px 3px var(--background-modifier-box-shadow);
}
.red-font-size-input {
width: 50px;
text-align: center;
}
/* ===== 帮助提示 ===== */
.red-help-tooltip {
position: absolute;
left: 30px;
bottom: 80px;
width: 450px;
padding: 12px 16px;
background: var(--background-primary);
border: 2px solid var(--background-modifier-border);
border-radius: 8px;
box-shadow: 0 4px 12px var(--background-modifier-box-shadow);
font-size: 13px;
line-height: 1.6;
color: var(--text-normal);
display: none;
white-space: pre-line;
z-index: 1000;
}
.red-help-button:hover + .red-help-tooltip {
display: block;
}
/* 预览区域 */
.red-preview-wrapper {
padding: 10px 20px 20px 20px;
margin: 10px;
height: calc(100% - 180px);
overflow-y: auto;
background: var(--background-primary);
flex: 1;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
border: 1px solid rgba(82, 144, 220, 0.1);
}
.red-empty-state {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
color: #999;
font-size: 16px;
}
/* 关于作者的框 */
.red-about-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--background-modifier-cover);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
/* 弹框主体 */
.red-about-modal {
background: var(--background-primary);
border-radius: 12px;
padding: 20px 20px;
width: 520px;
max-height: 90vh;
position: relative;
display: flex;
flex-direction: column;
gap: 10px;
overflow-y: auto;
}
/* 自定义滚动条样式 */
.red-about-modal::-webkit-scrollbar {
width: 8px;
}
.red-about-modal::-webkit-scrollbar-track {
background: var(--background-primary-alt);
border-radius: 4px;
}
.red-about-modal::-webkit-scrollbar-thumb {
background: var(--background-modifier-border);
border-radius: 4px;
}
.red-about-modal::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* 关闭按钮 */
.red-about-close {
position: absolute;
top: 7px;
right: 7px;
width: 28px;
height: 28px;
background: transparent;
border: none;
border-radius: 6px;
font-size: 17px;
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
/* macOS 系统下的样式 */
@media screen and (-webkit-min-device-pixel-ratio: 0) and (min-color-index:0) {
.red-about-close {
right: auto;
left: 7px;
}
}
.red-about-close:hover {
background: var(--background-primary-alt);
color: var(--text-normal);
}
/* 内容区块 */
.red-about-section {
padding: 10px;
margin: 8px 20px 0 20px;
border-radius: 8px;
}
.red-about-intro-section {
background: #fafafa;
border: 1px solid #f0f0f0;
}
.red-about-donate-section {
background: #fff9f5;
border: 1px solid #ffe4d9;
}
.red-about-mp-section {
background: #f5fff7;
border: 1px solid #e6f7e9;
}
/* 文字样式 */
.red-about-title {
font-size: 20px;
font-weight: 600;
color: var(--text-normal);
margin: 0 0 1px;
text-align: center;
letter-spacing: 0.5px;
}
.red-about-name {
color: var(--text-accent);
font-weight: 600;
font-size: 16px;
padding: 0 2px;
}
.red-about-identity {
color: var(--text-normal);
font-weight: 500;
background: var(--background-primary-alt);
padding: 0 4px;
border-radius: 3px;
}
.red-about-highlight {
color: var(--text-accent);
font-weight: 500;
}
.red-about-value {
color: var(--text-accent);
font-weight: 500;
}
.red-about-subtitle {
font-size: 18px;
color: var(--text-accent);
margin: 8px 0 12px;
letter-spacing: 0.3px;
font-weight: 600;
}
.red-about-intro {
font-size: 15px;
color: var(--text-normal);
margin: 8px 0;
line-height: 1.8;
letter-spacing: 0.2px;
}
.red-about-role,
.red-about-desc {
font-size: 14.5px;
color: var(--text-muted);
margin: 6px 0;
line-height: 1.8;
letter-spacing: 0.2px;
}
.red-about-emphasis {
font-weight: 500;
color: var(--text-error);
}
.red-about-footer {
font-size: 15px;
color: var(--text-normal);
text-align: center;
margin: 1px 0 0;
padding: 1px 1px;
background: var(--background-primary-alt);
border-radius: 8px;
font-weight: 500;
letter-spacing: 0.3px;
line-height: 1.6;
}
.red-about-footer strong {
color: var(--text-accent);
font-weight: 600;
}
/* 二维码容器 */
.red-about-qr {
width: 100%;
height: 150px;
margin: 5px 0;
padding: 5px;
background: var(--background-primary);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.red-about-qr img {
width: 100%;
height: 100%;
object-fit: contain;
}
/* 小红书预览容器 */
.red-preview-container {
position: relative;
min-width: 490px;
height: 100%;
display: flex;
justify-content: center;
align-items: flex-start;
background: var(--background-primary-alt);
border-radius: 12px;
padding: 20px;
overflow: auto;
}
.red-preview-header{
padding-bottom: 10px;
}
/* 图片预览区域 */
.red-image-preview {
width: 100%;
max-width: 450px;
aspect-ratio: 3/4;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
padding: 20px;
position: relative;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 内容区域容器 */
.red-content-wrapper {
flex: 1;
overflow: hidden;
}
/* 导航按钮 */
.red-nav-button {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 20px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.red-nav-button:hover {
background: white;
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 页码指示器 */
.red-page-indicator {
padding: 6px 12px;
background: rgba(255, 255, 255, 0.9);
border-radius: 16px;
font-size: 14px;
color: #333;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* 导航容器 */
.red-nav-container {
position: fixed;
bottom: 120px; /* 调整位置避免与底部工具栏重叠 */
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
z-index: 100;
padding: 10px;
background: rgba(255, 255, 255, 0.1); /* 半透明背景 */
backdrop-filter: blur(8px); /* 毛玻璃效果 */
border-radius: 20px;
}
.red-nav-button {
width: 40px;
height: 40px;
border: none;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
color: #333;
font-size: 20px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(4px);
}
.red-nav-button:hover {
background: white;
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 内容区块样式 */
.red-content-section {
display: none;
margin: 0 13px;
}
.red-content-section[data-index="0"] {
display: block;
}
/* 空状态提示 */
.red-empty-message {
text-align: center;
padding: 40px 20px;
color: var(--text-error);
font-size: 15px;
background: var(--background-primary-alt);
border: 1px dashed var(--background-modifier-border);
border-radius: 12px;
margin: 40px auto;
max-width: 320px;
line-height: 1.8;
white-space: pre-line;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 用户信息区域样式 */
.red-user-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 12px 3px 12px;
line-height: normal;
}
.red-user-left {
display: flex;
align-items: center;
gap: 12px;
}
.red-user-avatar {
width: 42px;
height: 42px;
border-radius: 50%;
overflow: hidden;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.red-user-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
}
.red-avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--background-primary-alt);
border-radius: 50%;
transition: all 0.3s ease;
}
.red-avatar-upload-icon {
font-size: 20px;
opacity: 0.6;
}
.red-avatar-placeholder:hover {
background-color: var(--background-modifier-border);
}
.red-avatar-placeholder:hover .red-avatar-upload-icon {
opacity: 0.8;
}
.red-user-meta {
display: flex;
flex-direction: column;
gap: 1px;
}
.red-user-name-container {
display: flex;
align-items: center;
gap: 4px;
}
.red-user-name {
font-size: 16px;
font-weight: 600;
color: var(--text-normal);
cursor: pointer;
}
.red-user-id {
font-size: 14px;
color: var(--text-muted);
cursor: pointer;
}
.red-user-right {
color: var(--text-muted);
font-size: 14px;
}
/* 编辑输入框样式 */
.red-user-edit-input {
border: none;
border-bottom: 1px solid var(--background-modifier-border);
outline: none;
padding: 2px 4px;
font-size: inherit;
font-family: inherit;
background: transparent;
color: var(--text-normal);
}
/* 悬停效果 */
.red-user-avatar:hover,
.red-user-name:hover,
.red-user-id:hover {
opacity: 0.8;
}
/* 代码块样式 */
.red-code-dots {
margin: 8px 0 12px 0;
display: flex;
gap: 6px;
}
.red-code-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.red-code-dot-red { background-color: #ff5f56; }
.red-code-dot-yellow { background-color: #ffbd2e; }
.red-code-dot-green { background-color: #27c93f; }
/* 链接样式 */
.red-link {
color: var(--text-accent);
text-decoration: none;
}
/* 表格样式 */
.red-table {
border-collapse: collapse;
margin: 1em 0;
width: 100%;
}
.red-table th,
.red-table td {
border: 1px solid var(--background-modifier-border);
padding: 8px;
}
/* 分割线样式 */
.red-hr {
border: none;
border-top: 1px solid var(--background-modifier-border);
margin: 20px 0;
}
/* 删除线样式 */
.red-del {
text-decoration: line-through;
}
/* 任务列表样式 */
.red-task-list-item {
list-style: none;
}
.red-task-list-item input[type="checkbox"] {
margin-right: 6px;
}
/* 脚注样式 */
.red-footnote {
color: var(--text-accent);
text-decoration: none;
}
/* 图片样式 */
.red-image {
max-width: 100%;
height: auto;
display: block;
margin: 1em auto;
}
/* 代码块容器样式 */
.red-pre {
padding-top: 32px;
}
.red-section-active {
display: block;
}
.red-preview-container section:not(.red-section-active) {
display: none;
}
.red-nav-hidden {
visibility: hidden;
}
.red-section-visible {
display: block !important;
}
.red-section-hidden {
display: none !important;
}
/* 复制按钮样式 */
.red-copy-button {
position: absolute;
top: 24px;
right: 30px;
z-index: 100;
background-color: var(--background-primary);
color: var(--text-normal);
border: none;
border-radius: 4px;
padding: 5px 8px;
font-size: 16px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease;
}
.red-preview-container:hover .red-copy-button {
opacity: 1;
}
.red-copy-button:hover {
background-color: var(--background-primary-alt);
}
.red-copy-button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
/* 备忘录风格样式 */
.red-notes-header .red-notes-bar {
position: relative;
height: 30px;
padding: 30px 0 0 0; /* 增加底部内边距 */
color: #f8c744;
font-size: 17px;
}
.red-notes-bar:before {
content: "备忘录";
position: absolute;
left: 0;
top: 3px;
height: 24px;
line-height: 28px;
padding-left: 24px;
width: 120px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='rgb(248, 199, 68)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 18-6-6 6-6'%3E%3C/path%3E%3C/svg%3E");
background-repeat: no-repeat;
}
.red-notes-bar:after {
content: "";
position: absolute;
right: 0;
top: 3px;
width: 24px;
height: 24px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(248, 199, 68)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpath d='M17 12h.01'%3E%3C/path%3E%3Cpath d='M12 12h.01'%3E%3C/path%3E%3Cpath d='M7 12h.01'%3E%3C/path%3E%3C/svg%3E");
background-repeat: no-repeat;
}
.red-notes-actions {
position: absolute;
right: 60px;
top: 2px;
width: 24px;
height: 24px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(248, 199, 68)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8'%3E%3C/path%3E%3Cpolyline points='16 6 12 2 8 6'%3E%3C/polyline%3E%3Cline x1='12' x2='12' y1='2' y2='15'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat;
}