返回 slidev
projectsTree.ts
根目录 / packages / vscode / src / views / projectsTree.ts
1 import type { TreeViewNode } from 'reactive-vscode'
2 import type { TreeItem } from 'vscode'
3 import type { SlidevProject } from '../projects'
4 import { isDeepEqual } from '@antfu/utils'
5 import { computed, defineService, shallowRef, useTreeView, watch } from 'reactive-vscode'
6 import { ThemeIcon, TreeItemCollapsibleState, Uri } from 'vscode'
7 import { activeEntry, projects } from '../projects'
8 import { getSlidesTitle } from '../utils/getSlidesTitle'
9 import { toRelativePath } from '../utils/toRelativePath'
10
11 /**
12 * No projects has dependency files. Then it would be weired to show a collapse button.
13 */
14 const nothingToCollapse = computed(() => [...projects.values()]
15 .every(project => Object.keys(project.data.markdownFiles).length <= 1))
16
17 function getProjectTreeItem(project: SlidevProject): TreeItem {
18 const active = activeEntry.value === project.entry
19 return {
20 label: toRelativePath(project.entry),
21 description: `${getSlidesTitle(project.data)}${project.detected.value?.ready ? ` (port: ${project.detected.value.port})` : ''}`,
22 resourceUri: Uri.file(project.entry),
23 iconPath: new ThemeIcon(active ? 'eye' : 'eye-closed'),
24 collapsibleState: nothingToCollapse.value ? TreeItemCollapsibleState.None : active ? TreeItemCollapsibleState.Expanded : TreeItemCollapsibleState.Collapsed,
25 contextValue: `<project><${active ? 'active' : 'inactive'}>`,
26 command: {
27 title: 'Open',
28 command: 'vscode.open',
29 arguments: [Uri.file(project.entry)],
30 },
31 }
32 }
33
34 function getFileTreeItem(file: string): TreeItem {
35 return {
36 resourceUri: Uri.file(file),
37 iconPath: new ThemeIcon('file'),
38 collapsibleState: TreeItemCollapsibleState.None,
39 command: {
40 title: 'Open',
41 command: 'vscode.open',
42 arguments: [Uri.file(file)],
43 },
44 }
45 }
46
47 export const useProjectsTree = defineService(() => {
48 const treeData = computed(() => {
49 return [...projects.values()]
50 .sort((a, b) => a.entry.localeCompare(b.entry, undefined, { numeric: true }))
51 .map(project => ({
52 treeItem: getProjectTreeItem(project),
53 children: Object.keys(project.data.markdownFiles)
54 .filter(file => file.toLowerCase() !== project.entry.toLowerCase())
55 .sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))
56 .map(file => ({ treeItem: getFileTreeItem(file) })),
57 }))
58 })
59
60 const treeItems = shallowRef<TreeViewNode[]>([])
61 watch(treeData, (treeData) => {
62 if (!isDeepEqual(treeItems.value, treeData)) {
63 treeItems.value = treeData
64 }
65 }, { immediate: true })
66
67 const treeView = useTreeView('slidev-projects-tree', treeItems, {
68 showCollapseAll: true,
69 })
70
71 return treeView
72 })
73
73 lines TYPESCRIPT