feat: Add status bar button, support one-button random, one-button save, one-button open settings

添加状态栏按钮,支持一键随机、一键保存、一键打开设置
This commit is contained in:
sean2077 2025-08-08 19:35:40 +08:00
parent dd4d3ef951
commit 6ae8d2c72b
9 changed files with 401 additions and 124 deletions

View file

@ -2,12 +2,13 @@
* -
*/
import { Command } from "obsidian";
import DynamicThemeBackgroundPlugin from "../plugin";
import type DynamicThemeBackgroundPlugin from "../plugin";
// 导入所有命令创建函数
import { createFetchWallpaperCommand } from "./fetch-wallpaper-command";
import { createNextBackgroundCommand } from "./next-background-command";
import { createOpenSettingsCommand } from "./open-settings-command";
import { createSaveBackgroundCommand } from "./save-background-command";
import { createTestBackgroundCommand } from "./test-background-command";
import { createToggleCommand } from "./toggle-command";
@ -21,6 +22,7 @@ export function registerCommands(plugin: DynamicThemeBackgroundPlugin): void {
createTestBackgroundCommand(plugin),
createFetchWallpaperCommand(plugin),
createOpenSettingsCommand(plugin),
createSaveBackgroundCommand(plugin),
];
commands.forEach((command) => {

View file

@ -0,0 +1,16 @@
/**
*
*/
import { Command } from "obsidian";
import { t } from "../i18n";
import DynamicThemeBackgroundPlugin from "../plugin";
export function createSaveBackgroundCommand(plugin: DynamicThemeBackgroundPlugin): Command {
return {
id: "save-current-background",
name: t("command_save_current_background_name"),
callback: async () => {
await plugin.saveBackground();
},
};
}

View file

@ -12,6 +12,7 @@ let DEFAULT_SETTINGS: DTBSettings;
function genDefaultSettings(): DTBSettings {
DEFAULT_SETTINGS = {
enabled: true,
statusBarEnabled: true, // 是否激活状态栏
// 全局背景模糊度、亮度和饱和度变量、背景颜色等
blurDepth: 0,
@ -84,6 +85,7 @@ function genDefaultSettings(): DTBSettings {
intervalMinutes: 60,
// 背景管理
localBackgroundFolder: "",
backgrounds: [
{
id: "blue-purple-gradient",

View file

@ -10,6 +10,10 @@ export default {
enable_plugin_desc: "Turn the dynamic background feature on or off.",
basic_settings_title: "Basic Settings",
reload_plugin_tooltip: "Refresh Background",
enable_status_bar_name: "Enable Status Bar",
enable_status_bar_desc: "Turn the status bar feature on or off.",
status_bar_title:
"🖱Left Click: Switch Random Wallpaper\n🖱Middle Click: Open Settings Tab\n🖱Right Click: Save Current Background",
// ===== 外观设置 =====
appearance_settings_title: "Appearance Settings",
@ -75,12 +79,12 @@ export default {
add_folder_bg_button: "Add Image Folder",
restore_default_bg_button: "Restore Defaults",
restore_default_bg_tooltip: "Add default gradient backgrounds to the list",
restore_default_bg_success: "Successfully added {count} default backgrounds",
restore_default_bg_success: "🎉 Successfully added {count} default backgrounds",
restore_default_bg_no_new: "All default backgrounds already exist in the list",
add_folder_modal_title: "Add Images from Folder",
folder_path_label: "Folder Path (vault internal path):",
folder_path_placeholder: "e.g., assets/images or photos",
folder_scan_success: "Successfully added {count} images from folder",
folder_scan_success: "🎉 Successfully added {count} images from folder",
folder_scan_error: "Failed to scan folder: {error}",
folder_not_found: "Folder not found or empty",
folder_no_new_images: "All images in this folder already exist in the background list",
@ -93,12 +97,14 @@ export default {
color_value_label: "Color value (e.g. #ff0000):",
gradient_css_label: "CSS gradient (e.g. linear-gradient(45deg, #ff0000, #0000ff)):",
select_background_option: "Select Background",
drag_hint_text: "💡 Tip: You can drag background items to reorder them",
background_management_hint: "💡 Tip: You can drag background items to reorder them",
drag_handle_tooltip: "Drag to reorder",
random_wallpaper_settings_title: "Random Wallpaper Settings",
enable_random_wallpaper_name: "Enable Random Wallpaper",
enable_random_wallpaper_desc:
"When enabled, random wallpapers will be fetched from wallpaper APIs and the background list, otherwise it will use the background list in order.",
save_image_path_title: "Save Image Path",
save_image_path_placeholder: "Enter the path to save the image",
// ===== 壁纸API管理 =====
wallpaper_api_management_title: "Wallpaper API Management",
@ -121,20 +127,21 @@ export default {
// ===== 命令相关 =====
command_open_settings_tab_name: "Open Settings in New Tab",
command_toggle_name: "Toggle dynamic background",
command_toggle_enabled_notice: "Dynamic background enabled",
command_toggle_disabled_notice: "Dynamic background disabled",
command_toggle_enabled_notice: "✅ DTB: Dynamic background enabled",
command_toggle_disabled_notice: "❌ DTB: Dynamic background disabled",
command_next_bg_name: "Switch to next background",
command_next_bg_notice: "Background switched to: {bgName}",
command_next_bg_notice: "🎨 DTB: Background switched to: {bgName}",
command_test_bg_name: "Test current time period background",
command_test_bg_success_notice: "Current period: {ruleName}, Background: {bgName}",
command_test_bg_no_bg_notice: "No background set for period {ruleName}",
command_test_bg_no_rule_notice: "No matching rule for the current time",
command_test_bg_not_supported_notice: "Current mode does not support background testing",
command_test_bg_success_notice: "🕒 DTB: Current period: {ruleName}, Background: {bgName}",
command_test_bg_no_bg_notice: "⚠️ DTB: No background set for period {ruleName}",
command_test_bg_no_rule_notice: "⚠️ DTB: No matching rule for the current time",
command_test_bg_not_supported_notice: "⚠️ DTB: Current mode does not support background testing",
command_fetch_random_wallpaper_name: "Fetch Random Wallpaper",
command_fetch_random_wallpaper_notice_disabled: "Please enable random wallpaper feature in settings first",
command_fetch_random_wallpaper_notice_success: "Applied random wallpaper",
command_fetch_random_wallpaper_notice_disabled: "⚠️ DTB: Please enable random wallpaper feature in settings first",
command_fetch_random_wallpaper_notice_success: "🎉 DTB: Applied random wallpaper",
command_fetch_random_wallpaper_notice_failed:
"Failed to fetch random wallpaper, please check API settings and network connection",
"❌ DTB: Failed to fetch random wallpaper, please check API settings and network connection",
command_save_current_background_name: "Save Current Background",
// ===== 通用按钮文本 =====
button_cancel: "Cancel",
@ -146,6 +153,7 @@ export default {
button_test: "Test",
button_update: "Update",
button_add: "Add",
button_save: "Save",
// ===== 默认配置相关 =====
default_morning_rule: "Morning",
@ -164,24 +172,31 @@ export default {
dark_blue_gray_gradient_bg: "Dark Blue Gray Gradient",
// ===== Notice 消息 =====
notice_all_fields_required: "Please provide all required fields",
notice_name_and_value_required: "Please provide both name and value",
notice_valid_folder_path_required: "Please provide a valid folder path",
notice_folder_not_found: "Folder not found",
notice_folder_added_successfully: 'Images from folder "{folderPath}" added successfully',
notice_error_adding_folder_images: "Error adding images from folder",
notice_api_failed_enable_disable: "❌ Failed to {action} {apiName}",
notice_api_success_enable_disable: "✅ Successfully {action} {apiName}",
notice_api_error_enable_disable: "❌ Error {action} {apiName}",
notice_api_disabled: "❌ {apiName}: API is disabled",
notice_api_fetching: "🔄 Fetching wallpaper from {apiName}...",
notice_api_success_applied: "✅ Successfully applied wallpaper from {apiName}",
notice_api_failed_fetch: "❌ Failed to fetch wallpaper from {apiName}",
notice_api_error_fetch: "❌ Error fetching wallpaper from {apiName}: {error}",
notice_api_fetching_generic: "🔄 Fetching wallpaper from API...",
notice_api_success_applied_generic: "✅ Successfully applied random wallpaper!",
notice_api_no_available: "❌ No wallpaper APIs available or all APIs failed",
notice_api_error_generic: "❌ Error fetching wallpaper from API",
notice_all_fields_required: "⚠️ DTB: Please provide all required fields",
notice_name_and_value_required: "⚠️ DTB: Please provide both name and value",
notice_valid_folder_path_required: "⚠️ DTB: Please provide a valid folder path",
notice_folder_not_found: "❌ DTB: Folder not found",
notice_folder_added_successfully: '🎉 DTB: Images from folder "{folderPath}" added successfully',
notice_error_adding_folder_images: "❌ DTB: Error adding images from folder",
notice_api_failed_enable_disable: "❌ DTB: Failed to {action} {apiName}",
notice_api_success_enable_disable: "🎉 DTB: Successfully {action} {apiName}",
notice_api_error_enable_disable: "❌ DTB: Error {action} {apiName}",
notice_api_disabled: "❌ DTB: {apiName}: API is disabled",
notice_api_fetching: "🔄 DTB: Fetching wallpaper from {apiName}...",
notice_api_success_applied: "🎉 DTB: Successfully applied wallpaper from {apiName}",
notice_api_failed_fetch: "❌ DTB: Failed to fetch wallpaper from {apiName}",
notice_api_error_fetch: "❌ DTB: Error fetching wallpaper from {apiName}: {error}",
notice_api_fetching_generic: "🔄 DTB: Fetching wallpaper from API...",
notice_api_success_applied_generic: "🎉 DTB: Successfully applied random wallpaper!",
notice_api_no_available: "❌ DTB: No wallpaper APIs available or all APIs failed",
notice_api_error_generic: "❌ DTB: Error fetching wallpaper from API",
notice_save_background_no_need_save_local: "🎉 DTB: Current background is a local image, no need to save",
notice_save_background_valid_folder_path_required:
"⚠️ DTB: Please provide a valid folder path to save the wallpaper",
notice_save_background_only_image_supported: "⚠️ DTB: Only image backgrounds are supported for saving",
notice_save_background_success: "🎉 DTB: Current background saved to {folderPath}",
notice_save_background_failed:
"❌ DTB: Failed to save current background, please check folder path and permissions",
// ===== API 模态窗口 =====
api_modal_invalid_json: "Invalid JSON in extra parameters",
@ -189,7 +204,7 @@ export default {
api_modal_invalid_params: "Invalid API parameters: {errors}",
api_modal_testing_config: "Testing API configuration...",
api_modal_cannot_test_invalid: "Cannot test due to invalid configuration",
api_modal_test_successful: "API test successful!",
api_modal_test_successful: "🎉 API test successful!",
api_modal_test_failed: "API test failed: {error}",
api_modal_api_url: "API URL",
api_modal_headers_optional: "Headers (optional)",

View file

@ -10,6 +10,9 @@ export default {
enable_plugin_desc: "开启或关闭动态背景功能",
basic_settings_title: "基础设置",
reload_plugin_tooltip: "刷新背景",
enable_status_bar_name: "启用状态栏",
enable_status_bar_desc: "开启或关闭状态栏功能: ",
status_bar_title: "🖱️左键:切换随机壁纸\n🖱中键打开设置标签页\n🖱右键保存当前背景",
// ===== 外观设置 =====
appearance_settings_title: "外观设置",
@ -70,12 +73,12 @@ export default {
add_folder_bg_button: "添加图片文件夹",
restore_default_bg_button: "恢复默认",
restore_default_bg_tooltip: "将默认渐变背景添加到列表中",
restore_default_bg_success: "成功添加了 {count} 个默认背景",
restore_default_bg_success: "🎉 成功添加了 {count} 个默认背景",
restore_default_bg_no_new: "所有默认背景已存在于列表中",
add_folder_modal_title: "从文件夹添加图片",
folder_path_label: "文件夹路径(库内路径):",
folder_path_placeholder: "例如assets/images 或 photos",
folder_scan_success: "成功从文件夹添加了 {count} 张图片",
folder_scan_success: "🎉 成功从文件夹添加了 {count} 张图片",
folder_scan_error: "扫描文件夹失败:{error}",
folder_not_found: "文件夹未找到或为空",
folder_no_new_images: "此文件夹中的所有图片已存在于背景列表中",
@ -88,11 +91,13 @@ export default {
color_value_label: "颜色值(如 #ff0000",
gradient_css_label: "CSS 渐变(如 linear-gradient(45deg, #ff0000, #0000ff)",
select_background_option: "选择背景",
drag_hint_text: "💡 提示:您可以拖拽背景项目来重新排序",
background_management_hint: "💡 提示:您可以拖拽背景项目来重新排序",
drag_handle_tooltip: "拖拽以重新排序",
random_wallpaper_settings_title: "随机壁纸设置",
enable_random_wallpaper_name: "启用随机壁纸",
enable_random_wallpaper_desc: "启用后,将从壁纸网站 API 和背景列表中获取随机壁纸,否则将从背景列表按顺序获取",
save_image_path_title: "保存图片路径",
save_image_path_placeholder: "请输入保存图片的路径",
// ===== 壁纸API管理 =====
wallpaper_api_management_title: "壁纸 API 管理",
@ -112,19 +117,20 @@ export default {
// ===== 命令相关 =====
command_open_settings_tab_name: "在新标签页中打开设置",
command_toggle_name: "切换动态背景开关",
command_toggle_enabled_notice: "动态背景已启用",
command_toggle_disabled_notice: "动态背景已禁用",
command_toggle_enabled_notice: "✅ DTB: 动态背景已启用",
command_toggle_disabled_notice: "❌ DTB: 动态背景已禁用",
command_next_bg_name: "切换到下一个背景",
command_next_bg_notice: "背景已切换为:{bgName}",
command_next_bg_notice: "🔄 DTB: 背景已切换为:{bgName}",
command_test_bg_name: "测试当前时间段背景",
command_test_bg_success_notice: "当前时间段:{ruleName},背景:{bgName}",
command_test_bg_no_bg_notice: "时间段 {ruleName} 没有设置背景",
command_test_bg_no_rule_notice: "当前时间没有匹配的规则",
command_test_bg_not_supported_notice: "非时段模式不支持该测试命令",
command_test_bg_success_notice: "🕒 DTB: 当前时间段:{ruleName},背景:{bgName}",
command_test_bg_no_bg_notice: "⚠️ DTB: 时间段 {ruleName} 没有设置背景",
command_test_bg_no_rule_notice: "⚠️ DTB: 当前时间没有匹配的规则",
command_test_bg_not_supported_notice: "🚫 DTB: 非时段模式不支持该测试命令",
command_fetch_random_wallpaper_name: "获取随机壁纸",
command_fetch_random_wallpaper_notice_disabled: "请先在设置中启用随机壁纸功能",
command_fetch_random_wallpaper_notice_success: "已应用随机壁纸",
command_fetch_random_wallpaper_notice_failed: "获取随机壁纸失败,请检查 API 设置和网络连接",
command_fetch_random_wallpaper_notice_disabled: "⚠️ DTB: 请先在设置中启用随机壁纸功能",
command_fetch_random_wallpaper_notice_success: "✅ DTB: 已应用随机壁纸",
command_fetch_random_wallpaper_notice_failed: "❌ DTB: 获取随机壁纸失败,请检查 API 设置和网络连接",
command_save_current_background_name: "保存当前背景",
// ===== 通用按钮文本 =====
button_cancel: "取消",
@ -136,6 +142,7 @@ export default {
button_test: "测试",
button_update: "更新",
button_add: "添加",
button_save: "保存",
// ===== 默认配置相关 =====
default_morning_rule: "清晨",
@ -154,24 +161,29 @@ export default {
dark_blue_gray_gradient_bg: "深蓝灰色渐变",
// ===== Notice 消息 =====
notice_all_fields_required: "请提供所有必填字段",
notice_name_and_value_required: "请提供名称和值",
notice_valid_folder_path_required: "请提供有效的文件夹路径",
notice_folder_not_found: "文件夹未找到",
notice_folder_added_successfully: '成功从文件夹 "{folderPath}" 添加图片',
notice_error_adding_folder_images: "添加文件夹图片时出错",
notice_api_failed_enable_disable: "❌ 无法{action} {apiName}",
notice_api_success_enable_disable: "✅ 成功{action} {apiName}",
notice_api_error_enable_disable: "❌ {action} {apiName} 时出错",
notice_api_disabled: "❌ {apiName}: API 已禁用",
notice_api_fetching: "🔄 正在从 {apiName} 获取壁纸...",
notice_api_success_applied: "✅ 成功应用来自 {apiName} 的壁纸",
notice_api_failed_fetch: "❌ 从 {apiName} 获取壁纸失败",
notice_api_error_fetch: "❌ 从 {apiName} 获取壁纸时出错:{error}",
notice_api_fetching_generic: "🔄 正在从 API 获取壁纸...",
notice_api_success_applied_generic: "✅ 成功应用随机壁纸!",
notice_api_no_available: "❌ 没有可用的壁纸 API 或所有 API 都失败了",
notice_api_error_generic: "❌ 从 API 获取壁纸时出错",
notice_all_fields_required: "⚠️ 请提供所有必填字段",
notice_name_and_value_required: "⚠️ 请提供名称和值",
notice_valid_folder_path_required: "⚠️ 请提供有效的文件夹路径",
notice_folder_not_found: "❌ 文件夹未找到",
notice_folder_added_successfully: '🎉 成功从文件夹 "{folderPath}" 添加图片',
notice_error_adding_folder_images: "❌ 添加文件夹图片时出错",
notice_api_failed_enable_disable: "❌ DTB: 无法{action} {apiName}",
notice_api_success_enable_disable: "🎉 DTB: 成功{action} {apiName}",
notice_api_error_enable_disable: "❌ DTB: {action} {apiName} 时出错",
notice_api_disabled: "❌ DTB: {apiName}: API 已禁用",
notice_api_fetching: "🔄 DTB: 正在从 {apiName} 获取壁纸...",
notice_api_success_applied: "🎉 DTB: 成功应用来自 {apiName} 的壁纸",
notice_api_failed_fetch: "❌ DTB: 从 {apiName} 获取壁纸失败",
notice_api_error_fetch: "❌ DTB: 从 {apiName} 获取壁纸时出错:{error}",
notice_api_fetching_generic: "🔄 DTB: 正在从 API 获取壁纸...",
notice_api_success_applied_generic: "🎉 DTB: 成功应用随机壁纸!",
notice_api_no_available: "❌ DTB: 没有可用的壁纸 API 或所有 API 都失败了",
notice_api_error_generic: "❌ DTB: 从 API 获取壁纸时出错",
notice_save_background_no_need_save_local: "🎉 DTB: 当前背景是本地图片,无需保存",
notice_save_background_valid_folder_path_required: "⚠️ 请提供有效的保存壁纸的文件夹路径",
notice_save_background_only_image_supported: "⚠️ DTB: 仅支持保存图片作为壁纸",
notice_save_background_success: "🎉 DTB: 当前背景已保存至 {folderPath}",
notice_save_background_failed: "❌ DTB: 当前背景保存失败,请检查文件夹路径和权限",
// ===== API 模态窗口 =====
api_modal_invalid_json: "额外参数中的 JSON 格式无效",
@ -179,7 +191,7 @@ export default {
api_modal_invalid_params: "无效的 API 参数:{errors}",
api_modal_testing_config: "正在测试 API 配置...",
api_modal_cannot_test_invalid: "由于配置无效无法测试",
api_modal_test_successful: "API 测试成功!",
api_modal_test_successful: "🎉 API 测试成功!",
api_modal_test_failed: "API 测试失败:{error}",
api_modal_api_url: "API 地址",
api_modal_headers_optional: "请求头(可选)",

View file

@ -1,10 +1,11 @@
/**
* -
*/
import { Plugin } from "obsidian";
import { Notice, Plugin, requestUrl } from "obsidian";
import { registerCommands } from "./commands";
import { getDefaultSettings } from "./default-settings";
import { t } from "./i18n";
import { DTBSettingTab, DTBSettingsView, DTB_SETTINGS_VIEW_TYPE } from "./settings";
import type { BackgroundItem, DTBSettings, TimeRule } from "./types";
import { hexToRgba } from "./utils";
@ -18,6 +19,8 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
intervalId: number | null = null; // 用于间隔模式的定时器 ID
timeoutId: number | null = null; // 用于时段规则的定时器 ID
statusBar: HTMLElement | null = null;
// ============================================================================
// 主要接口方法
// ============================================================================
@ -25,6 +28,16 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
async onload() {
await this.loadSettings();
// 左侧栏图标
this.addRibbonIcon("rainbow", "🌈 Obsidian DTB", async (evt: MouseEvent) => {
await this.applyRandomWallpaper();
});
// 状态栏
if (this.settings.statusBarEnabled) {
this.activateStatusBar();
}
// 注册自定义视图类型
this.registerView(DTB_SETTINGS_VIEW_TYPE, (leaf) => new DTBSettingsView(leaf, this));
@ -92,6 +105,38 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
this.app.workspace.revealLeaf(leaf);
}
/**
*
*/
deactivateStatusBar() {
this.statusBar?.empty();
}
/**
*
*/
activateStatusBar() {
this.deactivateStatusBar();
this.statusBar = this.addStatusBarItem();
this.statusBar.setText("🌈 DTB");
this.statusBar.addClass("dtb-status-bar");
this.statusBar.setAttribute("title", t("status_bar_title"));
this.statusBar.addEventListener("click", async (evt) => {
if (evt.button === 0) {
await this.applyRandomWallpaper();
}
});
this.statusBar.addEventListener("auxclick", async (evt) => {
if (evt.button === 1) {
await this.activateView();
}
});
this.statusBar.addEventListener("contextmenu", async (evt) => {
evt.preventDefault();
await this.saveBackground();
});
}
/**
*
*/
@ -211,43 +256,22 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
}
// 基于时间间隔切换
case "interval": {
// 检查是否启用随机壁纸
if (this.settings.enableRandomWallpaper) {
const randomWallpaperUrl = await this.fetchRandomWallpaper();
if (randomWallpaperUrl) {
// 创建一个临时的背景项用于随机壁纸
this.background = {
id: `random-wallpaper-${Date.now()}`,
name: `Random Wallpaper`,
type: "image",
value: randomWallpaperUrl,
};
needsUpdate = true;
console.debug("DTB: Interval mode - using random wallpaper", randomWallpaperUrl);
} else if (this.settings.backgrounds.length > 0) {
// API失败时回退到本地背景
this.settings.currentIndex =
(this.settings.currentIndex + 1) % this.settings.backgrounds.length;
this.background = this.settings.backgrounds[this.settings.currentIndex];
this.saveSettings();
needsUpdate = true;
console.debug("DTB: Interval mode - fallback to local background", this.background);
}
const randomWallpaperUrl = await this.fetchRandomWallpaper();
if (randomWallpaperUrl) {
// 创建一个临时的背景项用于随机壁纸
this.background = {
id: `random-wallpaper-${Date.now()}`,
name: `Random Wallpaper`,
type: "image",
value: randomWallpaperUrl,
};
needsUpdate = true;
} else if (this.settings.backgrounds.length > 0) {
// 使用本地背景
this.background = this.settings.backgrounds[this.settings.currentIndex];
// API失败时回退到本地背景
this.settings.currentIndex = (this.settings.currentIndex + 1) % this.settings.backgrounds.length;
this.background = this.settings.backgrounds[this.settings.currentIndex];
this.saveSettings();
needsUpdate = true; // 每次间隔切换都需要更新背景
console.debug(
"DTB: Interval mode - current index and background",
this.settings.currentIndex,
this.background
);
needsUpdate = true;
}
break;
}
@ -277,9 +301,7 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
});
} else {
const bgCssValue =
this.background.type === "image"
? this.sanitizeImagePath(this.background.value)
: this.background.value;
this.background.type === "image" ? this.getBgURL(this.background) : this.background.value;
// 模糊度、亮度、饱和度、遮罩颜色和透明度、填充方式的优先级统一为:
// 传入的自定义值 > 背景单独的设置 > 全局默认设置
const blurDepth = this.background.blurDepth ?? this.settings.blurDepth;
@ -312,6 +334,10 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
this.app.workspace.trigger("css-change", { source: "dtb" });
}
// ============================================================================
// 辅助方法
// ============================================================================
/**
* background-size
* @param imagePath
@ -404,6 +430,82 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
}
}
async applyRandomWallpaper() {
const randomWallpaperUrl = await this.fetchRandomWallpaper();
if (randomWallpaperUrl) {
// 创建一个临时的背景项用于随机壁纸
this.background = {
id: `random-wallpaper-${Date.now()}`,
name: `Random Wallpaper`,
type: "image",
value: randomWallpaperUrl,
};
} else if (this.settings.backgrounds.length > 0) {
// API失败时回退到本地背景
this.settings.currentIndex = (this.settings.currentIndex + 1) % this.settings.backgrounds.length;
this.background = this.settings.backgrounds[this.settings.currentIndex];
await this.saveSettings();
}
this.updateStyleCss();
}
/**
* ,
*/
async saveBackground(bg: BackgroundItem | null = this.background) {
if (!bg) return;
// 判断是否设置了 localBackgroundFolder
if (!this.settings.localBackgroundFolder) {
new Notice(t("notice_save_background_valid_folder_path_required"));
return;
}
// 判断是否是图片,非图片则不保存
if (bg.type !== "image") {
new Notice(t("notice_save_background_only_image_supported"));
return;
}
// 如果是本地图片,则不保存
if (!this.isRemoteImage(bg.value)) {
new Notice(t("notice_save_background_no_need_save_local"));
return;
}
const success = await this.saveRemoteImage(bg, this.settings.localBackgroundFolder);
if (!success) {
new Notice(t("notice_save_background_failed"));
return;
}
new Notice(t("notice_save_background_success", { folderPath: this.settings.localBackgroundFolder }));
}
async saveRemoteImage(bg: BackgroundItem, folderPath: string): Promise<boolean> {
if (!folderPath) {
new Notice(t("notice_save_background_valid_folder_path_required"));
return false;
}
// 默认图片名为 bg.name + .jpg , 并规范化路径 移除禁止的字符: \ / : * ? " < > |
const imageName = bg.name.replace(/[\\\/:\*\?"<>\|]/g, "_") + ".jpg";
const localPath = `${folderPath}/${imageName}`;
// 这里添加保存远程图片的逻辑
const response = await requestUrl({ url: bg.value });
if (response.status < 200 || response.status >= 300) {
new Notice(t("notice_save_background_failed"), response.status);
return false;
}
const arrayBuffer = response.arrayBuffer;
await this.app.vault.createBinary(localPath, arrayBuffer);
// 默认将bg中的url替换为本地路径并将remoteUrl设置为原始url以作备份
bg.remoteUrl = bg.value;
bg.value = localPath;
return true;
}
// 从壁纸API获取随机图片URL
async fetchRandomWallpaper(): Promise<string | null> {
if (!this.settings.enableRandomWallpaper) {
@ -443,28 +545,38 @@ export default class DynamicThemeBackgroundPlugin extends Plugin {
}
}
// ============================================================================
// 辅助方法
// ============================================================================
// 将图片路径转换为可用的 CSS URL
sanitizeImagePath(imagePath: string): string {
getBgURL(bg: BackgroundItem): string {
const imagePath = bg.value;
// 判断是否是远程图片
if (imagePath.startsWith("http://") || imagePath.startsWith("https://")) {
if (this.isRemoteImage(imagePath)) {
return `url(${imagePath})`;
}
// 本地图片路径(只接受 Vault 内的图片)
const file = this.app.vault.getFileByPath(imagePath);
if (!file) {
console.warn(`DTB: Image ${imagePath} not found`);
return "none";
if (file) {
const p = this.app.vault.getResourcePath(file);
if (p) {
return `url(${p})`;
}
} else {
console.warn(`DTB: Image ${imagePath} not found or inaccessible`);
}
const p = this.app.vault.getResourcePath(file);
if (!p) {
console.warn(`DTB: Cannot get resource path for image ${imagePath}`);
return "none";
// 如果 value 表示的本地路径无效,则查看 bg 有没有 remoteUrl 备份链接
if (bg.remoteUrl) {
// 这里恢复备份, 按理在这做不太合适
bg.value = bg.remoteUrl;
this.saveSettings(); // 保存设置
return `url(${bg.remoteUrl})`;
}
return `url(${p})`; // 形如 app://local/path/to/image.jpg
// 否则
return "none";
}
isRemoteImage(imagePath: string): boolean {
return imagePath.startsWith("http://") || imagePath.startsWith("https://");
}
/**

View file

@ -97,7 +97,7 @@ export class DTBSettingTab extends PluginSettingTab {
containerEl.empty();
containerEl.createEl("h3", { text: t("basic_settings_title") });
// 基础设置
// 是否启用插件
new Setting(containerEl)
.setName(t("enable_plugin_name"))
.setDesc(t("enable_plugin_desc"))
@ -126,6 +126,22 @@ export class DTBSettingTab extends PluginSettingTab {
})
);
// 是否开启状态栏
new Setting(containerEl)
.setName(t("enable_status_bar_name"))
.setDesc(t("enable_status_bar_desc") + t("status_bar_title").replace(/\n/g, " "))
.addToggle((toggle) =>
toggle.setValue(this.plugin.settings.statusBarEnabled).onChange(async (value) => {
this.plugin.settings.statusBarEnabled = value;
await this.plugin.saveSettings();
if (value) {
this.plugin.activateStatusBar();
} else {
this.plugin.deactivateStatusBar();
}
})
);
// 外观设置
containerEl.createEl("h4", { text: t("appearance_settings_title") });
// 背景模糊度设置
@ -539,9 +555,33 @@ export class DTBSettingTab extends PluginSettingTab {
// 背景管理
containerEl.createEl("h3", { text: t("bg_management_title") });
// 添加拖拽提示
const dragHint = containerEl.createDiv("dtb-hint");
dragHint.textContent = t("drag_hint_text");
// 保存远程图片的本地路径
const imageFolderInputContainer = containerEl.createDiv("setting-item dtb-flex-container-spaced");
imageFolderInputContainer.createEl("label", { text: t("save_image_path_title") });
const valueInput = imageFolderInputContainer.createEl("input", {
type: "text",
title: t("save_image_path_title"),
placeholder: t("save_image_path_placeholder"),
value: this.plugin.settings.localBackgroundFolder ?? "",
cls: "dtb-flex-1",
});
valueInput.oninput = () => {
this.plugin.settings.localBackgroundFolder = valueInput.value;
this.plugin.saveSettings();
};
const browseButton = imageFolderInputContainer.createEl("button", {
type: "button",
text: t("button_browse"),
cls: "dtb-button",
});
browseButton.onclick = () => {
const modal = new ImageFolderSuggestModal(this.app, (imagePath: string) => {
valueInput.value = imagePath;
this.plugin.settings.localBackgroundFolder = imagePath;
this.plugin.saveSettings();
});
modal.open();
};
// 添加背景的一组按钮
const buttonContainer = containerEl.createDiv("dtb-large-button-container");
@ -567,6 +607,10 @@ export class DTBSettingTab extends PluginSettingTab {
.onClick(() => this.restoreDefaultBackgrounds())
);
// 添加拖拽提示
const dragHint = containerEl.createDiv("dtb-hint");
dragHint.textContent = t("background_management_hint");
const backgroundContainer = containerEl.createDiv("dtb-section-container");
this.displayBackgrounds(backgroundContainer);
}
@ -739,13 +783,14 @@ export class DTBSettingTab extends PluginSettingTab {
contentDiv.createSpan({ text: bg.name, cls: "dtb-bg-name" });
contentDiv.createSpan({ text: bg.type, cls: "dtb-badge" });
// 预览
// 预览
const preview = contentDiv.createDiv("dtb-bg-preview");
this.setPreviewBackground(preview, bg);
// 操作按钮
const actions = contentDiv.createDiv("dtb-button-container");
// 预览按钮
actions.createEl("button", { text: t("button_preview") }).onclick = () => {
this.plugin.background = bg;
this.plugin.settings.currentIndex = index; // 更新当前索引
@ -753,10 +798,19 @@ export class DTBSettingTab extends PluginSettingTab {
this.plugin.updateStyleCss();
};
// 保存按钮
actions.createEl("button", { text: t("button_save") }).onclick = async () => {
await this.plugin.saveBackground(bg);
// 由于保存远程图片时会将本地图片路径替换为远程路径,因此需要更新设置
await this.plugin.saveSettings();
};
// 编辑按钮
actions.createEl("button", { text: t("button_edit") }).onclick = () => {
this.showEditBackgroundModal(bg, index);
};
// 删除按钮
actions.createEl("button", { text: t("button_delete") }).onclick = async () => {
// 使用 filter 方法删除
this.plugin.settings.backgrounds = this.plugin.settings.backgrounds.filter(
@ -786,7 +840,7 @@ export class DTBSettingTab extends PluginSettingTab {
switch (bg.type) {
case "image": {
preview.addClass("dtb-preview-image");
const sanitizedImagePath = this.plugin.sanitizeImagePath(bg.value);
const sanitizedImagePath = this.plugin.getBgURL(bg);
// 只有当图片路径有效时才设置 CSS 变量
if (sanitizedImagePath && sanitizedImagePath !== "none") {
preview.setCssProps({

View file

@ -7,6 +7,7 @@ import type { WallpaperApiConfig } from "./wallpaper-apis";
export interface DTBSettings {
enabled: boolean;
statusBarEnabled: boolean; // 是否激活状态栏
// 全局背景模糊度、亮度和饱和度变量、背景颜色
blurDepth: number; // 背景模糊度
@ -22,6 +23,7 @@ export interface DTBSettings {
intervalMinutes: number;
// 背景管理
localBackgroundFolder: string; // 保存远程背景图片的文件夹路径
backgrounds: BackgroundItem[];
currentIndex: number; // 当前背景索引
@ -44,7 +46,7 @@ export interface BackgroundItem {
name: string;
type: "image" | "color" | "gradient";
value: string; // image URL, color code, or gradient CSS
preview?: string;
remoteUrl?: string; // 作为备份防止一些远端保存到本地的图片删除后找不回来读取图片优先从value读取如果读取不到再从远端读取此种情况会将 remoteUrl 变更为 value
// 每个背景单独的模糊度、亮度和饱和度变量、遮罩颜色和透明度、填充方式,可覆盖全局设置
blurDepth?: number;

View file

@ -1041,3 +1041,65 @@
justify-content: space-between;
margin-bottom: 12px;
}
/* ===== 炫酷状态栏图标样式 ===== */
.dtb-status-bar {
display: flex;
align-items: center;
gap: 0.5em;
padding: 0.2em 1em 0.2em 0.8em;
border-radius: 1.2em;
font-weight: bold;
font-size: 1em;
background: var(--status-bar-background, rgba(40, 44, 52, 0.85));
color: var(--status-bar-text-color, var(--text-normal));
box-shadow: 0 1px 6px 0 rgba(80, 180, 255, 0.1);
border: 1px solid var(--background-modifier-border);
position: relative;
overflow: hidden;
transition:
box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
background 0.3s;
}
.dtb-status-bar:hover {
box-shadow:
0 2px 12px 0 rgba(80, 180, 255, 0.18),
0 0 8px 2px #91eac9;
background: linear-gradient(90deg, var(--status-bar-background, rgba(40, 44, 52, 0.92)) 60%, #91eac9 100%);
}
.dtb-status-bar .dtb-status-icon {
width: 1.4em;
height: 1.4em;
margin-right: 0.3em;
filter: drop-shadow(0 0 2px #91eac9);
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.dtb-status-bar:hover .dtb-status-icon {
transform: rotate(-12deg) scale(1.18);
}
.dtb-status-bar .dtb-status-text {
letter-spacing: 0.04em;
text-shadow: 0 1px 2px #0002;
font-size: 1em;
}
.dtb-status-bar .dtb-status-dot {
width: 0.7em;
height: 0.7em;
border-radius: 50%;
margin-left: 0.5em;
background: radial-gradient(circle, #91eac9 60%, var(--status-bar-background, #7f7fd5) 100%);
box-shadow: 0 0 4px 1px #91eac9;
animation: dtb-dot-pulse 1.2s infinite alternate;
}
@keyframes dtb-dot-pulse {
0% {
box-shadow:
0 0 8px 2px #91eac9,
0 0 2px 1px #fff8;
}
100% {
box-shadow:
0 0 16px 4px #91eac9,
0 0 4px 2px #fff8;
}
}