@lapis-notes/lapis-plugin-docs 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/README.md +188 -2
  2. package/dist/docs/DocsBlockMarkdownEditor.svelte +37 -0
  3. package/dist/docs/DocsBlockMarkdownEditor.svelte.d.ts +13 -0
  4. package/dist/docs/DocsBlockRefPicker.svelte +75 -0
  5. package/dist/docs/DocsBlockRefPicker.svelte.d.ts +11 -0
  6. package/dist/docs/DocsBookEditor.svelte +141 -0
  7. package/dist/docs/DocsBookEditor.svelte.d.ts +10 -0
  8. package/dist/docs/DocsBookNavigation.svelte +838 -0
  9. package/dist/docs/DocsBookNavigation.svelte.d.ts +11 -0
  10. package/dist/docs/DocsBooksColumn.svelte +82 -0
  11. package/dist/docs/DocsBooksColumn.svelte.d.ts +10 -0
  12. package/dist/docs/DocsCardBackMatter.svelte +32 -0
  13. package/dist/docs/DocsCardBackMatter.svelte.d.ts +10 -0
  14. package/dist/docs/DocsCardBlockExtra.svelte +43 -0
  15. package/dist/docs/DocsCardBlockExtra.svelte.d.ts +9 -0
  16. package/dist/docs/DocsCardPreviewFlip.svelte +143 -0
  17. package/dist/docs/DocsCardPreviewFlip.svelte.d.ts +17 -0
  18. package/dist/docs/DocsCardPreviewStack.svelte +135 -0
  19. package/dist/docs/DocsCardPreviewStack.svelte.d.ts +13 -0
  20. package/dist/docs/DocsCardPrompt.svelte +33 -0
  21. package/dist/docs/DocsCardPrompt.svelte.d.ts +8 -0
  22. package/dist/docs/DocsCardReviewAnswer.svelte +45 -0
  23. package/dist/docs/DocsCardReviewAnswer.svelte.d.ts +8 -0
  24. package/dist/docs/DocsCardTagChips.svelte +19 -0
  25. package/dist/docs/DocsCardTagChips.svelte.d.ts +7 -0
  26. package/dist/docs/DocsCardsPanel.svelte +232 -0
  27. package/dist/docs/DocsCardsPanel.svelte.d.ts +17 -0
  28. package/dist/docs/DocsCardsReview.css +1050 -0
  29. package/dist/docs/DocsChapterFooter.svelte +248 -0
  30. package/dist/docs/DocsChapterFooter.svelte.d.ts +11 -0
  31. package/dist/docs/DocsChapterScrollRing.svelte +101 -0
  32. package/dist/docs/DocsChapterScrollRing.svelte.d.ts +6 -0
  33. package/dist/docs/DocsDisplayPanel.css +627 -0
  34. package/dist/docs/DocsDisplayPanel.svelte +78 -0
  35. package/dist/docs/DocsDisplayPanel.svelte.d.ts +16 -0
  36. package/dist/docs/DocsEditorPanel.css +325 -0
  37. package/dist/docs/DocsEditorPanel.svelte +570 -0
  38. package/dist/docs/DocsEditorPanel.svelte.d.ts +22 -0
  39. package/dist/docs/DocsFlipCard.svelte +68 -0
  40. package/dist/docs/DocsFlipCard.svelte.d.ts +8 -0
  41. package/dist/docs/DocsFolderDirectoryList.svelte +206 -0
  42. package/dist/docs/DocsFolderDirectoryList.svelte.d.ts +14 -0
  43. package/dist/docs/DocsFolderPanel.css +357 -0
  44. package/dist/docs/DocsFolderPanel.svelte +102 -0
  45. package/dist/docs/DocsFolderPanel.svelte.d.ts +17 -0
  46. package/dist/docs/DocsLinksPanel.css +61 -0
  47. package/dist/docs/DocsLinksPanel.svelte +55 -0
  48. package/dist/docs/DocsLinksPanel.svelte.d.ts +11 -0
  49. package/dist/docs/DocsMarkdownField.svelte +93 -0
  50. package/dist/docs/DocsMarkdownField.svelte.d.ts +11 -0
  51. package/dist/docs/DocsMarkdownPreview.svelte +278 -0
  52. package/dist/docs/DocsMarkdownPreview.svelte.d.ts +17 -0
  53. package/dist/docs/DocsReviewPanel.svelte +63 -0
  54. package/dist/docs/DocsReviewPanel.svelte.d.ts +11 -0
  55. package/dist/docs/DocsRichBlock.svelte +291 -0
  56. package/dist/docs/DocsRichBlock.svelte.d.ts +13 -0
  57. package/dist/docs/DocsRichDisplay.svelte +316 -0
  58. package/dist/docs/DocsRichDisplay.svelte.d.ts +14 -0
  59. package/dist/docs/DocsSlidesPreview.css +243 -0
  60. package/dist/docs/DocsSlidesPreview.svelte +206 -0
  61. package/dist/docs/DocsSlidesPreview.svelte.d.ts +10 -0
  62. package/dist/docs/DocsWorkspace.css +570 -0
  63. package/dist/docs/DocsWorkspace.svelte +831 -0
  64. package/dist/docs/DocsWorkspace.svelte.d.ts +48 -0
  65. package/dist/docs/DocsWorkspaceToolbar.svelte +211 -0
  66. package/dist/docs/DocsWorkspaceToolbar.svelte.d.ts +27 -0
  67. package/dist/docs/candidates/ChoiceMenu.svelte +114 -0
  68. package/dist/docs/candidates/ChoiceMenu.svelte.d.ts +10 -0
  69. package/dist/docs/candidates/FlipCardDeck.svelte +800 -0
  70. package/dist/docs/candidates/FlipCardDeck.svelte.d.ts +36 -0
  71. package/dist/docs/candidates/MarkdownFloatingToc.svelte +313 -0
  72. package/dist/docs/candidates/MarkdownFloatingToc.svelte.d.ts +14 -0
  73. package/dist/docs/candidates/SearchableChoicePicker.css +161 -0
  74. package/dist/docs/candidates/SearchableChoicePicker.svelte +208 -0
  75. package/dist/docs/candidates/SearchableChoicePicker.svelte.d.ts +19 -0
  76. package/dist/docs/candidates/StructuredTable.svelte +98 -0
  77. package/dist/docs/candidates/StructuredTable.svelte.d.ts +8 -0
  78. package/dist/docs/candidates/StructuredTableEditor.svelte +374 -0
  79. package/dist/docs/candidates/StructuredTableEditor.svelte.d.ts +12 -0
  80. package/dist/docs/candidates/TagEditor.svelte +31 -0
  81. package/dist/docs/candidates/TagEditor.svelte.d.ts +14 -0
  82. package/dist/docs/candidates/WorkspaceHistoryControls.svelte +112 -0
  83. package/dist/docs/candidates/WorkspaceHistoryControls.svelte.d.ts +8 -0
  84. package/dist/docs/candidates/markdown-floating-toc.css +151 -0
  85. package/dist/docs/candidates/markdown-floating-toc.d.ts +1 -0
  86. package/dist/docs/candidates/markdown-floating-toc.js +1 -0
  87. package/dist/docs/docs-anki-import.d.ts +34 -0
  88. package/dist/docs/docs-anki-import.js +516 -0
  89. package/dist/docs/docs-book-view-model.d.ts +9 -0
  90. package/dist/docs/docs-book-view-model.js +71 -0
  91. package/dist/docs/docs-card-answer-markdown.d.ts +1 -0
  92. package/dist/docs/docs-card-answer-markdown.js +63 -0
  93. package/dist/docs/docs-card-display.d.ts +10 -0
  94. package/dist/docs/docs-card-display.js +18 -0
  95. package/dist/docs/docs-display-focus.d.ts +7 -0
  96. package/dist/docs/docs-display-focus.js +42 -0
  97. package/dist/docs/docs-document-surface.d.ts +7 -0
  98. package/dist/docs/docs-document-surface.js +25 -0
  99. package/dist/docs/docs-folder-directory.d.ts +21 -0
  100. package/dist/docs/docs-folder-directory.js +56 -0
  101. package/dist/docs/docs-link-mode.d.ts +16 -0
  102. package/dist/docs/docs-link-mode.js +94 -0
  103. package/dist/docs/docs-workspace-helpers.d.ts +25 -0
  104. package/dist/docs/docs-workspace-helpers.js +195 -0
  105. package/dist/docs/docs.tokens.css +13 -0
  106. package/dist/docs/import-anki-package.d.ts +10 -0
  107. package/dist/docs/import-anki-package.js +30 -0
  108. package/dist/docs/lapis-markdown-extensions.d.ts +9 -0
  109. package/dist/docs/lapis-markdown-extensions.js +128 -0
  110. package/dist/docs/pin-reading-chrome.d.ts +4 -0
  111. package/dist/docs/pin-reading-chrome.js +32 -0
  112. package/dist/docs/sidebar/DocsFoldersSidebar.svelte +134 -0
  113. package/dist/docs/sidebar/DocsFoldersSidebar.svelte.d.ts +15 -0
  114. package/dist/docs/sidebar/DocsLinksSidebar.svelte +105 -0
  115. package/dist/docs/sidebar/DocsLinksSidebar.svelte.d.ts +11 -0
  116. package/dist/docs/sidebar/DocsSidebar.css +346 -0
  117. package/dist/docs/sidebar/DocsSidebar.svelte +430 -0
  118. package/dist/docs/sidebar/DocsSidebar.svelte.d.ts +18 -0
  119. package/dist/docs/sidebar/DocsSidebarHost.svelte +139 -0
  120. package/dist/docs/sidebar/DocsSidebarHost.svelte.d.ts +12 -0
  121. package/dist/docs/sidebar/DocsTagsSidebar.svelte +176 -0
  122. package/dist/docs/sidebar/DocsTagsSidebar.svelte.d.ts +12 -0
  123. package/dist/docs/sidebar/docs-book-note-tree.d.ts +23 -0
  124. package/dist/docs/sidebar/docs-book-note-tree.js +88 -0
  125. package/dist/docs/sidebar/docs-note-sort.d.ts +26 -0
  126. package/dist/docs/sidebar/docs-note-sort.js +54 -0
  127. package/dist/docs/sidebar/docs-sidebar-filters.d.ts +17 -0
  128. package/dist/docs/sidebar/docs-sidebar-filters.js +74 -0
  129. package/dist/docs/sidebar/docs-sidebar-ui-storage.d.ts +24 -0
  130. package/dist/docs/sidebar/docs-sidebar-ui-storage.js +87 -0
  131. package/dist/docs/sidebar/docs-source-folder-tree.d.ts +16 -0
  132. package/dist/docs/sidebar/docs-source-folder-tree.js +143 -0
  133. package/dist/docs/sidebar/docs-tag-tree.d.ts +17 -0
  134. package/dist/docs/sidebar/docs-tag-tree.js +84 -0
  135. package/dist/docs-cards-view.d.ts +18 -0
  136. package/dist/docs-cards-view.js +52 -0
  137. package/dist/docs-document-view.d.ts +24 -0
  138. package/dist/docs-document-view.js +127 -0
  139. package/dist/docs-document-workspace.svelte +215 -0
  140. package/dist/docs-document-workspace.svelte.d.ts +16 -0
  141. package/dist/docs-index.d.ts +5 -0
  142. package/dist/docs-index.js +49 -0
  143. package/dist/docs-path.d.ts +6 -0
  144. package/dist/docs-path.js +10 -0
  145. package/dist/docs-plugin.d.ts +21 -0
  146. package/dist/docs-plugin.js +140 -0
  147. package/dist/docs-repository.d.ts +15 -0
  148. package/dist/docs-repository.js +75 -0
  149. package/dist/docs-review-view.d.ts +18 -0
  150. package/dist/docs-review-view.js +52 -0
  151. package/dist/docs-settings-tab.d.ts +8 -0
  152. package/dist/docs-settings-tab.js +25 -0
  153. package/dist/docs-settings.d.ts +17 -0
  154. package/dist/docs-settings.js +38 -0
  155. package/dist/docs-view.d.ts +22 -0
  156. package/dist/docs-view.js +51 -0
  157. package/dist/docs-workspace.svelte +394 -0
  158. package/dist/docs-workspace.svelte.d.ts +15 -0
  159. package/dist/index.d.ts +12 -0
  160. package/dist/index.js +12 -0
  161. package/dist/model/book.d.ts +6 -0
  162. package/dist/model/book.js +101 -0
  163. package/dist/model/coding-runtime.d.ts +4 -0
  164. package/dist/model/coding-runtime.js +9 -0
  165. package/dist/model/docs-card-context.d.ts +32 -0
  166. package/dist/model/docs-card-context.js +89 -0
  167. package/dist/model/docs-card-preview-stack-motion.d.ts +51 -0
  168. package/dist/model/docs-card-preview-stack-motion.js +94 -0
  169. package/dist/model/docs-media-context.d.ts +9 -0
  170. package/dist/model/docs-media-context.js +18 -0
  171. package/dist/model/docs-note-list.d.ts +8 -0
  172. package/dist/model/docs-note-list.js +25 -0
  173. package/dist/model/docs-relative-media.d.ts +30 -0
  174. package/dist/model/docs-relative-media.js +116 -0
  175. package/dist/model/docs-review-constants.d.ts +4 -0
  176. package/dist/model/docs-review-constants.js +13 -0
  177. package/dist/model/fsrs.d.ts +14 -0
  178. package/dist/model/fsrs.js +153 -0
  179. package/dist/model/graph.d.ts +12 -0
  180. package/dist/model/graph.js +169 -0
  181. package/dist/model/index.d.ts +14 -0
  182. package/dist/model/index.js +14 -0
  183. package/dist/model/markdown-normalize.d.ts +11 -0
  184. package/dist/model/markdown-normalize.js +755 -0
  185. package/dist/model/markdown.d.ts +167 -0
  186. package/dist/model/markdown.js +365 -0
  187. package/dist/model/sample.d.ts +7 -0
  188. package/dist/model/sample.js +524 -0
  189. package/dist/model/types.d.ts +328 -0
  190. package/dist/model/types.js +1 -0
  191. package/dist/model/workspace.d.ts +6 -0
  192. package/dist/model/workspace.js +81 -0
  193. package/dist/storybook.css +52 -0
  194. package/dist/styles.css +1 -0
  195. package/manifest.json +11 -0
  196. package/package.json +147 -4
@@ -0,0 +1,206 @@
1
+ <script lang="ts">
2
+ import "./DocsFolderPanel.css";
3
+
4
+ import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
5
+ import * as ScrollArea from "@lapismd/design-core/shadcn/scroll-area";
6
+
7
+ import {
8
+ getActiveFolderNote,
9
+ getActiveFolderTagKey,
10
+ getFolderNotePanels,
11
+ getFolderNotes,
12
+ getMatchingFolderTags,
13
+ isDocsSidebarPanelActive,
14
+ resolveDocsSidebarPanelSelection,
15
+ } from "./docs-folder-directory";
16
+ import type { DocsNote, DocsNotePanel, DocsNoteSummary, DocsWorkspace, DocsWorkspaceIndex } from '../model';
17
+
18
+ let {
19
+ workspace = null,
20
+ activeTag = null,
21
+ activeNoteId = null,
22
+ activePanel = "note",
23
+ onSelectNote = () => {},
24
+ onSelectPanel = () => {},
25
+ onSelectTag = () => {},
26
+ }: {
27
+ workspace?: DocsWorkspace | DocsWorkspaceIndex | null;
28
+ activeTag?: string | null;
29
+ activeNoteId?: string | null;
30
+ activePanel?: DocsNotePanel;
31
+ onSelectNote?: (noteId: string) => void;
32
+ onSelectPanel?: (panel: DocsNotePanel) => void;
33
+ onSelectTag?: (tag: string) => void;
34
+ } = $props();
35
+
36
+ let expandedNoteIds = $state<Record<string, boolean>>({});
37
+
38
+ const folderNotes = $derived(getFolderNotes(workspace, activeTag));
39
+ const activeFolderNote = $derived(getActiveFolderNote(folderNotes, activeNoteId));
40
+ const matchingTags = $derived(getMatchingFolderTags(activeTag, activeFolderNote));
41
+ const activeTagKey = $derived(getActiveFolderTagKey(activeTag));
42
+ const TREE_ROW_BASE_INDENT_REM = 0.25;
43
+ const TREE_ROW_DEPTH_INDENT_REM = 0.875;
44
+ const TREE_GUIDE_BASE_LEFT_REM = 0.75;
45
+ const TREE_PANEL_LABEL_OFFSET_REM = 1.75;
46
+ const TREE_PANEL_PARENT_GUIDE_OFFSET_REM = 0;
47
+
48
+ function notePanels(note: DocsNote | DocsNoteSummary) {
49
+ return getFolderNotePanels(workspace, note);
50
+ }
51
+
52
+ function isNoteExpanded(noteId: string) {
53
+ return activeNoteId === noteId
54
+ ? (expandedNoteIds[noteId] ?? true)
55
+ : (expandedNoteIds[noteId] ?? false);
56
+ }
57
+
58
+ function setNoteExpanded(noteId: string, open: boolean) {
59
+ expandedNoteIds = open
60
+ ? {
61
+ [noteId]: true,
62
+ ...(activeNoteId && activeNoteId !== noteId
63
+ ? { [activeNoteId]: false }
64
+ : {}),
65
+ }
66
+ : { [noteId]: false };
67
+ }
68
+
69
+ function treeRowStyle(depth: number) {
70
+ const safeDepth = Math.max(depth, 0);
71
+ return `padding-left: ${TREE_ROW_BASE_INDENT_REM + safeDepth * TREE_ROW_DEPTH_INDENT_REM}rem`;
72
+ }
73
+
74
+ function treePanelRowStyle(depth: number) {
75
+ const safeDepth = Math.max(depth, 0);
76
+ return `padding-left: ${
77
+ TREE_ROW_BASE_INDENT_REM +
78
+ safeDepth * TREE_ROW_DEPTH_INDENT_REM +
79
+ TREE_PANEL_LABEL_OFFSET_REM
80
+ }rem`;
81
+ }
82
+
83
+ function treeGuideStyle(depth: number, offsetRem = 0) {
84
+ return `left: ${TREE_GUIDE_BASE_LEFT_REM + depth * TREE_ROW_DEPTH_INDENT_REM + offsetRem}rem`;
85
+ }
86
+
87
+ function treeGuideDepths(depth: number) {
88
+ return Array.from({ length: Math.max(depth, 0) }, (_, index) => index);
89
+ }
90
+
91
+ function toggleNoteRow(noteId: string) {
92
+ if (activeNoteId === noteId) {
93
+ setNoteExpanded(noteId, !isNoteExpanded(noteId));
94
+ return;
95
+ }
96
+ selectNote(noteId);
97
+ }
98
+
99
+ function toggleNoteExpanded(noteId: string) {
100
+ setNoteExpanded(noteId, !isNoteExpanded(noteId));
101
+ }
102
+
103
+ function selectNote(noteId: string) {
104
+ setNoteExpanded(noteId, true);
105
+ onSelectNote(noteId);
106
+ }
107
+
108
+ function selectNotePanel(noteId: string, panel: DocsNotePanel) {
109
+ setNoteExpanded(noteId, true);
110
+ if (activeNoteId !== noteId) onSelectNote(noteId);
111
+ onSelectPanel(resolveDocsSidebarPanelSelection(panel));
112
+ }
113
+
114
+ function isNotePanelActive(panel: DocsNotePanel) {
115
+ return isDocsSidebarPanelActive(activePanel, panel);
116
+ }
117
+ </script>
118
+
119
+ {#snippet TreeGuides({ depth, finalGuideOffsetRem = 0 }: { depth: number; finalGuideOffsetRem?: number })}
120
+ {#each treeGuideDepths(depth) as guideDepth (guideDepth)}
121
+ <span
122
+ aria-hidden="true"
123
+ class="docs-folder-panel__indent-guide"
124
+ style={treeGuideStyle(
125
+ guideDepth,
126
+ guideDepth === depth - 1 ? finalGuideOffsetRem : 0,
127
+ )}
128
+ data-folder-panel-indent-guide={guideDepth}
129
+ ></span>
130
+ {/each}
131
+ {/snippet}
132
+
133
+ {#if activeTag}
134
+ <div class="docs-folder-panel__body">
135
+ <ScrollArea.Root class="docs-folder-panel__list">
136
+ <div class="docs-folder-panel__list-content">
137
+ {#each folderNotes as note (note.id)}
138
+ {@const expanded = isNoteExpanded(note.id)}
139
+ {@const active = note.id === activeNoteId}
140
+ <div class="docs-folder-panel__note-group">
141
+ <button
142
+ type="button"
143
+ class="docs-folder-panel__note-row"
144
+ style={treeRowStyle(0)}
145
+ aria-expanded={expanded}
146
+ data-folder-panel-note-row={note.id}
147
+ onclick={() => toggleNoteRow(note.id)}
148
+ >
149
+ <ChevronRightIcon
150
+ class={expanded
151
+ ? "docs-folder-panel__tree-chevron expanded"
152
+ : "docs-folder-panel__tree-chevron"}
153
+ data-icon="inline-start"
154
+ />
155
+ <span>{note.title}</span>
156
+ </button>
157
+ {#if expanded}
158
+ <div class="docs-folder-panel__children" data-folder-panel-note-panels={note.id}>
159
+ {#each notePanels(note) as panel (panel.id)}
160
+ <button
161
+ type="button"
162
+ class:active={active && isNotePanelActive(panel.id)}
163
+ class="docs-folder-panel__child"
164
+ style={treePanelRowStyle(0)}
165
+ aria-label={typeof panel.count === "number"
166
+ ? `${note.title} ${panel.label} ${panel.count}`
167
+ : `${note.title} ${panel.label}`}
168
+ aria-current={active && isNotePanelActive(panel.id) ? "true" : undefined}
169
+ onclick={() => selectNotePanel(note.id, panel.id)}
170
+ >
171
+ {@render TreeGuides({
172
+ depth: 1,
173
+ finalGuideOffsetRem: TREE_PANEL_PARENT_GUIDE_OFFSET_REM,
174
+ })}
175
+ <span>{panel.label}</span>
176
+ {#if typeof panel.count === "number"}
177
+ <span class="docs-folder-panel__child-count">{panel.count}</span>
178
+ {/if}
179
+ </button>
180
+ {/each}
181
+ </div>
182
+ {/if}
183
+ </div>
184
+ {:else}
185
+ <p class="docs-folder-panel__empty">No notes use this folder yet.</p>
186
+ {/each}
187
+ </div>
188
+ </ScrollArea.Root>
189
+ {#if matchingTags.length}
190
+ <div class="docs-folder-panel__tags" aria-label="Matching tags">
191
+ {#each matchingTags as tag (tag)}
192
+ <button
193
+ type="button"
194
+ class="docs-folder-panel__tag-chip"
195
+ class:active={activeTagKey === tag.toLowerCase()}
196
+ aria-pressed={activeTagKey === tag.toLowerCase()}
197
+ title={`#${tag}`}
198
+ onclick={() => onSelectTag(tag)}
199
+ >
200
+ #{tag}
201
+ </button>
202
+ {/each}
203
+ </div>
204
+ {/if}
205
+ </div>
206
+ {/if}
@@ -0,0 +1,14 @@
1
+ import "./DocsFolderPanel.css";
2
+ import type { DocsNotePanel, DocsWorkspace, DocsWorkspaceIndex } from '../model';
3
+ type $$ComponentProps = {
4
+ workspace?: DocsWorkspace | DocsWorkspaceIndex | null;
5
+ activeTag?: string | null;
6
+ activeNoteId?: string | null;
7
+ activePanel?: DocsNotePanel;
8
+ onSelectNote?: (noteId: string) => void;
9
+ onSelectPanel?: (panel: DocsNotePanel) => void;
10
+ onSelectTag?: (tag: string) => void;
11
+ };
12
+ declare const DocsFolderDirectoryList: import("svelte").Component<$$ComponentProps, {}, "">;
13
+ type DocsFolderDirectoryList = ReturnType<typeof DocsFolderDirectoryList>;
14
+ export default DocsFolderDirectoryList;
@@ -0,0 +1,357 @@
1
+ .docs-folder-panel {
2
+ display: flex;
3
+ flex: 0 0 17rem;
4
+ align-self: stretch;
5
+ min-height: 0;
6
+ max-width: 17rem;
7
+ flex-direction: column;
8
+ background: color-mix(in srgb, var(--docs-subtle) 42%, var(--docs-surface));
9
+ color: var(--foreground, #111);
10
+ }
11
+
12
+ .docs-folder-panel--collapsed {
13
+ flex-basis: 3rem;
14
+ max-width: 3rem;
15
+ align-items: center;
16
+ border-left: 1px solid var(--docs-border);
17
+ border-right: 1px solid var(--docs-border);
18
+ padding: 0.5rem 0.35rem;
19
+ }
20
+
21
+ .docs-folder-panel__collapsed-trigger {
22
+ display: flex;
23
+ width: 100%;
24
+ min-height: 0;
25
+ flex: 1;
26
+ flex-direction: column;
27
+ align-items: center;
28
+ justify-content: center;
29
+ gap: 0.65rem;
30
+ border: 1px solid transparent;
31
+ border-radius: 0.4rem;
32
+ background: transparent;
33
+ color: var(--docs-muted);
34
+ cursor: pointer;
35
+ font: inherit;
36
+ font-size: 0.75rem;
37
+ font-weight: 700;
38
+ padding: 0.55rem 0.35rem;
39
+ }
40
+
41
+ .docs-folder-panel__collapsed-trigger span {
42
+ max-width: 1.25rem;
43
+ max-height: min(28rem, calc(100% - 2rem));
44
+ overflow: hidden;
45
+ text-overflow: ellipsis;
46
+ white-space: nowrap;
47
+ line-height: 1.1;
48
+ writing-mode: vertical-rl;
49
+ }
50
+
51
+ .docs-folder-panel__collapsed-trigger:hover,
52
+ .docs-folder-panel__collapsed-trigger:focus-visible {
53
+ border-color: var(--docs-border);
54
+ background: var(--docs-surface);
55
+ color: var(--foreground, #111);
56
+ outline: 0;
57
+ }
58
+
59
+ .docs-folder-panel__header {
60
+ display: flex;
61
+ min-height: 3.75rem;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ gap: 0.5rem;
65
+ border-bottom: 1px solid var(--docs-border);
66
+ background: var(--docs-surface);
67
+ padding: 0.55rem 0.65rem;
68
+ }
69
+
70
+ .docs-folder-panel__title {
71
+ display: flex;
72
+ min-width: 0;
73
+ flex: 1 1 auto;
74
+ align-items: center;
75
+ gap: 0.5rem;
76
+ }
77
+
78
+ .docs-folder-panel__title > div {
79
+ min-width: 0;
80
+ }
81
+
82
+ .docs-folder-panel__title svg,
83
+ .docs-folder-panel__collapsed-trigger svg {
84
+ width: 0.95rem;
85
+ height: 0.95rem;
86
+ flex: none;
87
+ color: var(--docs-accent);
88
+ }
89
+
90
+ .docs-folder-panel__title p,
91
+ .docs-folder-panel__title span {
92
+ display: block;
93
+ max-width: 100%;
94
+ overflow: hidden;
95
+ text-overflow: ellipsis;
96
+ white-space: nowrap;
97
+ }
98
+
99
+ .docs-folder-panel__title p {
100
+ margin: 0;
101
+ font-size: 0.82rem;
102
+ font-weight: 750;
103
+ line-height: 1.2;
104
+ }
105
+
106
+ .docs-folder-panel__title span {
107
+ color: var(--docs-muted);
108
+ font-size: 0.68rem;
109
+ font-weight: 650;
110
+ }
111
+
112
+ .docs-folder-panel__actions {
113
+ display: flex;
114
+ flex: none;
115
+ align-items: center;
116
+ gap: 0.25rem;
117
+ margin-left: auto;
118
+ }
119
+
120
+ .docs-workspace .docs-folder-panel__actions button {
121
+ display: grid;
122
+ width: 1.75rem;
123
+ height: 1.75rem;
124
+ min-height: 1.75rem;
125
+ flex: none;
126
+ place-items: center;
127
+ border: 1px solid transparent;
128
+ border-radius: 0.3rem;
129
+ background: transparent;
130
+ color: var(--docs-muted);
131
+ cursor: pointer;
132
+ padding: 0;
133
+ }
134
+
135
+ .docs-workspace .docs-folder-panel__actions button:hover,
136
+ .docs-workspace .docs-folder-panel__actions button:focus-visible {
137
+ border-color: var(--docs-border);
138
+ background: color-mix(in srgb, var(--docs-subtle) 72%, transparent);
139
+ color: var(--foreground, #111);
140
+ outline: 0;
141
+ }
142
+
143
+ .docs-folder-panel__actions svg {
144
+ width: 0.82rem;
145
+ height: 0.82rem;
146
+ }
147
+
148
+ .docs-folder-panel__body {
149
+ display: flex;
150
+ min-height: 0;
151
+ flex: 1 1 0;
152
+ flex-direction: column;
153
+ border-left: 1px solid var(--docs-border);
154
+ border-right: 1px solid var(--docs-border);
155
+ }
156
+
157
+ .docs-folder-panel__list {
158
+ min-height: 0;
159
+ flex: 1 1 0;
160
+ }
161
+
162
+ .docs-folder-panel__list-content {
163
+ display: flex;
164
+ min-width: 0;
165
+ flex-direction: column;
166
+ gap: 0.25rem;
167
+ padding: 0.5rem 0.85rem 0.5rem 0.5rem;
168
+ }
169
+
170
+ .docs-folder-panel__note-group {
171
+ min-width: 0;
172
+ display: flex;
173
+ flex-direction: column;
174
+ gap: 0.15rem;
175
+ }
176
+
177
+ .docs-workspace button.docs-folder-panel__note-row {
178
+ position: relative;
179
+ width: 100%;
180
+ min-width: 0;
181
+ min-height: 2rem;
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: flex-start;
185
+ gap: 0.25rem;
186
+ border: 1px solid transparent;
187
+ border-radius: 0.4rem;
188
+ background: transparent;
189
+ color: var(--foreground, #111);
190
+ cursor: pointer;
191
+ font: inherit;
192
+ font-size: 0.78rem;
193
+ font-weight: 750;
194
+ line-height: 1.25;
195
+ padding-block: 0;
196
+ padding-right: 0.25rem;
197
+ text-align: left;
198
+ }
199
+
200
+ .docs-workspace button.docs-folder-panel__note-row:hover,
201
+ .docs-workspace button.docs-folder-panel__note-row:focus-visible,
202
+ .docs-workspace button.docs-folder-panel__child:hover,
203
+ .docs-workspace button.docs-folder-panel__child:focus-visible {
204
+ border-color: var(--docs-border);
205
+ background: var(--docs-surface);
206
+ color: var(--foreground, #111);
207
+ outline: 0;
208
+ }
209
+
210
+ .docs-folder-panel__tree-chevron {
211
+ width: 0.9rem;
212
+ height: 0.9rem;
213
+ flex: none;
214
+ color: var(--docs-muted);
215
+ transition: rotate 140ms ease;
216
+ }
217
+
218
+ .docs-folder-panel__tree-chevron.expanded {
219
+ rotate: 90deg;
220
+ }
221
+
222
+ .docs-folder-panel__note-row span {
223
+ min-width: 0;
224
+ flex: 1;
225
+ overflow: hidden;
226
+ text-overflow: ellipsis;
227
+ white-space: nowrap;
228
+ }
229
+
230
+ .docs-folder-panel__children {
231
+ min-width: 0;
232
+ display: flex;
233
+ flex-direction: column;
234
+ gap: 0.15rem;
235
+ }
236
+
237
+ .docs-workspace button.docs-folder-panel__child {
238
+ position: relative;
239
+ width: 100%;
240
+ min-width: 0;
241
+ min-height: 1.85rem;
242
+ display: flex;
243
+ align-items: center;
244
+ justify-content: space-between;
245
+ border: 1px solid transparent;
246
+ border-radius: 0.4rem;
247
+ background: transparent;
248
+ color: var(--docs-muted);
249
+ font: inherit;
250
+ font-size: 0.72rem;
251
+ font-weight: 650;
252
+ gap: 0.35rem;
253
+ padding-block: 0;
254
+ padding-right: 0.45rem;
255
+ text-align: left;
256
+ }
257
+
258
+ .docs-workspace button.docs-folder-panel__child.active {
259
+ border-color: var(--docs-border);
260
+ background: var(--docs-surface);
261
+ color: var(--foreground, #111);
262
+ outline: 0;
263
+ }
264
+
265
+ .docs-folder-panel__child > span:first-of-type {
266
+ min-width: 0;
267
+ overflow: hidden;
268
+ text-overflow: ellipsis;
269
+ white-space: nowrap;
270
+ }
271
+
272
+ .docs-folder-panel__indent-guide {
273
+ position: absolute;
274
+ top: 0;
275
+ bottom: 0;
276
+ width: 1px;
277
+ pointer-events: none;
278
+ background: color-mix(in srgb, var(--docs-border) 80%, transparent);
279
+ }
280
+
281
+ .docs-folder-panel__child-count {
282
+ display: inline-flex;
283
+ min-width: 1.25rem;
284
+ height: 1.25rem;
285
+ align-items: center;
286
+ justify-content: center;
287
+ border-radius: 999px;
288
+ background: color-mix(in srgb, var(--docs-accent) 12%, transparent);
289
+ color: var(--docs-muted);
290
+ font-size: 0.62rem;
291
+ font-weight: 750;
292
+ padding: 0 0.3rem;
293
+ }
294
+
295
+ .docs-workspace
296
+ button.docs-folder-panel__child.active
297
+ .docs-folder-panel__child-count {
298
+ color: var(--docs-accent);
299
+ }
300
+
301
+ .docs-folder-panel__empty {
302
+ margin: 0;
303
+ color: var(--docs-muted);
304
+ font-size: 0.75rem;
305
+ padding: 0.4rem 0.25rem;
306
+ }
307
+
308
+ .docs-folder-panel__tags {
309
+ display: flex;
310
+ flex: none;
311
+ flex-wrap: wrap;
312
+ gap: 0.3rem;
313
+ margin-top: auto;
314
+ border-top: 1px solid var(--docs-border);
315
+ background: color-mix(in srgb, var(--docs-subtle) 28%, var(--docs-surface));
316
+ padding: 0.45rem 0.5rem 0.55rem;
317
+ }
318
+
319
+ .docs-workspace button.docs-folder-panel__tag-chip {
320
+ display: inline-flex;
321
+ max-width: 100%;
322
+ min-height: 1.35rem;
323
+ align-items: center;
324
+ border: 1px solid color-mix(in srgb, var(--docs-border) 88%, transparent);
325
+ border-radius: 999px;
326
+ background: color-mix(in srgb, var(--docs-surface) 88%, transparent);
327
+ color: var(--docs-muted);
328
+ cursor: pointer;
329
+ font: inherit;
330
+ font-size: 0.62rem;
331
+ font-weight: 700;
332
+ line-height: 1.1;
333
+ padding: 0.15rem 0.45rem;
334
+ text-align: left;
335
+ }
336
+
337
+ .docs-workspace button.docs-folder-panel__tag-chip span,
338
+ .docs-workspace button.docs-folder-panel__tag-chip {
339
+ overflow: hidden;
340
+ text-overflow: ellipsis;
341
+ white-space: nowrap;
342
+ }
343
+
344
+ .docs-workspace button.docs-folder-panel__tag-chip:hover,
345
+ .docs-workspace button.docs-folder-panel__tag-chip:focus-visible {
346
+ border-color: color-mix(in srgb, var(--docs-accent) 28%, var(--docs-border));
347
+ background: color-mix(in srgb, var(--docs-accent) 10%, var(--docs-surface));
348
+ color: var(--docs-accent);
349
+ outline: 0;
350
+ }
351
+
352
+ .docs-workspace button.docs-folder-panel__tag-chip.active,
353
+ .docs-workspace button.docs-folder-panel__tag-chip[aria-pressed="true"] {
354
+ border-color: color-mix(in srgb, var(--docs-accent) 34%, var(--docs-border));
355
+ background: color-mix(in srgb, var(--docs-accent) 14%, var(--docs-surface));
356
+ color: var(--docs-accent);
357
+ }
@@ -0,0 +1,102 @@
1
+ <script lang="ts">
2
+ import "./DocsFolderPanel.css";
3
+
4
+ import ChevronLeftIcon from "@lucide/svelte/icons/chevron-left";
5
+ import FileTextIcon from "@lucide/svelte/icons/file-text";
6
+ import FolderIcon from "@lucide/svelte/icons/folder";
7
+ import XIcon from "@lucide/svelte/icons/x";
8
+ import DocsFolderDirectoryList from "./DocsFolderDirectoryList.svelte";
9
+ import { getActiveFolderNote, getFolderNotes } from "./docs-folder-directory";
10
+ import type { DocsNotePanel, DocsWorkspace, DocsWorkspaceIndex } from '../model';
11
+
12
+ let {
13
+ workspace = null,
14
+ activeTag = null,
15
+ activeNoteId = null,
16
+ activePanel = "note",
17
+ collapsed = false,
18
+ onSelectNote = () => {},
19
+ onSelectPanel = () => {},
20
+ onSelectTag = () => {},
21
+ onClose = () => {},
22
+ onCollapsedChange = () => {},
23
+ }: {
24
+ workspace?: DocsWorkspace | DocsWorkspaceIndex | null;
25
+ activeTag?: string | null;
26
+ activeNoteId?: string | null;
27
+ activePanel?: DocsNotePanel;
28
+ collapsed?: boolean;
29
+ onSelectNote?: (noteId: string) => void;
30
+ onSelectPanel?: (panel: DocsNotePanel) => void;
31
+ onSelectTag?: (tag: string) => void;
32
+ onClose?: () => void;
33
+ onCollapsedChange?: (collapsed: boolean) => void;
34
+ } = $props();
35
+
36
+ const folderNotes = $derived(getFolderNotes(workspace, activeTag));
37
+ const activeFolderNote = $derived(getActiveFolderNote(folderNotes, activeNoteId));
38
+ const collapsedLabel = $derived(activeFolderNote?.title ?? `#${activeTag}`);
39
+ const collapsedTitle = $derived(
40
+ activeFolderNote
41
+ ? `${activeFolderNote.title} in #${activeTag}`
42
+ : `#${activeTag}`,
43
+ );
44
+ </script>
45
+
46
+ {#if activeTag}
47
+ <aside class:docs-folder-panel--collapsed={collapsed} class="docs-folder-panel">
48
+ {#if collapsed}
49
+ <button
50
+ type="button"
51
+ class="docs-folder-panel__collapsed-trigger"
52
+ aria-label={`Expand #${activeTag} folder, selected ${collapsedLabel}`}
53
+ title={collapsedTitle}
54
+ onclick={() => onCollapsedChange(false)}
55
+ >
56
+ {#if activeFolderNote}
57
+ <FileTextIcon />
58
+ {:else}
59
+ <FolderIcon />
60
+ {/if}
61
+ <span>{collapsedLabel}</span>
62
+ </button>
63
+ {:else}
64
+ <header class="docs-folder-panel__header">
65
+ <div class="docs-folder-panel__title">
66
+ <FolderIcon />
67
+ <div>
68
+ <p>#{activeTag}</p>
69
+ <span>{folderNotes.length} {folderNotes.length === 1 ? "note" : "notes"}</span>
70
+ </div>
71
+ </div>
72
+ <div class="docs-folder-panel__actions">
73
+ <button
74
+ type="button"
75
+ aria-label={`Collapse #${activeTag} folder`}
76
+ title="Collapse folder panel"
77
+ onclick={() => onCollapsedChange(true)}
78
+ >
79
+ <ChevronLeftIcon />
80
+ </button>
81
+ <button
82
+ type="button"
83
+ aria-label={`Close #${activeTag} folder`}
84
+ title="Close folder panel"
85
+ onclick={onClose}
86
+ >
87
+ <XIcon />
88
+ </button>
89
+ </div>
90
+ </header>
91
+ <DocsFolderDirectoryList
92
+ {workspace}
93
+ {activeTag}
94
+ {activeNoteId}
95
+ {activePanel}
96
+ {onSelectNote}
97
+ {onSelectPanel}
98
+ {onSelectTag}
99
+ />
100
+ {/if}
101
+ </aside>
102
+ {/if}
@@ -0,0 +1,17 @@
1
+ import "./DocsFolderPanel.css";
2
+ import type { DocsNotePanel, DocsWorkspace, DocsWorkspaceIndex } from '../model';
3
+ type $$ComponentProps = {
4
+ workspace?: DocsWorkspace | DocsWorkspaceIndex | null;
5
+ activeTag?: string | null;
6
+ activeNoteId?: string | null;
7
+ activePanel?: DocsNotePanel;
8
+ collapsed?: boolean;
9
+ onSelectNote?: (noteId: string) => void;
10
+ onSelectPanel?: (panel: DocsNotePanel) => void;
11
+ onSelectTag?: (tag: string) => void;
12
+ onClose?: () => void;
13
+ onCollapsedChange?: (collapsed: boolean) => void;
14
+ };
15
+ declare const DocsFolderPanel: import("svelte").Component<$$ComponentProps, {}, "">;
16
+ type DocsFolderPanel = ReturnType<typeof DocsFolderPanel>;
17
+ export default DocsFolderPanel;