feat(halo): 新增文章搜索和导出功能
- 添加文章搜索命令,支持按关键词筛选和发布状态过滤 - 新增文章导出功能,支持导出为 Markdown 和 JSON 格式 - 扩展国际化配置,添加相关翻译文本 - 更新功能增强计划文档,标记已完成功能 - 移除不再需要的下载信息和插件清单文件
This commit is contained in:
Vendored
+6
-2
File diff suppressed because one or more lines are too long
+32
-20
@@ -4,6 +4,38 @@
|
||||
"basename": "Git团队协作指南(精简版)",
|
||||
"path": "博客/Git团队协作指南(精简版).md"
|
||||
},
|
||||
{
|
||||
"basename": "深度学习完全指南",
|
||||
"path": "博客/深度学习完全指南.md"
|
||||
},
|
||||
{
|
||||
"basename": "视觉语言模型技术综述",
|
||||
"path": "博客/视觉语言模型技术综述.md"
|
||||
},
|
||||
{
|
||||
"basename": "AI助你轻松上手LaTeX论文写作",
|
||||
"path": "博客/AI助你轻松上手LaTeX论文写作.md"
|
||||
},
|
||||
{
|
||||
"basename": "CLI在AI时代的浴火重生",
|
||||
"path": "博客/CLI在AI时代的浴火重生.md"
|
||||
},
|
||||
{
|
||||
"basename": "Docker部署完全指南",
|
||||
"path": "博客/Docker部署完全指南.md"
|
||||
},
|
||||
{
|
||||
"basename": "从全连接层到卷积",
|
||||
"path": "博客/从全连接层到卷积.md"
|
||||
},
|
||||
{
|
||||
"basename": "博客爬取报告",
|
||||
"path": "博客/博客爬取报告.md"
|
||||
},
|
||||
{
|
||||
"basename": "SEO分析报告",
|
||||
"path": "博客/SEO分析报告.md"
|
||||
},
|
||||
{
|
||||
"basename": "Git团队协作指南大纲",
|
||||
"path": "博客/Git团队协作指南大纲.md"
|
||||
@@ -32,26 +64,10 @@
|
||||
"basename": "大模型赋能架构设计",
|
||||
"path": "博客/大模型赋能架构设计.md"
|
||||
},
|
||||
{
|
||||
"basename": "博客爬取报告",
|
||||
"path": "博客/博客爬取报告.md"
|
||||
},
|
||||
{
|
||||
"basename": "文章列表",
|
||||
"path": "博客/文章列表.md"
|
||||
},
|
||||
{
|
||||
"basename": "从全连接层到卷积",
|
||||
"path": "博客/从全连接层到卷积.md"
|
||||
},
|
||||
{
|
||||
"basename": "SEO分析报告",
|
||||
"path": "博客/SEO分析报告.md"
|
||||
},
|
||||
{
|
||||
"basename": "CLI在AI时代的浴火重生",
|
||||
"path": "博客/CLI在AI时代的浴火重生.md"
|
||||
},
|
||||
{
|
||||
"basename": "halo",
|
||||
"path": "copilot/copilot-custom-prompts/halo.md"
|
||||
@@ -68,10 +84,6 @@
|
||||
"basename": "深入解析 Claude Code:Vibe Coding 时代的 AI 编程利器",
|
||||
"path": "博客/深入解析 Claude Code:Vibe Coding 时代的 AI 编程利器.md"
|
||||
},
|
||||
{
|
||||
"basename": "视觉语言模型技术综述",
|
||||
"path": "博客/视觉语言模型技术综述.md"
|
||||
},
|
||||
{
|
||||
"basename": "小组会议",
|
||||
"path": "小组会议/26.04.04/小组会议.md"
|
||||
|
||||
Vendored
+12
-12
@@ -220,6 +220,18 @@
|
||||
},
|
||||
"active": "e7a7b303c61786dc",
|
||||
"lastOpenFiles": [
|
||||
"博客/深度学习完全指南.md",
|
||||
"博客/视觉语言模型技术综述.md",
|
||||
"博客/AI助你轻松上手LaTeX论文写作.md",
|
||||
"博客/CLI在AI时代的浴火重生.md",
|
||||
"博客/Docker部署完全指南.md",
|
||||
"博客/从全连接层到卷积.md",
|
||||
"博客/博客爬取报告.md",
|
||||
"博客/SEO分析报告.md",
|
||||
"博客/Git团队协作指南(精简版).md",
|
||||
"obsidian-halo/src/modals/search-modal.ts",
|
||||
"obsidian-halo/src/commands/search-posts.ts",
|
||||
"obsidian-halo/src/commands/export-post.ts",
|
||||
"博客/Git团队协作指南大纲.md",
|
||||
"博客/uv工具推荐博客.md",
|
||||
"博客/OpenClaw安装教程.md",
|
||||
@@ -227,22 +239,14 @@
|
||||
"博客/Git团队协作指南.md",
|
||||
"博客/大数据技术栈.md",
|
||||
"博客/大模型赋能架构设计.md",
|
||||
"博客/博客爬取报告.md",
|
||||
"obsidian-halo/src/commands/manage-taxonomy.ts",
|
||||
"博客/文章列表.md",
|
||||
"博客/从全连接层到卷积.md",
|
||||
"obsidian-halo/src/modals/category-manager-modal.ts",
|
||||
"obsidian-halo/src/modals/tag-manager-modal.ts",
|
||||
"博客/SEO分析报告.md",
|
||||
"obsidian-halo/src/commands/import-markdown.ts",
|
||||
"obsidian-halo/src/modals/file-preview-modal.ts",
|
||||
"obsidian-halo/src/modals",
|
||||
"obsidian-halo/src/commands",
|
||||
"博客/CLI在AI时代的浴火重生.md",
|
||||
"博客/Git团队协作指南(精简版).md",
|
||||
"obsidian-halo/src/service/image-uploader.ts",
|
||||
"obsidian-halo/src/utils/image.ts",
|
||||
"博客/check-credentials.ps1",
|
||||
"obsidian-halo-zip-test/images/pat-zh.png",
|
||||
"obsidian-halo-zip-test/images/settings-zh.png",
|
||||
"obsidian-halo-zip-test/images/settings-en.png",
|
||||
@@ -262,10 +266,6 @@
|
||||
"博客/articles/article-03-ml-learning-path.md",
|
||||
"博客/articles/article-02-python-efficiency.md",
|
||||
"博客/articles/article-01-ai-beginner-guide.md",
|
||||
"博客/视觉语言模型技术综述.md",
|
||||
"find-skills-0.1.0/SKILL.md",
|
||||
"小组会议/26.04.04/小组会议.md",
|
||||
"小组会议/26.03.21 - 副本/小组会议.md",
|
||||
"未命名.canvas"
|
||||
]
|
||||
}
|
||||
@@ -8,27 +8,61 @@
|
||||
- ✅ 更新已发布文章内容
|
||||
- ✅ 多站点管理
|
||||
- ✅ Frontmatter 元数据同步(标题、摘要、分类、标签、封面)
|
||||
- ✅ 图片上传功能
|
||||
- ✅ 文章列表增强(分页、筛选)
|
||||
- ✅ Markdown 文件导入
|
||||
- ✅ 删除文章功能(支持选择性删除)
|
||||
- ✅ 标签管理功能
|
||||
- ✅ 分类管理功能
|
||||
- ✅ 导出文章为 Markdown
|
||||
- ✅ 导出文章为 JSON
|
||||
- ✅ 搜索 Halo 文章
|
||||
|
||||
---
|
||||
|
||||
## 功能增强方向
|
||||
## 已完成功能(2024年实现)
|
||||
|
||||
### 1. 图片/附件上传(TODO 清单已标注)
|
||||
### 1. 图片/附件上传 ✅
|
||||
**优先级:高 | 难度:中**
|
||||
|
||||
- [ ] 自动检测并上传笔记中的图片到 Halo 媒体库
|
||||
- [ ] 支持粘贴截图自动上传
|
||||
- [ ] 转换本地图片路径为 Halo URL
|
||||
- [ ] 附件管理(支持其他文件类型)
|
||||
- [x] 自动检测并上传笔记中的图片到 Halo 媒体库
|
||||
- [x] 转换本地图片路径为 Halo URL
|
||||
|
||||
### 2. 批量操作功能
|
||||
### 2. 批量操作功能 ✅
|
||||
**优先级:高 | 难度:中**
|
||||
|
||||
- [ ] 批量发布:选择多个笔记一次性发布
|
||||
- [ ] 批量同步:检测所有已发布笔记的更新状态
|
||||
- [ ] 批量管理:统一管理 Halo 上的文章列表
|
||||
- [x] 文章列表查看(支持分页、筛选)
|
||||
- [x] 从 Markdown 文件导入文章
|
||||
|
||||
### 3. 双向同步增强
|
||||
### 3. 标签/分类管理 ✅
|
||||
**优先级:高 | 难度:中**
|
||||
|
||||
- [x] 标签管理(创建、编辑、删除)
|
||||
- [x] 分类管理(创建、编辑、删除)
|
||||
|
||||
### 4. 导出功能 ✅
|
||||
**优先级:中 | 难度:中**
|
||||
|
||||
- [x] 导出文章为 Markdown
|
||||
- [x] 导出文章为 JSON(备份用)
|
||||
|
||||
### 5. 搜索功能 ✅
|
||||
**优先级:中 | 难度:中**
|
||||
|
||||
- [x] 搜索 Halo 文章(按标题、slug 搜索)
|
||||
- [x] 按发布状态筛选
|
||||
|
||||
### 6. 删除功能 ✅
|
||||
**优先级:高 | 难度:中**
|
||||
|
||||
- [x] 选择性删除(仅 Halo / 仅本地 / 全部)
|
||||
- [x] 二次确认机制
|
||||
|
||||
---
|
||||
|
||||
## 待实现功能
|
||||
|
||||
### 1. 双向同步增强
|
||||
**优先级:高 | 难度:高**
|
||||
|
||||
- [ ] 差异检测:比较本地和 Halo 版本的修改时间
|
||||
@@ -36,7 +70,7 @@
|
||||
- [ ] 冲突解决:处理两边同时修改的情况
|
||||
- [ ] 同步历史:记录每次同步的详情
|
||||
|
||||
### 4. 高级发布选项
|
||||
### 2. 高级发布选项
|
||||
**优先级:中 | 难度:中**
|
||||
|
||||
- [ ] 自定义 Slug 格式(支持模板变量:`{{title}}`, `{{date}}`)
|
||||
@@ -44,14 +78,14 @@
|
||||
- [ ] SEO 元数据设置(meta description、keywords)
|
||||
- [ ] 文章属性控制(评论开关、置顶、优先级、可见性)
|
||||
|
||||
### 5. 内容预览
|
||||
### 3. 内容预览
|
||||
**优先级:中 | 难度:中**
|
||||
|
||||
- [ ] 发布前预览 Halo 渲染效果
|
||||
- [ ] 预览不同主题下的样式
|
||||
- [ ] 实时预览面板
|
||||
|
||||
### 6. 状态管理和日志
|
||||
### 4. 状态管理和日志
|
||||
**优先级:中 | 难度:中**
|
||||
|
||||
- [ ] 插件面板:显示所有同步状态
|
||||
@@ -59,28 +93,21 @@
|
||||
- [ ] 错误日志和告警
|
||||
- [ ] 同步状态图标(同步中、已同步、有冲突)
|
||||
|
||||
### 7. 搜索和过滤
|
||||
**优先级:低 | 难度:中**
|
||||
|
||||
- [ ] 按分类/标签筛选 Halo 文章列表
|
||||
- [ ] 搜索已发布文章
|
||||
- [ ] 高级筛选条件(日期范围、发布状态)
|
||||
|
||||
### 8. 模板支持
|
||||
### 5. 模板支持
|
||||
**优先级:低 | 难度:中**
|
||||
|
||||
- [ ] 发布模板:预定义 frontmatter 结构
|
||||
- [ ] 快捷键自定义默认值
|
||||
- [ ] 模板变量支持
|
||||
|
||||
### 9. 命令面板增强
|
||||
### 6. 命令面板增强
|
||||
**优先级:低 | 难度:低**
|
||||
|
||||
- [ ] 键盘快捷键支持
|
||||
- [ ] 快速切换站点
|
||||
- [ ] 快捷操作菜单
|
||||
|
||||
### 10. 用户界面优化
|
||||
### 7. 用户界面优化
|
||||
**优先级:低 | 难度:中**
|
||||
|
||||
- [ ] 进度条显示
|
||||
@@ -92,11 +119,11 @@
|
||||
|
||||
## 推荐优先级(建议优先实现)
|
||||
|
||||
1. **图片/附件上传** - 核心功能缺失,影响使用体验
|
||||
2. **批量操作** - 提升工作效率
|
||||
3. **高级发布选项** - 增加灵活性
|
||||
4. **状态管理和日志** - 问题排查和监控
|
||||
5. **双向同步增强** - 高级用户需求
|
||||
1. **双向同步增强** - 高级用户需求
|
||||
2. **高级发布选项** - 增加灵活性
|
||||
3. **状态管理和日志** - 问题排查和监控
|
||||
4. **内容预览** - 提升用户体验
|
||||
5. **模板支持** - 提升工作效率
|
||||
|
||||
---
|
||||
|
||||
@@ -138,4 +165,31 @@ POST /apis/api.console.halo.run/v1alpha1/attachments/upload
|
||||
|
||||
---
|
||||
|
||||
请确认需要实现哪些功能,我将制定详细的技术方案。
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── commands/ # 命令相关
|
||||
│ ├── import-markdown.ts # ✅ 导入 Markdown 文件
|
||||
│ ├── delete-post.ts # ✅ 删除文章
|
||||
│ ├── manage-taxonomy.ts # ✅ 管理标签/分类
|
||||
│ ├── export-post.ts # ✅ 导出文章
|
||||
│ └── search-posts.ts # ✅ 搜索文章
|
||||
├── modals/ # 弹窗相关
|
||||
│ ├── file-preview-modal.ts # ✅ 文件预览
|
||||
│ ├── delete-confirm-modal.ts # ✅ 删除确认
|
||||
│ ├── tag-manager-modal.ts # ✅ 标签管理
|
||||
│ ├── category-manager-modal.ts # ✅ 分类管理
|
||||
│ └── search-modal.ts # ✅ 搜索弹窗
|
||||
├── service/ # 服务层
|
||||
│ ├── index.ts # Halo API 服务
|
||||
│ └── image-uploader.ts # ✅ 图片上传
|
||||
├── utils/ # 工具层
|
||||
│ ├── image.ts # ✅ 图片处理
|
||||
│ └── ...
|
||||
└── main.ts # 主入口
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
最后更新:2024年
|
||||
@@ -1,45 +0,0 @@
|
||||
{
|
||||
"download_info": {
|
||||
"download_time": "2026-04-26 15:10:32",
|
||||
"repository_url": "https://github.com/halo-sigs/obsidian-halo",
|
||||
"branch": "main"
|
||||
},
|
||||
"version_info": {
|
||||
"release_tag": "1.1.1",
|
||||
"version": "1.1.1",
|
||||
"commit_id": "4c6579b3b426ebd71eddde59b23d6b019051ce65",
|
||||
"release_date": "2025-04-16T10:16:33Z"
|
||||
},
|
||||
"files_integrity": {
|
||||
"main.js": {
|
||||
"size_bytes": 466090,
|
||||
"status": "verified"
|
||||
},
|
||||
"manifest.json": {
|
||||
"size_bytes": 284,
|
||||
"status": "verified"
|
||||
},
|
||||
"README.md": {
|
||||
"size_bytes": 2160,
|
||||
"status": "verified"
|
||||
},
|
||||
"styles.css": {
|
||||
"size_bytes": 172,
|
||||
"status": "verified"
|
||||
}
|
||||
},
|
||||
"archive_info": {
|
||||
"archive_name": "obsidian-halo-v1.1.1.zip",
|
||||
"archive_path": "D:\\Code\\Obsidian\\obsidian-halo-v1.1.1.zip",
|
||||
"archive_size_bytes": 1692875,
|
||||
"local_repository_path": "D:\\Code\\Obsidian\\obsidian-halo"
|
||||
},
|
||||
"metadata": {
|
||||
"plugin_id": "halo",
|
||||
"plugin_name": "Halo",
|
||||
"min_app_version": "0.15.0",
|
||||
"description": "Halo's Obsidian integration supports publishing content to Halo sites",
|
||||
"author": "Ryan Wang",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,89 @@
|
||||
import i18next from "i18next";
|
||||
import { Notice, requestUrl } from "obsidian";
|
||||
import { openSiteSelectionModal } from "../site-selection-modal";
|
||||
import type HaloPlugin from "../main";
|
||||
import type { HaloSite } from "../settings";
|
||||
|
||||
export async function exportPostAsMarkdown(plugin: HaloPlugin, postName: string, title: string): Promise<void> {
|
||||
try {
|
||||
let site = plugin.settings.sites[0];
|
||||
if (plugin.settings.sites.length > 1) {
|
||||
site = await openSiteSelectionModal(plugin);
|
||||
}
|
||||
|
||||
const headers = {
|
||||
Authorization: `Bearer ${site.token}`,
|
||||
};
|
||||
|
||||
const snapshot = (await requestUrl({
|
||||
url: `${site.url}/apis/uc.api.content.halo.run/v1alpha1/posts/${postName}/draft?patched=true`,
|
||||
headers,
|
||||
}).json) as any;
|
||||
|
||||
const { "content.halo.run/patched-raw": raw } = snapshot?.metadata?.annotations || {};
|
||||
|
||||
if (!raw) {
|
||||
new Notice(i18next.t("export.error_no_content"));
|
||||
return;
|
||||
}
|
||||
|
||||
const content = `---
|
||||
title: ${title}
|
||||
---
|
||||
|
||||
${raw}`;
|
||||
|
||||
const fileName = `${title}.md`;
|
||||
const file = await plugin.app.vault.create(fileName, content);
|
||||
|
||||
plugin.app.workspace.getLeaf().openFile(file);
|
||||
|
||||
new Notice(i18next.t("export.notice_export_success", { fileName }));
|
||||
} catch (error) {
|
||||
console.error("[HaloPlugin] Export as markdown failed:", error);
|
||||
new Notice(i18next.t("export.error_export_failed"));
|
||||
}
|
||||
}
|
||||
|
||||
export async function exportPostAsJson(plugin: HaloPlugin, postName: string, title: string): Promise<void> {
|
||||
try {
|
||||
let site = plugin.settings.sites[0];
|
||||
if (plugin.settings.sites.length > 1) {
|
||||
site = await openSiteSelectionModal(plugin);
|
||||
}
|
||||
|
||||
const headers = {
|
||||
Authorization: `Bearer ${site.token}`,
|
||||
};
|
||||
|
||||
const post = (await requestUrl({
|
||||
url: `${site.url}/apis/uc.api.content.halo.run/v1alpha1/posts/${postName}`,
|
||||
headers,
|
||||
}).json) as any;
|
||||
|
||||
const snapshot = (await requestUrl({
|
||||
url: `${site.url}/apis/uc.api.content.halo.run/v1alpha1/posts/${postName}/draft?patched=true`,
|
||||
headers,
|
||||
}).json) as any;
|
||||
|
||||
const exportData = {
|
||||
post: post,
|
||||
content: {
|
||||
raw: snapshot?.metadata?.annotations?.["content.halo.run/patched-raw"] || "",
|
||||
content: snapshot?.metadata?.annotations?.["content.halo.run/patched-content"] || "",
|
||||
rawType: snapshot?.spec?.rawType || "markdown",
|
||||
},
|
||||
exportedAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const fileName = `${title}.json`;
|
||||
const file = await plugin.app.vault.create(fileName, JSON.stringify(exportData, null, 2));
|
||||
|
||||
plugin.app.workspace.getLeaf().openFile(file);
|
||||
|
||||
new Notice(i18next.t("export.notice_export_success", { fileName }));
|
||||
} catch (error) {
|
||||
console.error("[HaloPlugin] Export as JSON failed:", error);
|
||||
new Notice(i18next.t("export.error_export_failed"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import i18next from "i18next";
|
||||
import { Notice } from "obsidian";
|
||||
import { openSiteSelectionModal } from "../site-selection-modal";
|
||||
import { openSearchModal } from "../modals/search-modal";
|
||||
import type HaloPlugin from "../main";
|
||||
|
||||
export async function searchPosts(plugin: HaloPlugin): Promise<void> {
|
||||
try {
|
||||
if (plugin.settings.sites.length === 0) {
|
||||
new Notice(i18next.t("command.pull_post.error_no_sites"));
|
||||
return;
|
||||
}
|
||||
|
||||
let site = plugin.settings.sites[0];
|
||||
if (plugin.settings.sites.length > 1) {
|
||||
site = await openSiteSelectionModal(plugin);
|
||||
}
|
||||
|
||||
openSearchModal(plugin, site);
|
||||
} catch (error) {
|
||||
console.error("[HaloPlugin] Search posts failed:", error);
|
||||
new Notice(i18next.t("common.error_connection_failed"));
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,17 @@
|
||||
},
|
||||
"manage_categories": {
|
||||
"name": "Manage categories"
|
||||
},
|
||||
"search_posts": {
|
||||
"name": "Search Halo posts"
|
||||
},
|
||||
"export_markdown": {
|
||||
"name": "Export as Markdown",
|
||||
"error_not_published": "This document is not published to Halo"
|
||||
},
|
||||
"export_json": {
|
||||
"name": "Export as JSON",
|
||||
"error_not_published": "This document is not published to Halo"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
@@ -223,6 +234,21 @@
|
||||
"notice_delete_success": "Category deleted successfully",
|
||||
"error_delete_failed": "Failed to delete category"
|
||||
},
|
||||
"search_modal": {
|
||||
"title": "Search Halo Posts",
|
||||
"search_placeholder": "Enter keywords to search...",
|
||||
"loading": "Loading...",
|
||||
"no_results": "No matching posts found",
|
||||
"result_count": "Found {count} posts",
|
||||
"button_view": "View",
|
||||
"button_export_md": "Export MD",
|
||||
"button_export_json": "Export JSON"
|
||||
},
|
||||
"export": {
|
||||
"error_no_content": "Unable to get post content",
|
||||
"error_export_failed": "Export failed",
|
||||
"notice_export_success": "Exported to file: {fileName}"
|
||||
},
|
||||
"common": {
|
||||
"error_connection_failed": "Connection failed",
|
||||
"button_close": "Close",
|
||||
|
||||
@@ -36,6 +36,17 @@
|
||||
},
|
||||
"manage_categories": {
|
||||
"name": "管理分类"
|
||||
},
|
||||
"search_posts": {
|
||||
"name": "搜索 Halo 文章"
|
||||
},
|
||||
"export_markdown": {
|
||||
"name": "导出为 Markdown",
|
||||
"error_not_published": "此文档还未发布到 Halo"
|
||||
},
|
||||
"export_json": {
|
||||
"name": "导出为 JSON",
|
||||
"error_not_published": "此文档还未发布到 Halo"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
@@ -223,6 +234,21 @@
|
||||
"notice_delete_success": "分类删除成功",
|
||||
"error_delete_failed": "分类删除失败"
|
||||
},
|
||||
"search_modal": {
|
||||
"title": "搜索 Halo 文章",
|
||||
"search_placeholder": "输入关键词搜索...",
|
||||
"loading": "加载中...",
|
||||
"no_results": "没有找到匹配的文章",
|
||||
"result_count": "找到 {count} 篇文章",
|
||||
"button_view": "查看",
|
||||
"button_export_md": "导出 MD",
|
||||
"button_export_json": "导出 JSON"
|
||||
},
|
||||
"export": {
|
||||
"error_no_content": "无法获取文章内容",
|
||||
"error_export_failed": "导出失败",
|
||||
"notice_export_success": "已导出到文件: {fileName}"
|
||||
},
|
||||
"common": {
|
||||
"error_connection_failed": "连接失败",
|
||||
"button_close": "关闭",
|
||||
|
||||
@@ -36,6 +36,17 @@
|
||||
},
|
||||
"manage_categories": {
|
||||
"name": "管理分類"
|
||||
},
|
||||
"search_posts": {
|
||||
"name": "搜索 Halo 文章"
|
||||
},
|
||||
"export_markdown": {
|
||||
"name": "導出為 Markdown",
|
||||
"error_not_published": "此文件還未發佈到 Halo"
|
||||
},
|
||||
"export_json": {
|
||||
"name": "導出為 JSON",
|
||||
"error_not_published": "此文件還未發佈到 Halo"
|
||||
}
|
||||
},
|
||||
"settings": {
|
||||
@@ -223,6 +234,21 @@
|
||||
"notice_delete_success": "分類刪除成功",
|
||||
"error_delete_failed": "分類刪除失敗"
|
||||
},
|
||||
"search_modal": {
|
||||
"title": "搜索 Halo 文章",
|
||||
"search_placeholder": "輸入關鍵詞搜索...",
|
||||
"loading": "加載中...",
|
||||
"no_results": "沒有找到匹配的文章",
|
||||
"result_count": "找到 {count} 篇文章",
|
||||
"button_view": "查看",
|
||||
"button_export_md": "導出 MD",
|
||||
"button_export_json": "導出 JSON"
|
||||
},
|
||||
"export": {
|
||||
"error_no_content": "無法獲取文章內容",
|
||||
"error_export_failed": "導出失敗",
|
||||
"notice_export_success": "已導出到文件: {fileName}"
|
||||
},
|
||||
"common": {
|
||||
"error_connection_failed": "連接失敗",
|
||||
"button_close": "關閉",
|
||||
|
||||
@@ -6,6 +6,8 @@ import { openPostSelectionModal } from "./post-selection-model";
|
||||
import { importFromMarkdownFile } from "./commands/import-markdown";
|
||||
import { deletePost } from "./commands/delete-post";
|
||||
import { manageTags, manageCategories } from "./commands/manage-taxonomy";
|
||||
import { exportPostAsMarkdown, exportPostAsJson } from "./commands/export-post";
|
||||
import { searchPosts } from "./commands/search-posts";
|
||||
import { DEFAULT_SETTINGS, type HaloSetting, HaloSettingTab, type HaloSite } from "./settings";
|
||||
import HaloService from "./service";
|
||||
import { openSiteSelectionModal } from "./site-selection-modal";
|
||||
@@ -141,6 +143,44 @@ export default class HaloPlugin extends Plugin {
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "search-posts",
|
||||
name: i18next.t("command.search_posts.name"),
|
||||
callback: async () => {
|
||||
await searchPosts(this);
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "export-post-as-markdown",
|
||||
name: i18next.t("command.export_markdown.name"),
|
||||
editorCallback: async () => {
|
||||
const { activeEditor } = this.app.workspace;
|
||||
if (!activeEditor || !activeEditor.file) return;
|
||||
const matterData = this.app.metadataCache.getFileCache(activeEditor.file)?.frontmatter;
|
||||
if (!matterData?.halo?.name) {
|
||||
new Notice(i18next.t("command.export_markdown.error_not_published"));
|
||||
return;
|
||||
}
|
||||
await exportPostAsMarkdown(this, matterData.halo.name, matterData.title || activeEditor.file.basename);
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "export-post-as-json",
|
||||
name: i18next.t("command.export_json.name"),
|
||||
editorCallback: async () => {
|
||||
const { activeEditor } = this.app.workspace;
|
||||
if (!activeEditor || !activeEditor.file) return;
|
||||
const matterData = this.app.metadataCache.getFileCache(activeEditor.file)?.frontmatter;
|
||||
if (!matterData?.halo?.name) {
|
||||
new Notice(i18next.t("command.export_json.error_not_published"));
|
||||
return;
|
||||
}
|
||||
await exportPostAsJson(this, matterData.halo.name, matterData.title || activeEditor.file.basename);
|
||||
},
|
||||
});
|
||||
|
||||
this.addSettingTab(new HaloSettingTab(this));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import type { ListedPost } from "@halo-dev/api-client";
|
||||
import i18next from "i18next";
|
||||
import { Modal, Notice, Setting, requestUrl } from "obsidian";
|
||||
import type HaloPlugin from "../main";
|
||||
import type { HaloSite } from "../settings";
|
||||
import { exportPostAsMarkdown, exportPostAsJson } from "../commands/export-post";
|
||||
|
||||
export function openSearchModal(plugin: HaloPlugin, site: HaloSite): void {
|
||||
const modal = new SearchModal(plugin, site);
|
||||
modal.open();
|
||||
}
|
||||
|
||||
class SearchModal extends Modal {
|
||||
private posts: ListedPost[] = [];
|
||||
private filteredPosts: ListedPost[] = [];
|
||||
private searchKeyword = "";
|
||||
private filter: "all" | "published" | "draft" = "all";
|
||||
|
||||
constructor(
|
||||
private readonly plugin: HaloPlugin,
|
||||
private readonly site: HaloSite,
|
||||
) {
|
||||
super(app);
|
||||
}
|
||||
|
||||
async onOpen() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
|
||||
contentEl.createEl("h2", {
|
||||
text: i18next.t("search_modal.title"),
|
||||
});
|
||||
|
||||
const searchInput = new Setting(contentEl)
|
||||
.setName(i18next.t("search_modal.search_placeholder"))
|
||||
.addText((text) => {
|
||||
text.setPlaceholder(i18next.t("search_modal.search_placeholder"))
|
||||
.onChange((value) => {
|
||||
this.searchKeyword = value;
|
||||
this.filterPosts();
|
||||
this.renderResults();
|
||||
});
|
||||
});
|
||||
|
||||
const filterEl = contentEl.createDiv("search-filter");
|
||||
|
||||
const allButton = filterEl.createEl("button", {
|
||||
text: i18next.t("post_selection_modal.filter_all"),
|
||||
cls: this.filter === "all" ? "active" : "",
|
||||
});
|
||||
allButton.addEventListener("click", async () => {
|
||||
this.filter = "all";
|
||||
await this.loadPosts();
|
||||
this.renderResults();
|
||||
});
|
||||
|
||||
const publishedButton = filterEl.createEl("button", {
|
||||
text: i18next.t("post_selection_modal.filter_published"),
|
||||
cls: this.filter === "published" ? "active" : "",
|
||||
});
|
||||
publishedButton.addEventListener("click", async () => {
|
||||
this.filter = "published";
|
||||
await this.loadPosts();
|
||||
this.renderResults();
|
||||
});
|
||||
|
||||
const draftButton = filterEl.createEl("button", {
|
||||
text: i18next.t("post_selection_modal.filter_draft"),
|
||||
cls: this.filter === "draft" ? "active" : "",
|
||||
});
|
||||
draftButton.addEventListener("click", async () => {
|
||||
this.filter = "draft";
|
||||
await this.loadPosts();
|
||||
this.renderResults();
|
||||
});
|
||||
|
||||
const resultsEl = contentEl.createDiv("search-results");
|
||||
resultsEl.createEl("p", { text: i18next.t("search_modal.loading") });
|
||||
|
||||
await this.loadPosts();
|
||||
this.renderResults();
|
||||
}
|
||||
|
||||
private async loadPosts() {
|
||||
try {
|
||||
let labelSelector = "content.halo.run/deleted=false";
|
||||
|
||||
if (this.filter === "published") {
|
||||
labelSelector = "content.halo.run/deleted=false,content.halo.run/published=true";
|
||||
} else if (this.filter === "draft") {
|
||||
labelSelector = "content.halo.run/deleted=false,content.halo.run/published=false";
|
||||
}
|
||||
|
||||
const response = await requestUrl({
|
||||
url: `${this.site.url}/apis/uc.api.content.halo.run/v1alpha1/posts?labelSelector=${encodeURIComponent(labelSelector)}&size=100`,
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.site.token}`,
|
||||
},
|
||||
});
|
||||
|
||||
this.posts = response.json.items || [];
|
||||
this.filterPosts();
|
||||
} catch (error) {
|
||||
new Notice(i18next.t("common.error_connection_failed"));
|
||||
}
|
||||
}
|
||||
|
||||
private filterPosts() {
|
||||
if (!this.searchKeyword) {
|
||||
this.filteredPosts = this.posts;
|
||||
return;
|
||||
}
|
||||
|
||||
const keyword = this.searchKeyword.toLowerCase();
|
||||
this.filteredPosts = this.posts.filter((post) => {
|
||||
const title = (post.post.spec.title || "").toLowerCase();
|
||||
const slug = (post.post.spec.slug || "").toLowerCase();
|
||||
return title.includes(keyword) || slug.includes(keyword);
|
||||
});
|
||||
}
|
||||
|
||||
private renderResults() {
|
||||
const { contentEl } = this;
|
||||
const resultsEl = contentEl.querySelector(".search-results") as HTMLElement;
|
||||
|
||||
if (!resultsEl) return;
|
||||
|
||||
resultsEl.empty();
|
||||
|
||||
if (this.filteredPosts.length === 0) {
|
||||
resultsEl.createEl("p", { text: i18next.t("search_modal.no_results") });
|
||||
return;
|
||||
}
|
||||
|
||||
resultsEl.createEl("p", {
|
||||
text: i18next.t("search_modal.result_count", { count: this.filteredPosts.length }),
|
||||
cls: "result-count"
|
||||
});
|
||||
|
||||
for (const post of this.filteredPosts) {
|
||||
this.renderPostItem(post, resultsEl);
|
||||
}
|
||||
}
|
||||
|
||||
private renderPostItem(post: ListedPost, container: HTMLElement) {
|
||||
const postEl = container.createDiv("search-result-item");
|
||||
|
||||
const headerEl = postEl.createDiv("result-header");
|
||||
|
||||
const titleEl = headerEl.createEl("h3", {
|
||||
text: post.post.spec.title || i18next.t("post_selection_modal.untitled"),
|
||||
});
|
||||
|
||||
const statusEl = headerEl.createSpan({
|
||||
text: post.post.spec.publish ? i18next.t("post_selection_modal.status_published") : i18next.t("post_selection_modal.status_draft"),
|
||||
cls: post.post.spec.publish ? "status-published" : "status-draft",
|
||||
});
|
||||
|
||||
const metaEl = postEl.createDiv("result-meta");
|
||||
metaEl.createEl("span", { text: `Slug: ${post.post.spec.slug}` });
|
||||
metaEl.createEl("span", { text: ` | ${new Date(post.post.metadata.creationTimestamp).toLocaleDateString()}` });
|
||||
|
||||
const actionsEl = postEl.createDiv("result-actions");
|
||||
|
||||
actionsEl.createEl("button", {
|
||||
text: i18next.t("search_modal.button_view"),
|
||||
}).addEventListener("click", () => {
|
||||
window.open(`${this.site.url}/archives/${post.post.spec.slug}`, "_blank");
|
||||
});
|
||||
|
||||
actionsEl.createEl("button", {
|
||||
text: i18next.t("search_modal.button_export_md"),
|
||||
}).addEventListener("click", async () => {
|
||||
await exportPostAsMarkdown(this.plugin, post.post.metadata.name, post.post.spec.title);
|
||||
});
|
||||
|
||||
actionsEl.createEl("button", {
|
||||
text: i18next.t("search_modal.button_export_json"),
|
||||
}).addEventListener("click", async () => {
|
||||
await exportPostAsJson(this.plugin, post.post.metadata.name, post.post.spec.title);
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
}
|
||||
@@ -1,544 +0,0 @@
|
||||
{
|
||||
"inventory_metadata": {
|
||||
"generated_at": "2026-04-26 15:15:00",
|
||||
"vault_path": "D:\\Code\\Obsidian",
|
||||
"obsidian_config_path": "D:\\Code\\Obsidian\\.obsidian",
|
||||
"plugins_path": "D:\\Code\\Obsidian\\.obsidian\\plugins",
|
||||
"themes_path": "D:\\Code\\Obsidian\\.obsidian\\themes"
|
||||
},
|
||||
"summary": {
|
||||
"total_community_plugins": 33,
|
||||
"total_core_plugins": 24,
|
||||
"total_themes": 1,
|
||||
"enabled_community_plugins": 33,
|
||||
"desktop_only_plugins": 2,
|
||||
"cross_platform_plugins": 31
|
||||
},
|
||||
"community_plugins": [
|
||||
{
|
||||
"id": "calendar",
|
||||
"name": "Calendar",
|
||||
"version": "1.5.10",
|
||||
"description": "Calendar view of your daily notes",
|
||||
"author": "Liam Cain",
|
||||
"min_app_version": "0.9.11",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\calendar",
|
||||
"has_data_file": true,
|
||||
"has_styles": false,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "cmdr",
|
||||
"name": "Commander",
|
||||
"version": "0.5.4",
|
||||
"description": "Customize your workspace by adding commands everywhere, create Macros and supercharge your mobile toolbar.",
|
||||
"author": "jsmorabito & phibr0",
|
||||
"min_app_version": "1.4.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\cmdr",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "copilot",
|
||||
"name": "Copilot",
|
||||
"version": "3.2.7",
|
||||
"description": "Your AI Copilot: Chat with Your Second Brain, Learn Faster, Work Smarter.",
|
||||
"author": "Logan Yang",
|
||||
"min_app_version": "0.15.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\copilot",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active",
|
||||
"configuration": {
|
||||
"default_model": "MiniMax-M2.7|anthropic",
|
||||
"embedding_model": "text-embedding-3-small|openai",
|
||||
"has_api_key_configured": true,
|
||||
"has_custom_prompts": true,
|
||||
"autonomous_agent_enabled": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dataview",
|
||||
"name": "Dataview",
|
||||
"version": "0.5.68",
|
||||
"description": "Complex data views for the data-obsessed.",
|
||||
"author": "Michael Brenan",
|
||||
"min_app_version": "0.13.11",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\dataview",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-admonition",
|
||||
"name": "Admonition",
|
||||
"version": "10.3.2",
|
||||
"description": "Enhanced callouts for Obsidian.md",
|
||||
"author": "Jeremy Valentine",
|
||||
"min_app_version": "1.1.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-admonition",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-banners",
|
||||
"name": "Banners",
|
||||
"version": "1.3.3",
|
||||
"description": "Add banner images to your notes!",
|
||||
"author": "Danny Hernandez",
|
||||
"min_app_version": "0.13.21",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-banners",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.20.6",
|
||||
"description": "Sketch Your Mind. An Obsidian plugin to edit and view Excalidraw drawings.",
|
||||
"author": "Zsolt Viczian",
|
||||
"min_app_version": "1.5.7",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-excalidraw-plugin",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-git",
|
||||
"name": "Git",
|
||||
"version": "2.38.0",
|
||||
"description": "Integrate Git version control with automatic backup and other advanced features.",
|
||||
"author": "Vinzent",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-git",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-kanban",
|
||||
"name": "Kanban",
|
||||
"version": "2.0.51",
|
||||
"description": "Create markdown-backed Kanban boards in Obsidian.",
|
||||
"author": "mgmeyers",
|
||||
"min_app_version": "1.0.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-kanban",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-tasks-plugin",
|
||||
"name": "Tasks",
|
||||
"version": "7.23.1",
|
||||
"description": "Track tasks across your vault. Supports due dates, recurring tasks, done dates, sub-set of checklist items, and filtering.",
|
||||
"author": "Clare Macrae and Ilyas Landikov",
|
||||
"min_app_version": "1.4.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-tasks-plugin",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "templater-obsidian",
|
||||
"name": "Templater",
|
||||
"version": "2.18.1",
|
||||
"description": "Create and use templates",
|
||||
"author": "SilentVoid",
|
||||
"min_app_version": "1.5.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\templater-obsidian",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "quickadd",
|
||||
"name": "QuickAdd",
|
||||
"version": "2.12.0",
|
||||
"description": "Quickly add new pages or content to your vault.",
|
||||
"author": "Christian B. B. Houmann",
|
||||
"min_app_version": "1.11.4",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\quickadd",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-style-settings",
|
||||
"name": "Style Settings",
|
||||
"version": "1.0.9",
|
||||
"description": "Offers controls for adjusting theme, plugin, and snippet CSS variables.",
|
||||
"author": "mgmeyers",
|
||||
"min_app_version": "0.11.5",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-style-settings",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-minimal-settings",
|
||||
"name": "Minimal Theme Settings",
|
||||
"version": "8.2.1",
|
||||
"description": "Change the colors, fonts and features of Minimal Theme.",
|
||||
"author": "@kepano",
|
||||
"min_app_version": "1.11.1",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-minimal-settings",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-hover-editor",
|
||||
"name": "Hover Editor",
|
||||
"version": "0.11.26",
|
||||
"description": "Transform the Page Preview hover popover into a fully working editor instance",
|
||||
"author": "NothingIsLost",
|
||||
"min_app_version": "1.5.8",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-hover-editor",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "omnisearch",
|
||||
"name": "Omnisearch",
|
||||
"version": "1.28.2",
|
||||
"description": "A search engine that just works",
|
||||
"author": "Simon Cambier",
|
||||
"min_app_version": "1.7.2",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\omnisearch",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "floating-toc",
|
||||
"name": "floating toc",
|
||||
"version": "2.7.0",
|
||||
"description": "This is a floating Toc plugin that hovers a table of content containing a header level on the notes sidebar.",
|
||||
"author": "Cuman",
|
||||
"min_app_version": "0.14.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\floating-toc",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "editing-toolbar",
|
||||
"name": "Editing Toolbar",
|
||||
"version": "3.1.18",
|
||||
"description": "The Obsidian Editing Toolbar is modified from cmenu, which provides more powerful customization settings.",
|
||||
"author": "Cuman",
|
||||
"min_app_version": "0.14.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\editing-toolbar",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-outliner",
|
||||
"name": "Outliner",
|
||||
"version": "4.9.0",
|
||||
"description": "Work with your lists like in Workflowy or RoamResearch.",
|
||||
"author": "Viacheslav Slinko",
|
||||
"min_app_version": "1.8.7",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-outliner",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-importer",
|
||||
"name": "Importer",
|
||||
"version": "1.8.4",
|
||||
"description": "Import data from Notion, Evernote, Apple Notes, Microsoft OneNote, Google Keep, Bear, Roam, Textbundle, CSV, and HTML files.",
|
||||
"author": "Obsidian",
|
||||
"min_app_version": "0.15.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-importer",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "tag-wrangler",
|
||||
"name": "Tag Wrangler",
|
||||
"version": "0.6.4",
|
||||
"description": "Rename, merge, toggle, and search tags from the tags view",
|
||||
"author": "PJ Eby",
|
||||
"min_app_version": "1.5.8",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\tag-wrangler",
|
||||
"has_data_file": false,
|
||||
"has_styles": false,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "table-editor-obsidian",
|
||||
"name": "Advanced Tables",
|
||||
"version": "0.22.1",
|
||||
"description": "Improved table navigation, formatting, manipulation, and formulas",
|
||||
"author": "Tony Grosinger",
|
||||
"min_app_version": "1.0.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\table-editor-obsidian",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-icon-folder",
|
||||
"name": "Iconize",
|
||||
"version": "2.14.7",
|
||||
"description": "Add icons to anything you desire in Obsidian, including files, folders, and text.",
|
||||
"author": "Florian Woelki",
|
||||
"min_app_version": "0.9.12",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-icon-folder",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "recent-files-obsidian",
|
||||
"name": "Recent Files",
|
||||
"version": "1.7.4",
|
||||
"description": "List files by most recently opened",
|
||||
"author": "Tony Grosinger",
|
||||
"min_app_version": "0.16.3",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\recent-files-obsidian",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "remotely-save",
|
||||
"name": "Remotely Save",
|
||||
"version": "0.5.25",
|
||||
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
|
||||
"author": "fyears",
|
||||
"min_app_version": "0.13.21",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\remotely-save",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "homepage",
|
||||
"name": "Homepage",
|
||||
"version": "4.2.2",
|
||||
"description": "Open a specified note, canvas, base, or workspace on startup, or set it for quick access later.",
|
||||
"author": "novov",
|
||||
"min_app_version": "1.4.10",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\homepage",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "easy-typing-obsidian",
|
||||
"name": "Easy Typing",
|
||||
"version": "5.5.15",
|
||||
"description": "This plugin aims to enhance and optimize the editing experience in Obsidian",
|
||||
"author": "yaozhuwa",
|
||||
"min_app_version": "0.15.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\easy-typing-obsidian",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "obsidian-mind-map",
|
||||
"name": "Mind Map",
|
||||
"version": "1.1.0",
|
||||
"description": "A plugin to preview notes as Markmap mind maps",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\obsidian-mind-map",
|
||||
"has_data_file": false,
|
||||
"has_styles": false,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "mermaid-tools",
|
||||
"name": "Mermaid Tools",
|
||||
"version": "1.3.0",
|
||||
"description": "Improved Mermaid.js experience for Obsidian: visual toolbar with common elements & more",
|
||||
"author": "dartungar",
|
||||
"min_app_version": "1.4.0",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\mermaid-tools",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "multi-column-markdown",
|
||||
"name": "Multi-Column Markdown",
|
||||
"version": "0.9.1",
|
||||
"description": "This plugin adds functionality to create markdown documents with multiple columns of content viewable within Obsidian's preview mode",
|
||||
"author": "Cameron Robinson",
|
||||
"min_app_version": "1.5.3",
|
||||
"is_desktop_only": false,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\multi-column-markdown",
|
||||
"has_data_file": false,
|
||||
"has_styles": true,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"id": "mousewheel-image-zoom",
|
||||
"name": "Mousewheel Image zoom",
|
||||
"version": "1.0.24",
|
||||
"description": "This plugin enables you to increase/decrease the size of an image by scrolling",
|
||||
"author": "Nico Jeske",
|
||||
"min_app_version": "0.9.12",
|
||||
"is_desktop_only": true,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\mousewheel-image-zoom",
|
||||
"has_data_file": false,
|
||||
"has_styles": false,
|
||||
"status": "active",
|
||||
"warning": "Desktop-only plugin"
|
||||
},
|
||||
{
|
||||
"id": "drawio-obsidian",
|
||||
"name": "Diagrams",
|
||||
"version": "1.5.4",
|
||||
"description": "Draw.io diagrams for Obsidian.",
|
||||
"author": "Sam Greenhalgh",
|
||||
"min_app_version": "0.9.12",
|
||||
"is_desktop_only": true,
|
||||
"enabled": true,
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\plugins\\drawio-obsidian",
|
||||
"has_data_file": true,
|
||||
"has_styles": true,
|
||||
"status": "active",
|
||||
"warning": "Desktop-only plugin"
|
||||
}
|
||||
],
|
||||
"core_plugins": {
|
||||
"enabled": [
|
||||
"file-explorer",
|
||||
"global-search",
|
||||
"switcher",
|
||||
"graph",
|
||||
"backlink",
|
||||
"canvas",
|
||||
"outgoing-link",
|
||||
"tag-pane",
|
||||
"page-preview",
|
||||
"daily-notes",
|
||||
"templates",
|
||||
"note-composer",
|
||||
"command-palette",
|
||||
"editor-status",
|
||||
"bookmarks",
|
||||
"outline",
|
||||
"word-count",
|
||||
"file-recovery",
|
||||
"sync",
|
||||
"bases"
|
||||
],
|
||||
"disabled": [
|
||||
"footnotes",
|
||||
"properties",
|
||||
"slash-command",
|
||||
"markdown-importer",
|
||||
"zk-prefixer",
|
||||
"random-note",
|
||||
"slides",
|
||||
"audio-recorder",
|
||||
"workspaces",
|
||||
"publish",
|
||||
"webviewer"
|
||||
]
|
||||
},
|
||||
"themes": [
|
||||
{
|
||||
"name": "Minimal",
|
||||
"version": "8.1.6",
|
||||
"author": "@kepano",
|
||||
"min_app_version": "1.9.0",
|
||||
"install_path": "D:\\Code\\Obsidian\\.obsidian\\themes\\Minimal",
|
||||
"status": "active"
|
||||
}
|
||||
],
|
||||
"verification_notes": {
|
||||
"how_to_verify_plugins_downloaded": [
|
||||
"1. 检查插件目录:导航到 D:\\Code\\Obsidian\\.obsidian\\plugins",
|
||||
"2. 每个插件都有自己的子文件夹,文件夹名称就是插件ID",
|
||||
"3. 必需的插件文件包括:",
|
||||
" - manifest.json:插件元数据文件",
|
||||
" - main.js:插件的主代码文件",
|
||||
" - styles.css:可选的样式文件(如果插件有UI样式)",
|
||||
" - data.json:可选的数据存储文件(如果插件有用户配置)",
|
||||
"4. 验证方法:在文件资源管理器中打开插件文件夹,确认所需文件存在",
|
||||
"5. 检查插件是否启用:查看 community-plugins.json 文件,确认插件ID在列表中",
|
||||
"6. 查看 Obsidian 设置:在 Obsidian 应用中进入 Settings > Community Plugins 查看已安装和启用的插件"
|
||||
],
|
||||
"compatibility_check": [
|
||||
"所有插件的 minAppVersion 要求都已满足",
|
||||
"Obsidian 版本应 >= 1.8.7(基于 obsidian-outliner 的要求)",
|
||||
"所有插件都标记为 isDesktopOnly: false,除了 drawio-obsidian 和 mousewheel-image-zoom"
|
||||
],
|
||||
"dependencies": [
|
||||
"Minimal Theme Settings 需要配合 Minimal 主题使用",
|
||||
"Style Settings 可用于调整主题和插件的 CSS 变量",
|
||||
"多个插件可能依赖 Dataview 插件进行数据查询"
|
||||
]
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ halo:
|
||||
## 一、现有标签列表
|
||||
|
||||
| 标签名称 | 显示名称 | 颜色 |
|
||||
|---------|---------|------|
|
||||
| ---------------------- | ----- | ------- |
|
||||
| xie-hui-dong-tai | 协会动态 | #B8E986 |
|
||||
| 5fen-zhong-su-lan | 5分钟速览 | #50E3C2 |
|
||||
| ji-shu-shen-qian | 技术深潜 | #4A90E2 |
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# 深度学习完全指南:从理论基础到实践入门
|
||||
# 深度学习完全指南:从理论基础到实践入门
|
||||
|
||||
> 作者:人工智能协会比赛部部长
|
||||
|
||||
|
||||
Reference in New Issue
Block a user