@lapis-notes/lapis-plugin-docs 0.0.0-stage → 0.2.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 (197) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +188 -2
  3. package/dist/docs/DocsBlockMarkdownEditor.svelte +37 -0
  4. package/dist/docs/DocsBlockMarkdownEditor.svelte.d.ts +13 -0
  5. package/dist/docs/DocsBlockRefPicker.svelte +75 -0
  6. package/dist/docs/DocsBlockRefPicker.svelte.d.ts +11 -0
  7. package/dist/docs/DocsBookEditor.svelte +141 -0
  8. package/dist/docs/DocsBookEditor.svelte.d.ts +10 -0
  9. package/dist/docs/DocsBookNavigation.svelte +838 -0
  10. package/dist/docs/DocsBookNavigation.svelte.d.ts +11 -0
  11. package/dist/docs/DocsBooksColumn.svelte +82 -0
  12. package/dist/docs/DocsBooksColumn.svelte.d.ts +10 -0
  13. package/dist/docs/DocsCardBackMatter.svelte +32 -0
  14. package/dist/docs/DocsCardBackMatter.svelte.d.ts +10 -0
  15. package/dist/docs/DocsCardBlockExtra.svelte +43 -0
  16. package/dist/docs/DocsCardBlockExtra.svelte.d.ts +9 -0
  17. package/dist/docs/DocsCardPreviewFlip.svelte +143 -0
  18. package/dist/docs/DocsCardPreviewFlip.svelte.d.ts +17 -0
  19. package/dist/docs/DocsCardPreviewStack.svelte +139 -0
  20. package/dist/docs/DocsCardPreviewStack.svelte.d.ts +13 -0
  21. package/dist/docs/DocsCardPrompt.svelte +33 -0
  22. package/dist/docs/DocsCardPrompt.svelte.d.ts +8 -0
  23. package/dist/docs/DocsCardReviewAnswer.svelte +45 -0
  24. package/dist/docs/DocsCardReviewAnswer.svelte.d.ts +8 -0
  25. package/dist/docs/DocsCardTagChips.svelte +19 -0
  26. package/dist/docs/DocsCardTagChips.svelte.d.ts +7 -0
  27. package/dist/docs/DocsCardsPanel.svelte +232 -0
  28. package/dist/docs/DocsCardsPanel.svelte.d.ts +17 -0
  29. package/dist/docs/DocsCardsReview.css +1050 -0
  30. package/dist/docs/DocsChapterFooter.svelte +248 -0
  31. package/dist/docs/DocsChapterFooter.svelte.d.ts +11 -0
  32. package/dist/docs/DocsChapterScrollRing.svelte +101 -0
  33. package/dist/docs/DocsChapterScrollRing.svelte.d.ts +6 -0
  34. package/dist/docs/DocsDisplayPanel.css +627 -0
  35. package/dist/docs/DocsDisplayPanel.svelte +78 -0
  36. package/dist/docs/DocsDisplayPanel.svelte.d.ts +16 -0
  37. package/dist/docs/DocsEditorPanel.css +325 -0
  38. package/dist/docs/DocsEditorPanel.svelte +570 -0
  39. package/dist/docs/DocsEditorPanel.svelte.d.ts +22 -0
  40. package/dist/docs/DocsFlipCard.svelte +68 -0
  41. package/dist/docs/DocsFlipCard.svelte.d.ts +8 -0
  42. package/dist/docs/DocsFolderDirectoryList.svelte +206 -0
  43. package/dist/docs/DocsFolderDirectoryList.svelte.d.ts +14 -0
  44. package/dist/docs/DocsFolderPanel.css +357 -0
  45. package/dist/docs/DocsFolderPanel.svelte +102 -0
  46. package/dist/docs/DocsFolderPanel.svelte.d.ts +17 -0
  47. package/dist/docs/DocsLinksPanel.css +61 -0
  48. package/dist/docs/DocsLinksPanel.svelte +55 -0
  49. package/dist/docs/DocsLinksPanel.svelte.d.ts +11 -0
  50. package/dist/docs/DocsMarkdownField.svelte +93 -0
  51. package/dist/docs/DocsMarkdownField.svelte.d.ts +11 -0
  52. package/dist/docs/DocsMarkdownPreview.svelte +278 -0
  53. package/dist/docs/DocsMarkdownPreview.svelte.d.ts +17 -0
  54. package/dist/docs/DocsReviewPanel.svelte +63 -0
  55. package/dist/docs/DocsReviewPanel.svelte.d.ts +11 -0
  56. package/dist/docs/DocsRichBlock.svelte +291 -0
  57. package/dist/docs/DocsRichBlock.svelte.d.ts +13 -0
  58. package/dist/docs/DocsRichDisplay.svelte +316 -0
  59. package/dist/docs/DocsRichDisplay.svelte.d.ts +14 -0
  60. package/dist/docs/DocsSlidesPreview.css +243 -0
  61. package/dist/docs/DocsSlidesPreview.svelte +206 -0
  62. package/dist/docs/DocsSlidesPreview.svelte.d.ts +10 -0
  63. package/dist/docs/DocsWorkspace.css +570 -0
  64. package/dist/docs/DocsWorkspace.svelte +831 -0
  65. package/dist/docs/DocsWorkspace.svelte.d.ts +48 -0
  66. package/dist/docs/DocsWorkspaceToolbar.svelte +211 -0
  67. package/dist/docs/DocsWorkspaceToolbar.svelte.d.ts +27 -0
  68. package/dist/docs/candidates/ChoiceMenu.svelte +114 -0
  69. package/dist/docs/candidates/ChoiceMenu.svelte.d.ts +10 -0
  70. package/dist/docs/candidates/FlipCardDeck.svelte +817 -0
  71. package/dist/docs/candidates/FlipCardDeck.svelte.d.ts +37 -0
  72. package/dist/docs/candidates/MarkdownFloatingToc.svelte +313 -0
  73. package/dist/docs/candidates/MarkdownFloatingToc.svelte.d.ts +14 -0
  74. package/dist/docs/candidates/SearchableChoicePicker.css +161 -0
  75. package/dist/docs/candidates/SearchableChoicePicker.svelte +208 -0
  76. package/dist/docs/candidates/SearchableChoicePicker.svelte.d.ts +19 -0
  77. package/dist/docs/candidates/StructuredTable.svelte +98 -0
  78. package/dist/docs/candidates/StructuredTable.svelte.d.ts +8 -0
  79. package/dist/docs/candidates/StructuredTableEditor.svelte +374 -0
  80. package/dist/docs/candidates/StructuredTableEditor.svelte.d.ts +12 -0
  81. package/dist/docs/candidates/TagEditor.svelte +31 -0
  82. package/dist/docs/candidates/TagEditor.svelte.d.ts +14 -0
  83. package/dist/docs/candidates/WorkspaceHistoryControls.svelte +112 -0
  84. package/dist/docs/candidates/WorkspaceHistoryControls.svelte.d.ts +8 -0
  85. package/dist/docs/candidates/markdown-floating-toc.css +151 -0
  86. package/dist/docs/candidates/markdown-floating-toc.d.ts +1 -0
  87. package/dist/docs/candidates/markdown-floating-toc.js +1 -0
  88. package/dist/docs/docs-anki-import.d.ts +34 -0
  89. package/dist/docs/docs-anki-import.js +516 -0
  90. package/dist/docs/docs-book-view-model.d.ts +9 -0
  91. package/dist/docs/docs-book-view-model.js +71 -0
  92. package/dist/docs/docs-card-answer-markdown.d.ts +1 -0
  93. package/dist/docs/docs-card-answer-markdown.js +63 -0
  94. package/dist/docs/docs-card-display.d.ts +10 -0
  95. package/dist/docs/docs-card-display.js +18 -0
  96. package/dist/docs/docs-display-focus.d.ts +7 -0
  97. package/dist/docs/docs-display-focus.js +42 -0
  98. package/dist/docs/docs-document-surface.d.ts +7 -0
  99. package/dist/docs/docs-document-surface.js +25 -0
  100. package/dist/docs/docs-folder-directory.d.ts +21 -0
  101. package/dist/docs/docs-folder-directory.js +56 -0
  102. package/dist/docs/docs-link-mode.d.ts +16 -0
  103. package/dist/docs/docs-link-mode.js +94 -0
  104. package/dist/docs/docs-workspace-helpers.d.ts +25 -0
  105. package/dist/docs/docs-workspace-helpers.js +195 -0
  106. package/dist/docs/docs.tokens.css +13 -0
  107. package/dist/docs/import-anki-package.d.ts +10 -0
  108. package/dist/docs/import-anki-package.js +30 -0
  109. package/dist/docs/lapis-markdown-extensions.d.ts +9 -0
  110. package/dist/docs/lapis-markdown-extensions.js +128 -0
  111. package/dist/docs/pin-reading-chrome.d.ts +4 -0
  112. package/dist/docs/pin-reading-chrome.js +32 -0
  113. package/dist/docs/sidebar/DocsFoldersSidebar.svelte +134 -0
  114. package/dist/docs/sidebar/DocsFoldersSidebar.svelte.d.ts +15 -0
  115. package/dist/docs/sidebar/DocsLinksSidebar.svelte +105 -0
  116. package/dist/docs/sidebar/DocsLinksSidebar.svelte.d.ts +11 -0
  117. package/dist/docs/sidebar/DocsSidebar.css +346 -0
  118. package/dist/docs/sidebar/DocsSidebar.svelte +430 -0
  119. package/dist/docs/sidebar/DocsSidebar.svelte.d.ts +18 -0
  120. package/dist/docs/sidebar/DocsSidebarHost.svelte +139 -0
  121. package/dist/docs/sidebar/DocsSidebarHost.svelte.d.ts +12 -0
  122. package/dist/docs/sidebar/DocsTagsSidebar.svelte +176 -0
  123. package/dist/docs/sidebar/DocsTagsSidebar.svelte.d.ts +12 -0
  124. package/dist/docs/sidebar/docs-book-note-tree.d.ts +23 -0
  125. package/dist/docs/sidebar/docs-book-note-tree.js +88 -0
  126. package/dist/docs/sidebar/docs-note-sort.d.ts +26 -0
  127. package/dist/docs/sidebar/docs-note-sort.js +54 -0
  128. package/dist/docs/sidebar/docs-sidebar-filters.d.ts +17 -0
  129. package/dist/docs/sidebar/docs-sidebar-filters.js +74 -0
  130. package/dist/docs/sidebar/docs-sidebar-ui-storage.d.ts +24 -0
  131. package/dist/docs/sidebar/docs-sidebar-ui-storage.js +87 -0
  132. package/dist/docs/sidebar/docs-source-folder-tree.d.ts +16 -0
  133. package/dist/docs/sidebar/docs-source-folder-tree.js +143 -0
  134. package/dist/docs/sidebar/docs-tag-tree.d.ts +17 -0
  135. package/dist/docs/sidebar/docs-tag-tree.js +84 -0
  136. package/dist/docs-cards-view.d.ts +18 -0
  137. package/dist/docs-cards-view.js +52 -0
  138. package/dist/docs-document-view.d.ts +24 -0
  139. package/dist/docs-document-view.js +127 -0
  140. package/dist/docs-document-workspace.svelte +215 -0
  141. package/dist/docs-document-workspace.svelte.d.ts +16 -0
  142. package/dist/docs-index.d.ts +5 -0
  143. package/dist/docs-index.js +49 -0
  144. package/dist/docs-path.d.ts +6 -0
  145. package/dist/docs-path.js +10 -0
  146. package/dist/docs-plugin.d.ts +21 -0
  147. package/dist/docs-plugin.js +140 -0
  148. package/dist/docs-repository.d.ts +15 -0
  149. package/dist/docs-repository.js +75 -0
  150. package/dist/docs-review-view.d.ts +18 -0
  151. package/dist/docs-review-view.js +52 -0
  152. package/dist/docs-settings-tab.d.ts +8 -0
  153. package/dist/docs-settings-tab.js +25 -0
  154. package/dist/docs-settings.d.ts +17 -0
  155. package/dist/docs-settings.js +38 -0
  156. package/dist/docs-view.d.ts +22 -0
  157. package/dist/docs-view.js +51 -0
  158. package/dist/docs-workspace.svelte +394 -0
  159. package/dist/docs-workspace.svelte.d.ts +15 -0
  160. package/dist/index.d.ts +12 -0
  161. package/dist/index.js +12 -0
  162. package/dist/model/book.d.ts +6 -0
  163. package/dist/model/book.js +101 -0
  164. package/dist/model/coding-runtime.d.ts +4 -0
  165. package/dist/model/coding-runtime.js +9 -0
  166. package/dist/model/docs-card-context.d.ts +32 -0
  167. package/dist/model/docs-card-context.js +89 -0
  168. package/dist/model/docs-card-preview-stack-motion.d.ts +51 -0
  169. package/dist/model/docs-card-preview-stack-motion.js +94 -0
  170. package/dist/model/docs-media-context.d.ts +9 -0
  171. package/dist/model/docs-media-context.js +18 -0
  172. package/dist/model/docs-note-list.d.ts +8 -0
  173. package/dist/model/docs-note-list.js +25 -0
  174. package/dist/model/docs-relative-media.d.ts +30 -0
  175. package/dist/model/docs-relative-media.js +116 -0
  176. package/dist/model/docs-review-constants.d.ts +4 -0
  177. package/dist/model/docs-review-constants.js +13 -0
  178. package/dist/model/fsrs.d.ts +14 -0
  179. package/dist/model/fsrs.js +153 -0
  180. package/dist/model/graph.d.ts +12 -0
  181. package/dist/model/graph.js +169 -0
  182. package/dist/model/index.d.ts +14 -0
  183. package/dist/model/index.js +14 -0
  184. package/dist/model/markdown-normalize.d.ts +11 -0
  185. package/dist/model/markdown-normalize.js +755 -0
  186. package/dist/model/markdown.d.ts +167 -0
  187. package/dist/model/markdown.js +365 -0
  188. package/dist/model/sample.d.ts +7 -0
  189. package/dist/model/sample.js +524 -0
  190. package/dist/model/types.d.ts +328 -0
  191. package/dist/model/types.js +1 -0
  192. package/dist/model/workspace.d.ts +6 -0
  193. package/dist/model/workspace.js +81 -0
  194. package/dist/storybook.css +52 -0
  195. package/dist/styles.css +1 -0
  196. package/manifest.json +11 -0
  197. package/package.json +147 -4
@@ -0,0 +1,11 @@
1
+ import type { DocsBookChapterNavigation, DocsBookNavigation } from '../model';
2
+ type $$ComponentProps = {
3
+ book: DocsBookNavigation;
4
+ activeNoteId: string;
5
+ chapterNavigation?: DocsBookChapterNavigation | null;
6
+ variant?: 'toc' | 'floating';
7
+ onOpenNote?: (noteId: string) => void;
8
+ };
9
+ declare const DocsBookNavigation: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type DocsBookNavigation = ReturnType<typeof DocsBookNavigation>;
11
+ export default DocsBookNavigation;
@@ -0,0 +1,82 @@
1
+ <script lang="ts">
2
+ import type { DocsBookNavigation, DocsNoteListItem } from "../model";
3
+
4
+ let {
5
+ books = [],
6
+ notes = [],
7
+ activeNoteId = null,
8
+ onOpenNote = () => {},
9
+ }: {
10
+ books?: DocsBookNavigation[];
11
+ notes?: DocsNoteListItem[];
12
+ activeNoteId?: string | null;
13
+ onOpenNote?: (noteId: string) => void;
14
+ } = $props();
15
+
16
+ const claimedIds = $derived(
17
+ new Set(
18
+ books.flatMap((book) => [
19
+ book.indexNoteId,
20
+ ...book.chapters.map((chapter) => chapter.noteId),
21
+ ]),
22
+ ),
23
+ );
24
+ const standaloneNotes = $derived(
25
+ notes.filter((note) => !claimedIds.has(note.id)),
26
+ );
27
+ </script>
28
+
29
+ <nav class="docs-books" aria-label="Books">
30
+ {#if books.length}
31
+ {#each books as book (book.id)}
32
+ <section class="docs-books__book" aria-label={book.title}>
33
+ <button
34
+ type="button"
35
+ class="docs-books__index"
36
+ aria-current={activeNoteId === book.indexNoteId ? "page" : undefined}
37
+ onclick={() => onOpenNote(book.indexNoteId)}
38
+ >
39
+ {book.title}
40
+ </button>
41
+ <ol>
42
+ {#each book.chapters as chapter (chapter.index + chapter.noteId)}
43
+ <li>
44
+ {#if chapter.resolved}
45
+ <button
46
+ type="button"
47
+ aria-current={activeNoteId === chapter.noteId ? "page" : undefined}
48
+ onclick={() => onOpenNote(chapter.noteId)}
49
+ >
50
+ <span>{chapter.index + 1}</span>
51
+ {chapter.title}
52
+ </button>
53
+ {:else}
54
+ <span class="docs-books__missing">{chapter.title}</span>
55
+ {/if}
56
+ </li>
57
+ {/each}
58
+ </ol>
59
+ </section>
60
+ {/each}
61
+ {:else}
62
+ <p class="docs-books__empty">No books in this vault.</p>
63
+ {/if}
64
+ {#if standaloneNotes.length}
65
+ <section class="docs-books__book" aria-label="Notes">
66
+ <p>Notes</p>
67
+ <ol>
68
+ {#each standaloneNotes as note (note.id)}
69
+ <li>
70
+ <button
71
+ type="button"
72
+ aria-current={activeNoteId === note.id ? "page" : undefined}
73
+ onclick={() => onOpenNote(note.id)}
74
+ >
75
+ {note.title || note.id}
76
+ </button>
77
+ </li>
78
+ {/each}
79
+ </ol>
80
+ </section>
81
+ {/if}
82
+ </nav>
@@ -0,0 +1,10 @@
1
+ import type { DocsBookNavigation, DocsNoteListItem } from "../model";
2
+ type $$ComponentProps = {
3
+ books?: DocsBookNavigation[];
4
+ notes?: DocsNoteListItem[];
5
+ activeNoteId?: string | null;
6
+ onOpenNote?: (noteId: string) => void;
7
+ };
8
+ declare const DocsBooksColumn: import("svelte").Component<$$ComponentProps, {}, "">;
9
+ type DocsBooksColumn = ReturnType<typeof DocsBooksColumn>;
10
+ export default DocsBooksColumn;
@@ -0,0 +1,32 @@
1
+ <script lang="ts">
2
+ import DocsCardBlockExtra from './DocsCardBlockExtra.svelte';
3
+ import DocsCardReviewAnswer from './DocsCardReviewAnswer.svelte';
4
+ import { resolveCardBlockRefs } from '../model/docs-card-context';
5
+ import type { DocsCard, DocsRevisionBlock } from '../model';
6
+
7
+ let {
8
+ card,
9
+ noteSourcePath = '',
10
+ noteBlocks = [],
11
+ showExtras = false
12
+ }: {
13
+ card: DocsCard;
14
+ noteSourcePath?: string;
15
+ noteBlocks?: DocsRevisionBlock[];
16
+ showExtras?: boolean;
17
+ } = $props();
18
+
19
+ const blockResolution = $derived(resolveCardBlockRefs({ blocks: noteBlocks }, card.blockRefs));
20
+ </script>
21
+
22
+ <DocsCardReviewAnswer {card} {noteSourcePath} />
23
+
24
+ {#if showExtras}
25
+ {#if blockResolution.resolved.length > 0 || blockResolution.missing.length > 0}
26
+ <DocsCardBlockExtra
27
+ blocks={blockResolution.resolved.map((item) => item.block)}
28
+ missingRefs={blockResolution.missing.map((item) => item.ref)}
29
+ sourcePath={noteSourcePath}
30
+ />
31
+ {/if}
32
+ {/if}
@@ -0,0 +1,10 @@
1
+ import type { DocsCard, DocsRevisionBlock } from '../model';
2
+ type $$ComponentProps = {
3
+ card: DocsCard;
4
+ noteSourcePath?: string;
5
+ noteBlocks?: DocsRevisionBlock[];
6
+ showExtras?: boolean;
7
+ };
8
+ declare const DocsCardBackMatter: import("svelte").Component<$$ComponentProps, {}, "">;
9
+ type DocsCardBackMatter = ReturnType<typeof DocsCardBackMatter>;
10
+ export default DocsCardBackMatter;
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { renderDocsBlockMarkdown } from '../model/markdown';
3
+ import type { DocsRevisionBlock } from '../model';
4
+ import DocsMarkdownPreview from './DocsMarkdownPreview.svelte';
5
+ import { BLOCK_TYPE_LABELS } from './docs-workspace-helpers';
6
+
7
+ let {
8
+ blocks = [],
9
+ missingRefs = [],
10
+ sourcePath = ''
11
+ }: {
12
+ blocks: DocsRevisionBlock[];
13
+ missingRefs?: string[];
14
+ sourcePath?: string;
15
+ } = $props();
16
+
17
+ function blockTitle(block: DocsRevisionBlock) {
18
+ return block.title?.trim() || BLOCK_TYPE_LABELS[block.type] || block.type;
19
+ }
20
+ </script>
21
+
22
+ {#if blocks.length > 0 || missingRefs.length > 0}
23
+ <section class="docs-card-extra docs-card-extra--blocks" aria-label="From note">
24
+ <h4 class="docs-card-extra__heading">From note</h4>
25
+ <div class="docs-card-extra__items">
26
+ {#each blocks as block (block.id)}
27
+ <article class="docs-card-extra__block">
28
+ <p class="docs-card-extra__block-label">{blockTitle(block)}</p>
29
+ <div class="docs-card-extra__block-body application-markdown-preview is-compact">
30
+ <DocsMarkdownPreview
31
+ compact
32
+ value={renderDocsBlockMarkdown(block, 3)}
33
+ {sourcePath}
34
+ />
35
+ </div>
36
+ </article>
37
+ {/each}
38
+ {#each missingRefs as ref (ref)}
39
+ <p class="docs-card-extra__missing">Missing block: {ref}</p>
40
+ {/each}
41
+ </div>
42
+ </section>
43
+ {/if}
@@ -0,0 +1,9 @@
1
+ import type { DocsRevisionBlock } from '../model';
2
+ type $$ComponentProps = {
3
+ blocks: DocsRevisionBlock[];
4
+ missingRefs?: string[];
5
+ sourcePath?: string;
6
+ };
7
+ declare const DocsCardBlockExtra: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type DocsCardBlockExtra = ReturnType<typeof DocsCardBlockExtra>;
9
+ export default DocsCardBlockExtra;
@@ -0,0 +1,143 @@
1
+ <script lang="ts">
2
+ import EyeIcon from '@lucide/svelte/icons/eye';
3
+ import DocsCardBackMatter from './DocsCardBackMatter.svelte';
4
+ import DocsCardPrompt from './DocsCardPrompt.svelte';
5
+ import DocsCardTagChips from './DocsCardTagChips.svelte';
6
+ import { REVIEW_RATINGS, REVIEW_RATING_LABELS } from '../model/docs-review-constants';
7
+ import { formatDocsReviewInterval, previewDocsCardRatings } from '../model/fsrs';
8
+ import type { DocsCard, DocsRevisionBlock, DocsReviewRating } from '../model';
9
+
10
+ let {
11
+ card,
12
+ noteTitle,
13
+ noteSourcePath = '',
14
+ dueAt,
15
+ noteBlocks = [],
16
+ revealed = false,
17
+ peek = false,
18
+ showIntervalPreview = false,
19
+ onReveal,
20
+ onHide,
21
+ onReview
22
+ }: {
23
+ card: DocsCard;
24
+ noteTitle: string;
25
+ noteSourcePath?: string;
26
+ dueAt?: string;
27
+ noteBlocks?: DocsRevisionBlock[];
28
+ revealed?: boolean;
29
+ peek?: boolean;
30
+ showIntervalPreview?: boolean;
31
+ onReveal?: () => void;
32
+ onHide?: () => void;
33
+ onReview?: (rating: DocsReviewRating) => void | Promise<void>;
34
+ } = $props();
35
+
36
+ const ratingPreviews = $derived(
37
+ showIntervalPreview && revealed && onReview ? previewDocsCardRatings(card) : null
38
+ );
39
+ </script>
40
+
41
+ <div
42
+ class={`docs-review-flip docs-card-preview-flip ${!peek && revealed ? 'docs-review-flip--revealed' : ''}`}
43
+ data-card-type={card.type}
44
+ data-card-status={card.status}
45
+ data-peek={peek ? 'true' : undefined}
46
+ >
47
+ {#if peek}
48
+ <article class="docs-review-face docs-review-face--front docs-review-face--peek">
49
+ <div class="docs-review-face__meta">
50
+ <span class="docs-review-face__label">{noteTitle}</span>
51
+ {#if card.tags.length}
52
+ <DocsCardTagChips tags={card.tags} />
53
+ {:else if dueAt}
54
+ <span class="docs-review-face__label">Due {dueAt}</span>
55
+ {/if}
56
+ </div>
57
+ <div class="docs-review-face__scroll">
58
+ <div class="docs-review-face__prompt">
59
+ <span>Question</span>
60
+ <h3>
61
+ <DocsCardPrompt {card} />
62
+ </h3>
63
+ </div>
64
+ </div>
65
+ </article>
66
+ {:else}
67
+ <div class="docs-review-flip__inner">
68
+ <article class="docs-review-face docs-review-face--front" aria-hidden={revealed}>
69
+ <div class="docs-review-face__meta">
70
+ <span class="docs-review-face__label">{noteTitle}</span>
71
+ {#if card.tags.length}
72
+ <DocsCardTagChips tags={card.tags} />
73
+ {:else if dueAt}
74
+ <span class="docs-review-face__label">Due {dueAt}</span>
75
+ {/if}
76
+ </div>
77
+ <div class="docs-review-face__scroll">
78
+ <div class="docs-review-face__prompt">
79
+ <span>Question</span>
80
+ <h3>
81
+ <DocsCardPrompt {card} />
82
+ </h3>
83
+ </div>
84
+ </div>
85
+ <div class="docs-review-face__actions">
86
+ <button
87
+ type="button"
88
+ class="docs-review-show-answer"
89
+ disabled={revealed}
90
+ onclick={() => onReveal?.()}
91
+ >
92
+ <EyeIcon aria-hidden="true" />
93
+ Show Answer
94
+ </button>
95
+ </div>
96
+ </article>
97
+
98
+ <article class="docs-review-face docs-review-face--back" aria-hidden={!revealed}>
99
+ <div class="docs-review-face__meta">
100
+ <span class="docs-review-face__label">Answer</span>
101
+ <span class="docs-review-face__label">{card.type}</span>
102
+ </div>
103
+ <div class="docs-review-face__scroll">
104
+ <DocsCardBackMatter
105
+ {card}
106
+ {noteSourcePath}
107
+ {noteBlocks}
108
+ showExtras={revealed}
109
+ />
110
+ </div>
111
+ <div class="docs-review-face__actions">
112
+ {#if onReview}
113
+ <div class="docs-rating-grid" aria-label="Rate your recall">
114
+ {#each REVIEW_RATINGS as rating (rating)}
115
+ <button
116
+ type="button"
117
+ class={`docs-rating-button docs-rating-button--${rating}`}
118
+ disabled={!revealed}
119
+ onclick={() => void onReview(rating)}
120
+ >
121
+ <span class="docs-rating-button__label">{REVIEW_RATING_LABELS[rating]}</span>
122
+ {#if ratingPreviews}
123
+ <span class="docs-rating-button__interval">
124
+ {formatDocsReviewInterval(ratingPreviews[rating].due)}
125
+ </span>
126
+ {/if}
127
+ </button>
128
+ {/each}
129
+ </div>
130
+ {:else}
131
+ <button
132
+ type="button"
133
+ class="docs-review-show-answer docs-card-preview-question-button"
134
+ onclick={() => onHide?.()}
135
+ >
136
+ Show Question
137
+ </button>
138
+ {/if}
139
+ </div>
140
+ </article>
141
+ </div>
142
+ {/if}
143
+ </div>
@@ -0,0 +1,17 @@
1
+ import type { DocsCard, DocsRevisionBlock, DocsReviewRating } from '../model';
2
+ type $$ComponentProps = {
3
+ card: DocsCard;
4
+ noteTitle: string;
5
+ noteSourcePath?: string;
6
+ dueAt?: string;
7
+ noteBlocks?: DocsRevisionBlock[];
8
+ revealed?: boolean;
9
+ peek?: boolean;
10
+ showIntervalPreview?: boolean;
11
+ onReveal?: () => void;
12
+ onHide?: () => void;
13
+ onReview?: (rating: DocsReviewRating) => void | Promise<void>;
14
+ };
15
+ declare const DocsCardPreviewFlip: import("svelte").Component<$$ComponentProps, {}, "">;
16
+ type DocsCardPreviewFlip = ReturnType<typeof DocsCardPreviewFlip>;
17
+ export default DocsCardPreviewFlip;
@@ -0,0 +1,139 @@
1
+ <script lang="ts">
2
+ import FlipCardDeck, { type FlipCardDeckContext } from "./candidates/FlipCardDeck.svelte";
3
+ import DocsCardBackMatter from './DocsCardBackMatter.svelte';
4
+ import DocsCardPrompt from './DocsCardPrompt.svelte';
5
+ import DocsCardTagChips from './DocsCardTagChips.svelte';
6
+ import { REVIEW_RATINGS, REVIEW_RATING_LABELS } from '../model/docs-review-constants';
7
+ import { formatDocsReviewInterval, previewDocsCardRatings } from '../model/fsrs';
8
+ import type {
9
+ DocsCardStackItem,
10
+ DocsCardStackMode,
11
+ DocsReviewRating
12
+ } from '../model';
13
+ let {
14
+ items,
15
+ previewAnswerOpenById = $bindable({}),
16
+ ariaLabel = 'Card previews',
17
+ mode = 'browse',
18
+ initialIndex = 0,
19
+ blockSwipeWhenRevealed = false,
20
+ onReviewCard
21
+ }: {
22
+ items: DocsCardStackItem[];
23
+ previewAnswerOpenById: Record<string, boolean>;
24
+ ariaLabel?: string;
25
+ mode?: DocsCardStackMode;
26
+ initialIndex?: number;
27
+ blockSwipeWhenRevealed?: boolean;
28
+ onReviewCard?: (
29
+ noteId: string,
30
+ cardId: string,
31
+ rating: DocsReviewRating
32
+ ) => void | Promise<void>;
33
+ } = $props();
34
+
35
+ function keyFor(item: unknown) {
36
+ return (item as DocsCardStackItem).key;
37
+ }
38
+
39
+ function ratingPreviewsFor(item: DocsCardStackItem, revealed: boolean) {
40
+ return mode === 'study' && revealed && onReviewCard
41
+ ? previewDocsCardRatings(item.card)
42
+ : null;
43
+ }
44
+
45
+ async function reviewItem(
46
+ item: DocsCardStackItem,
47
+ rating: DocsReviewRating,
48
+ context: FlipCardDeckContext
49
+ ) {
50
+ if (!onReviewCard || !item.noteId) return;
51
+ await onReviewCard(item.noteId, item.card.id, rating);
52
+ context.hide();
53
+ if (mode === 'study') context.reset();
54
+ }
55
+ </script>
56
+
57
+ <div class="docs-card-preview-stack">
58
+ <FlipCardDeck
59
+ {items}
60
+ {keyFor}
61
+ bind:revealedByKey={previewAnswerOpenById}
62
+ {ariaLabel}
63
+ mode={mode as 'browse' | 'study'}
64
+ {initialIndex}
65
+ {blockSwipeWhenRevealed}
66
+ emptyLabel="No cards yet."
67
+ >
68
+ {#snippet frontHeader(item)}
69
+ {@const stackItem = item as DocsCardStackItem}
70
+ <div class="docs-review-face__meta">
71
+ <span class="docs-review-face__label">{stackItem.noteTitle}</span>
72
+ {#if stackItem.card.tags.length}
73
+ <DocsCardTagChips tags={stackItem.card.tags} />
74
+ {:else if stackItem.dueAt}
75
+ <span class="docs-review-face__label">Due {stackItem.dueAt}</span>
76
+ {/if}
77
+ </div>
78
+ {/snippet}
79
+
80
+ {#snippet front(item, context)}
81
+ {@const stackItem = item as DocsCardStackItem}
82
+ <div
83
+ class="docs-review-face__content docs-review-face__content--front"
84
+ id={stackItem.noteId ? `docs-card-${stackItem.noteId}-${stackItem.card.id}` : undefined}
85
+ >
86
+ <div class="docs-review-face__prompt">
87
+ <span>Question</span>
88
+ <h3>
89
+ <DocsCardPrompt card={stackItem.card} />
90
+ </h3>
91
+ </div>
92
+ </div>
93
+ {/snippet}
94
+
95
+ {#snippet back(item, context)}
96
+ {@const stackItem = item as DocsCardStackItem}
97
+ <div class="docs-review-face__content docs-review-face__content--back">
98
+ <div class="docs-review-face__meta">
99
+ <span class="docs-review-face__label">Answer</span>
100
+ <span class="docs-review-face__label">{stackItem.card.type}</span>
101
+ </div>
102
+ <DocsCardBackMatter
103
+ card={stackItem.card}
104
+ noteSourcePath={stackItem.noteSourcePath}
105
+ noteBlocks={stackItem.noteBlocks ?? []}
106
+ showExtras={context.revealed}
107
+ />
108
+ </div>
109
+ {/snippet}
110
+
111
+ {#snippet backActions(item, context)}
112
+ {@const stackItem = item as DocsCardStackItem}
113
+ {@const ratingPreviews = ratingPreviewsFor(stackItem, context.revealed)}
114
+ {#if onReviewCard && stackItem.noteId}
115
+ <div class="docs-rating-grid" aria-label="Rate your recall">
116
+ {#each REVIEW_RATINGS as rating (rating)}
117
+ <button
118
+ type="button"
119
+ class={`docs-rating-button docs-rating-button--${rating}`}
120
+ disabled={!context.revealed}
121
+ onclick={() => void reviewItem(stackItem, rating, context)}
122
+ >
123
+ <span class="docs-rating-button__label">{REVIEW_RATING_LABELS[rating]}</span>
124
+ {#if ratingPreviews}
125
+ <span class="docs-rating-button__interval">
126
+ {formatDocsReviewInterval(ratingPreviews[rating].due)}
127
+ </span>
128
+ {/if}
129
+ </button>
130
+ {/each}
131
+ </div>
132
+ {:else}
133
+ <button type="button" class="flip-card-deck__primary-action docs-card-preview-question-button" onclick={context.hide}>
134
+ Show Question
135
+ </button>
136
+ {/if}
137
+ {/snippet}
138
+ </FlipCardDeck>
139
+ </div>
@@ -0,0 +1,13 @@
1
+ import type { DocsCardStackItem, DocsCardStackMode, DocsReviewRating } from '../model';
2
+ type $$ComponentProps = {
3
+ items: DocsCardStackItem[];
4
+ previewAnswerOpenById: Record<string, boolean>;
5
+ ariaLabel?: string;
6
+ mode?: DocsCardStackMode;
7
+ initialIndex?: number;
8
+ blockSwipeWhenRevealed?: boolean;
9
+ onReviewCard?: (noteId: string, cardId: string, rating: DocsReviewRating) => void | Promise<void>;
10
+ };
11
+ declare const DocsCardPreviewStack: import("svelte").Component<$$ComponentProps, {}, "previewAnswerOpenById">;
12
+ type DocsCardPreviewStack = ReturnType<typeof DocsCardPreviewStack>;
13
+ export default DocsCardPreviewStack;
@@ -0,0 +1,33 @@
1
+ <script lang="ts">
2
+ import { docsCardQuestionParts } from './docs-card-display';
3
+ import type { DocsCard } from '../model';
4
+
5
+ let {
6
+ card,
7
+ revealClozes = false
8
+ }: {
9
+ card: DocsCard;
10
+ revealClozes?: boolean;
11
+ } = $props();
12
+ </script>
13
+
14
+ {#each docsCardQuestionParts(card) as part}
15
+ {#if part.kind === 'cloze'}
16
+ <span
17
+ class={revealClozes
18
+ ? 'docs-cloze-gap docs-cloze-gap--revealed'
19
+ : part.hint
20
+ ? 'docs-cloze-gap docs-cloze-gap--hint'
21
+ : 'docs-cloze-gap'}
22
+ aria-label={revealClozes
23
+ ? 'Revealed cloze answer'
24
+ : part.hint
25
+ ? `Hidden cloze, hint: ${part.hint}`
26
+ : 'Hidden cloze'}
27
+ >
28
+ {revealClozes ? part.text : part.hint ?? ''}
29
+ </span>
30
+ {:else}
31
+ {part.text}
32
+ {/if}
33
+ {/each}
@@ -0,0 +1,8 @@
1
+ import type { DocsCard } from '../model';
2
+ type $$ComponentProps = {
3
+ card: DocsCard;
4
+ revealClozes?: boolean;
5
+ };
6
+ declare const DocsCardPrompt: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type DocsCardPrompt = ReturnType<typeof DocsCardPrompt>;
8
+ export default DocsCardPrompt;
@@ -0,0 +1,45 @@
1
+ <script lang="ts">
2
+ import BrainIcon from '@lucide/svelte/icons/brain';
3
+ import DocsCardPrompt from './DocsCardPrompt.svelte';
4
+ import DocsMarkdownPreview from './DocsMarkdownPreview.svelte';
5
+ import { docsCardAnswerMarkdown } from './docs-card-answer-markdown';
6
+ import type { DocsCard } from '../model';
7
+
8
+ let { card, noteSourcePath = '' }: { card: DocsCard; noteSourcePath?: string } = $props();
9
+
10
+ const renderedAnswer = $derived(docsCardAnswerMarkdown(card.answer));
11
+ </script>
12
+
13
+ {#if card.type === 'cloze'}
14
+ <div class="docs-review-face__prompt docs-review-face__prompt--answer">
15
+ <h3>
16
+ <DocsCardPrompt {card} revealClozes />
17
+ </h3>
18
+ </div>
19
+ <div class="docs-review-face__answer docs-review-face__answer--context">
20
+ <BrainIcon aria-hidden="true" />
21
+ <div>
22
+ <span class="docs-review-face__answer-label">Context</span>
23
+ <DocsMarkdownPreview
24
+ value={renderedAnswer}
25
+ empty="No additional context has been added yet."
26
+ compact
27
+ floatingToc="off"
28
+ sourcePath={noteSourcePath}
29
+ headingIdPrefix={`docs-card-${card.id}-answer`}
30
+ />
31
+ </div>
32
+ </div>
33
+ {:else}
34
+ <div class="docs-review-face__answer">
35
+ <BrainIcon aria-hidden="true" />
36
+ <DocsMarkdownPreview
37
+ value={renderedAnswer}
38
+ empty="No answer has been added yet."
39
+ compact
40
+ floatingToc="off"
41
+ sourcePath={noteSourcePath}
42
+ headingIdPrefix={`docs-card-${card.id}-answer`}
43
+ />
44
+ </div>
45
+ {/if}
@@ -0,0 +1,8 @@
1
+ import type { DocsCard } from '../model';
2
+ type $$ComponentProps = {
3
+ card: DocsCard;
4
+ noteSourcePath?: string;
5
+ };
6
+ declare const DocsCardReviewAnswer: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type DocsCardReviewAnswer = ReturnType<typeof DocsCardReviewAnswer>;
8
+ export default DocsCardReviewAnswer;
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ let {
3
+ tags = [],
4
+ limit = 2
5
+ }: {
6
+ tags?: string[];
7
+ limit?: number;
8
+ } = $props();
9
+
10
+ const visibleTags = $derived(tags.slice(0, limit));
11
+ </script>
12
+
13
+ {#if visibleTags.length}
14
+ <span class="docs-review-face__tags" aria-label="Tags">
15
+ {#each visibleTags as tag (tag)}
16
+ <span class="docs-review-face__tag">#{tag}</span>
17
+ {/each}
18
+ </span>
19
+ {/if}
@@ -0,0 +1,7 @@
1
+ type $$ComponentProps = {
2
+ tags?: string[];
3
+ limit?: number;
4
+ };
5
+ declare const DocsCardTagChips: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type DocsCardTagChips = ReturnType<typeof DocsCardTagChips>;
7
+ export default DocsCardTagChips;