diff --git a/esbuild.config.mjs b/esbuild.config.mjs index f431974..c1323eb 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -53,6 +53,9 @@ const jsContext = await esbuild.context({ treeShaking: true, outfile: "dist/main.js", minify: prod, + loader: { + ".md": "text", + }, plugins: [copyPlugin], }); diff --git a/src/BanyanAppData.ts b/src/BanyanAppData.ts index 7e7ab23..0a68ace 100644 --- a/src/BanyanAppData.ts +++ b/src/BanyanAppData.ts @@ -4,10 +4,7 @@ import { DefaultRandomReviewFilter, RandomReviewFilter } from "./models/RandomRe import { SortType } from "./models/Enum"; import { getToday } from "./utils/utils"; -export const CUR_APP_DATA_VERSION = 1; - export interface BanyanAppData { - version: number; // in app sortType: SortType; firstUseDate: string; @@ -24,7 +21,6 @@ export interface BanyanAppData { export const DEFAULT_APP_DATA: BanyanAppData = { - version: CUR_APP_DATA_VERSION, // in app sortType: 'created', firstUseDate: getToday(), diff --git a/src/BanyanPlugin.ts b/src/BanyanPlugin.ts index 154f96b..52559f8 100644 --- a/src/BanyanPlugin.ts +++ b/src/BanyanPlugin.ts @@ -1,11 +1,13 @@ import { Plugin, WorkspaceLeaf } from 'obsidian'; import { BanyanPluginSettings, DEFAULT_SETTINGS, CUR_SETTINGS_VERSION } from './BanyanPluginSettings'; -import { BanyanAppData, DEFAULT_APP_DATA, CUR_APP_DATA_VERSION } from './BanyanAppData'; +import { BanyanAppData, DEFAULT_APP_DATA } from './BanyanAppData'; import { CARD_DASHBOARD_VIEW_TYPE, CardDashboard } from './pages/CardDashboard'; import { BanyanSettingTab } from './BanyanSettingTab'; import { FileUtils } from './utils/fileUtils'; import { i18n } from './utils/i18n'; import { TagFilter, isEmptyTagFilter } from './models/TagFilter'; +import { AnnouncementModal } from './components/AnnouncementModal'; +import { getWelcomeMarkdown, getChangelogMarkdown } from './utils/announcements'; export default class BanyanPlugin extends Plugin { @@ -82,6 +84,44 @@ export default class BanyanPlugin extends Plugin { }); } + checkAnnouncements = async () => { + const curVersion = this.manifest.version; + const lastVersion = this.settings.lastVersion; + const settingVersion = this.settings.settingsVersion; + + if ((!lastVersion || lastVersion === '') && settingVersion === CUR_SETTINGS_VERSION) { + // 初次启动 + const modal = new AnnouncementModal(this.app, { + type: 'welcome', + content: getWelcomeMarkdown(), + onClose: () => { + this.settings.lastVersion = curVersion; + this.saveSettings(); + } + }); + modal.open(); + } else if (lastVersion !== curVersion) { + // 版本更新 + const updateContent = getChangelogMarkdown(); + if (updateContent && updateContent.trim().length > 0) { + const modal = new AnnouncementModal(this.app, { + type: 'update', + content: updateContent, + onClose: () => { + this.settings.lastVersion = curVersion; + this.saveSettings(); + } + }); + modal.open(); + } else { + // 如果当前版本没有更新公告,也更新版本号,避免重复检查 + this.settings.lastVersion = curVersion; + await this.saveSettings(); + } + } + } + + onunload() { // do nothing } @@ -120,7 +160,7 @@ export default class BanyanPlugin extends Plugin { setupRandomReview = () => { if (!this.settings.enableRandomReview) return; - + const icons = ['dice', 'shuffle', 'dices', 'dice-6', 'dice-5', 'dice-4', 'dice-3', 'dice-2', 'dice-1']; this.randomRibbonIcons = []; @@ -143,7 +183,7 @@ export default class BanyanPlugin extends Plugin { }); } - updateSettingIfNeeded = async () => { + updateSettingIfNeeded = () => { // *** 版本更新时,在以下添加更新逻辑 *** if (this.settings.settingsVersion < 2) { const getNewFilterIfNeeded = (tf: TagFilter) => { @@ -199,7 +239,7 @@ export default class BanyanPlugin extends Plugin { } if (this.settings.settingsVersion < 9) { const usedViewSchemes = this.appData.viewSchemes && this.appData.viewSchemes.length > 0; - + let usedRandomReview = false; if (this.appData.randomReviewFilters && this.appData.randomReviewFilters.length > 0) { if (this.appData.randomReviewFilters.length > 1) { @@ -212,8 +252,8 @@ export default class BanyanPlugin extends Plugin { this.settings.enableViewSchemes = usedViewSchemes; this.settings.enableRandomReview = usedRandomReview; } + this.checkAnnouncements(); this.settings.settingsVersion = CUR_SETTINGS_VERSION; - this.appData.version = CUR_APP_DATA_VERSION; this.updateSavedFile(); this.saveSettings(); this.saveAppData(); @@ -276,7 +316,6 @@ export default class BanyanPlugin extends Plugin { if (migrated) { console.log('Detected legacy settings, migrated to appData'); - this.appData.version = CUR_APP_DATA_VERSION; await this.saveAppData(); await this.saveSettings(); } diff --git a/src/BanyanPluginSettings.ts b/src/BanyanPluginSettings.ts index d0673d6..44602e0 100644 --- a/src/BanyanPluginSettings.ts +++ b/src/BanyanPluginSettings.ts @@ -24,6 +24,8 @@ export interface BanyanPluginSettings { enableViewSchemes?: boolean; enableRandomReview?: boolean; + // meta + lastVersion?: string; } export const CUR_SETTINGS_VERSION = 9; @@ -52,4 +54,5 @@ export const DEFAULT_SETTINGS: BanyanPluginSettings = { enableViewSchemes: false, enableRandomReview: false, + lastVersion: '', } \ No newline at end of file diff --git a/src/BanyanSettingTab.tsx b/src/BanyanSettingTab.tsx index 7bc6396..4c9659d 100644 --- a/src/BanyanSettingTab.tsx +++ b/src/BanyanSettingTab.tsx @@ -6,6 +6,8 @@ import { useCombineStore } from './store'; import { CardContentMaxHeightType, FontTheme, NewNoteLocationMode } from './models/Enum'; import { openMigrateTitleModal } from './components/MigrateTitleModal'; import { openRemoveIdModal } from './components/RemoveIdModal'; +import { AnnouncementModal } from './components/AnnouncementModal'; +import { getWelcomeMarkdown, getChangelogMarkdown } from './utils/announcements'; export class BanyanSettingTab extends PluginSettingTab { plugin: BanyanPlugin; @@ -23,8 +25,6 @@ export class BanyanSettingTab extends PluginSettingTab { this.setupCardsDirectorySetting(containerEl); this.setupOpenWhenStartObsidianSetting(containerEl); this.setupCardsColumnsSetting(containerEl); - this.setupEnableViewSchemesSetting(containerEl); - this.setupEnableRandomReviewSetting(containerEl); // 卡片视图 new Setting(containerEl).setName(i18n.t('setting_header_cards')).setHeading(); @@ -40,11 +40,18 @@ export class BanyanSettingTab extends PluginSettingTab { this.setupUseZkPrefixerFormatSetting(containerEl); this.setupShowAddNoteRibbonSetting(containerEl); + // 帮助 + new Setting(containerEl).setName(i18n.t('setting_header_help')).setHeading(); + this.setupHelpSetting(containerEl); + // 旧版清理 new Setting(containerEl).setName(i18n.t('setting_header_clean')).setHeading(); + this.setupEnableViewSchemesSetting(containerEl); + this.setupEnableRandomReviewSetting(containerEl); this.setupMigrateTitleToFilenameSetting(containerEl); } + setupCardsDirectorySetting(containerEl: HTMLElement) { const dateDesc = document.createDocumentFragment(); dateDesc.appendText(i18n.t('setting_note_directory_desc1')); @@ -288,4 +295,33 @@ export class BanyanSettingTab extends PluginSettingTab { }); } + setupHelpSetting(containerEl: HTMLElement) { + new Setting(containerEl) + .setName(i18n.t('setting_show_welcome_name')) + .setDesc(i18n.t('setting_show_welcome_desc')) + .addButton(btn => { + btn.setButtonText(i18n.t('setting_show_welcome_btn')) + .onClick(async () => { + const modal = new AnnouncementModal(this.app, { + type: 'welcome', + content: getWelcomeMarkdown() + }); + modal.open(); + }); + }); + new Setting(containerEl) + .setName(i18n.t('setting_show_update_name')) + .setDesc(i18n.t('setting_show_update_desc')) + .addButton(btn => { + btn.setButtonText(i18n.t('setting_show_update_btn')) + .onClick(async () => { + const modal = new AnnouncementModal(this.app, { + type: 'update', + content: getChangelogMarkdown() + }); + modal.open(); + }); + }); + } + } diff --git a/docs/changelog.md b/src/announcements/changelog_en.md similarity index 90% rename from docs/changelog.md rename to src/announcements/changelog_en.md index 291c26c..35e7683 100644 --- a/docs/changelog.md +++ b/src/announcements/changelog_en.md @@ -1,4 +1,14 @@ -### Changelog +# Changelog + +### 1.4.3 + +Improvements + +- Now we have guidance pop-up and changelog pop-up, which can also be viewed in the settings panel. +- Now we add switches for "Random Review" and "View Scheme" in the setting. If you have been using these features, all remains the same; otherwise, they are disabled by default. These two features may be considered for removal in later version. +- We optimized the refresh logic of the card panel. Now Adding or editing notes will no longer cause a full refresh of the card panel. +- Fixed the extra blank block appeared in the search box on mobile. +- Optimized some styles. ### 1.4.2 diff --git a/docs/changelog_zh.md b/src/announcements/changelog_zh.md similarity index 89% rename from docs/changelog_zh.md rename to src/announcements/changelog_zh.md index 526e90b..668c1aa 100644 --- a/docs/changelog_zh.md +++ b/src/announcements/changelog_zh.md @@ -1,4 +1,17 @@ -### 更新日志 +# 更新日志 + +### 1.4.3 + +新增 + +- 指引弹窗和版本更新日志弹窗,并且可以在设置面板中主动查看。 +- 「随机回顾」和「视图空间」的设置开关,如果你使用过该功能,开关是打开的,使用照旧;否则默认是关闭的,日后考虑下掉这2个功能。 + +修复和优化 + +- 优化了卡片面板的刷新逻辑,现在新增或修改笔记不会再导致卡片面板全量刷新了。 +- 修复移动端搜索框出现额外空白块的问题。 +- 对一些样式进行了优化。 ### 1.4.2 diff --git a/src/announcements/welcome_en.md b/src/announcements/welcome_en.md new file mode 100644 index 0000000..5aed79f --- /dev/null +++ b/src/announcements/welcome_en.md @@ -0,0 +1,25 @@ +# 🌲 Welcome to Banyan + +Banyan allows you to visualize your notes through a card view and retrieve them using a tag-based filtering system, rather than a traditional tree directory. + +### 🚀 Getting Started + +This plugin only manages notes within the `Notes Directory` (defaulted to `cards`). +The storage structure of notes and subdirectories within this folder is no longer important. +The `banyan_config` under the "Notes Directory" stores plugin configuration files. It cannot be hidden for now, as setting it to a hidden directory will cause the MD files within it to fail to load. + +The Card Panel displays notes chronologically and allows you to view specific notes through filtering schemes. +Filters include tags, dates, and keywords. Tags can be combined using **"OR, AND, NOT"** logic to create powerful filtering combinations. +Click the **Card Icon** 🗂️ in the functional area to open the Card Panel. + +Click the **Lightbulb Icon** 💡 in the functional area to create a new note. +The current time is used as the default title, but you can modify it as you wish. +New notes are stored by default in a `Year/Quarter/Month/Day` hierarchy—though the hierarchy is secondary, you can customize the storage directory in the settings. + +*Please feel free to explore more. Happy learning in your forest of knowledge!* + +### 📮 Contact Me + +github issue: [obsidian-banyan - ratiger | Github](https://github.com/ratiger/obsidian-banyan) +email: 2084939306@qq.com +rednote: ratiger (rednote number: 1392996322) diff --git a/src/announcements/welcome_zh.md b/src/announcements/welcome_zh.md new file mode 100644 index 0000000..4a7c609 --- /dev/null +++ b/src/announcements/welcome_zh.md @@ -0,0 +1,26 @@ +# 🌲 欢迎使用 Banyan + +Banyan 通过卡片视图直观查看笔记内容,并通过以标签为主的筛选方案,而非传统的树形目录来检索笔记。 + +### 🚀 基本使用 + +本插件只管理「笔记目录」(默认为 `cards`)下的笔记; +该目录下的笔记与子目录的存放结构不再紧要。 +「笔记目录」的根目录下的「banyan_config」目录用于存储应用配置文件,暂时无法隐藏,因为设置为隐藏目录会导致其内的md文件读取失败。 + +卡片面板以时间顺序展示笔记,并通过筛选方案展示指定笔记; +筛选包括标签、日期、关键字,其中标签通过「或且非」组合出强大的筛选方案; +点击功能区的卡片图标 🗂️ 打开卡片面板。 + +点击功能区的灯泡图标 💡 新建笔记; +默认以当时时间作为新建笔记的标题,但你可以任意修改它; +新建笔记将默认按 `年/季度/月/日` 的层级存放,但层级其实无关紧要,不过你也可以在设置中自定义存放目录; + +*尽请探索更多内容,祝您在的知识森林中学习愉快!* + +### 📮 与我联系 + +github issue: [obsidian-banyan - ratiger | Github](https://github.com/ratiger/obsidian-banyan) +邮箱: 2084939306@qq.com +小红书: ratiger (小红书号: 1392996322) + diff --git a/src/components/AnnouncementModal.tsx b/src/components/AnnouncementModal.tsx new file mode 100644 index 0000000..7fcb2c7 --- /dev/null +++ b/src/components/AnnouncementModal.tsx @@ -0,0 +1,63 @@ +import { App, Modal, MarkdownRenderer, Component } from "obsidian"; +import * as React from "react"; +import { createRoot, Root } from "react-dom/client"; +import { i18n } from "src/utils/i18n"; + +interface AnnouncementModalProps { + type: 'welcome' | 'update'; + content: string; + onClose?: () => void; +} + +export class AnnouncementModal extends Modal { + props: AnnouncementModalProps; + root: Root | null = null; + + constructor(app: App, props: AnnouncementModalProps) { + super(app); + this.props = props; + } + + onOpen() { + this.modalEl.addClass('announcement-modal'); + this.root = createRoot(this.modalEl); + this.root.render( + + { this.close() }} /> + + ); + (this as any).shouldRestoreSelection = false; + } + + onClose() { + this.root?.unmount(); + this.props.onClose?.(); + } +} + +const AnnouncementContainer = ({ app, props, close }: { + app: App, props: AnnouncementModalProps, close: () => void +}) => { + const { type, content } = props; + const buttonText = type === 'welcome' ? i18n.t('announcement_get_started') : i18n.t('announcement_close'); + const contentRef = React.useRef(null); + + React.useEffect(() => { + if (contentRef.current) { + contentRef.current.empty(); + const component = new Component(); + component.load(); + MarkdownRenderer.render(app, content, contentRef.current, '', component); + } + }, [content, app]); + + return ( +
+
+
+
+ +
+
+ ); +}; diff --git a/src/components/components.css b/src/components/components.css index 0916ffe..b4821d3 100644 --- a/src/components/components.css +++ b/src/components/components.css @@ -246,4 +246,52 @@ font-size: 32px; cursor: pointer; transition: box-shadow 0.2s, background 0.2s; +} + +/* 公告弹窗 */ +.announcement-modal { + max-width: 500px; +} + +.announcement-container { + padding: 24px; + display: flex; + flex-direction: column; + gap: 20px; +} + +.announcement-content { + line-height: 1.6; + max-height: 65vh; + overflow-y: auto; + padding-right: 12px; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE and Edge */ +} + +.announcement-content::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ +} + +.announcement-content h1:first-child { + margin-top: 0; + text-align: center; + color: var(--text-accent); +} + +.announcement-content h3 { + margin-top: 1.5em; + border-bottom: 1px solid var(--background-modifier-border); + padding-bottom: 0.3em; +} + +.announcement-footer { + display: flex; + justify-content: center; +} + +.announcement-btn { + width: 100%; + padding: 10px !important; + font-weight: bold !important; } \ No newline at end of file diff --git a/src/declarations.d.ts b/src/declarations.d.ts new file mode 100644 index 0000000..dc003b7 --- /dev/null +++ b/src/declarations.d.ts @@ -0,0 +1,4 @@ +declare module "*.md" { + const content: string; + export default content; +} diff --git a/src/utils/announcements.ts b/src/utils/announcements.ts new file mode 100644 index 0000000..dbc0e2d --- /dev/null +++ b/src/utils/announcements.ts @@ -0,0 +1,19 @@ +import { i18n } from "./i18n"; + +// Import markdown files as strings +import welcome_en from "../announcements/welcome_en.md"; +import welcome_zh from "../announcements/welcome_zh.md"; +import changelog_en from "../announcements/changelog_en.md"; +import changelog_zh from "../announcements/changelog_zh.md"; + +export const getWelcomeMarkdown = (): string => { + const lang = i18n.getCurrentLanguage(); + if (lang === 'zh') return welcome_zh; + return welcome_en; +}; + +export const getChangelogMarkdown = (): string => { + const lang = i18n.getCurrentLanguage(); + if (lang === 'zh') return changelog_zh; + return changelog_en; +}; diff --git a/src/utils/i18n/languages/en.ts b/src/utils/i18n/languages/en.ts index 2e89d32..3f90489 100644 --- a/src/utils/i18n/languages/en.ts +++ b/src/utils/i18n/languages/en.ts @@ -108,10 +108,10 @@ export default { setting_card_content_max_height_expand: "Expand", setting_enable_view_schemes_name: "Enable \"View schemes\"", - setting_enable_view_schemes_desc: "Whether to display and enable the \"View schemes\" feature in the sidebar.", - + setting_enable_view_schemes_desc: "Most of the use cases of this feature are replaced by \"Filter schemes\". So we are considering removing it.", + setting_enable_random_review_name: "Enable \"Random review\"", - setting_enable_random_review_desc: "Whether to display and enable the \"Random review\" feature in the sidebar.", + setting_enable_random_review_desc: "Most of the use cases of this feature are replaced by \"Random browse\". So we are considering removing it.", // font setting_font_theme_name: "Font size", @@ -234,4 +234,18 @@ export default { loading_text: "Loading...", reached_bottom: "You have reached the bottom.~", + /* Announcement Modal */ + announcement_welcome_title: "Welcome to Banyan", + announcement_update_title: "What's New in Banyan", + announcement_get_started: "Get Started", + announcement_close: "Close", + + /* Settings - Help */ + setting_header_help: "❓ Help", + setting_show_welcome_name: "Tutorial", + setting_show_welcome_desc: "About Banyan usage.", + setting_show_welcome_btn: "View", + setting_show_update_name: "Changelog", + setting_show_update_desc: "All versions changelog.", + setting_show_update_btn: "View", }; \ No newline at end of file diff --git a/src/utils/i18n/languages/zh.ts b/src/utils/i18n/languages/zh.ts index ecb437d..5fbeab5 100644 --- a/src/utils/i18n/languages/zh.ts +++ b/src/utils/i18n/languages/zh.ts @@ -62,7 +62,7 @@ export default { setting_header_basic: "⚙️ 基础设置", setting_header_cards: "🗂 卡片视图", setting_header_editor: "✏️ 新建笔记", - setting_header_clean: "⚠️ 旧版数据清理", + setting_header_clean: "⚠️ 旧版清理", setting_note_directory_name: "笔记目录", setting_note_directory_desc1: "「卡片面板」只会管理该目录下的所有笔记。", @@ -109,11 +109,11 @@ export default { setting_card_content_max_height_normal: "一般", setting_card_content_max_height_expand: "不折叠", - setting_enable_view_schemes_name: "启用「视图空间」", - setting_enable_view_schemes_desc: "是否在侧边栏显示并在后台启用「视图空间」功能。", - - setting_enable_random_review_name: "启用「随机回顾」", - setting_enable_random_review_desc: "是否在侧边栏显示并在后台启用「随机回顾」功能。", + setting_enable_view_schemes_name: "启用「视图空间」功能", + setting_enable_view_schemes_desc: "该功能的使用场景更多被「筛选方案」替代了,故正考虑下掉该功能。", + + setting_enable_random_review_name: "启用「随机回顾」功能", + setting_enable_random_review_desc: "该功能的使用场景更多被「乱序浏览」替代了,故正考虑下掉该功能。", // 字体 setting_font_theme_name: "内容区域字体大小", @@ -236,4 +236,18 @@ export default { loading_text: "加载中...", reached_bottom: "你已经到底部了", + /* Announcement Modal */ + announcement_welcome_title: "欢迎使用 Banyan", + announcement_update_title: "Banyan 更新日志", + announcement_get_started: "开始使用", + announcement_close: "关闭", + + /* 设置 - 帮助 */ + setting_header_help: "❓ 帮助", + setting_show_welcome_name: "新手指引", + setting_show_welcome_desc: "关于 Banyan 的使用说明。", + setting_show_welcome_btn: "查看", + setting_show_update_name: "更新日志", + setting_show_update_desc: "所有版本的更新内容。", + setting_show_update_btn: "查看", }; \ No newline at end of file