@panaversity/ksor 0.0.26 → 0.0.28

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 (30) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/cli.mjs +67 -4
  3. package/dist/{gateway-api-BF06IsJ--D-eI--yB.mjs → gateway-api-8lNruq9e-CuohjtoK.mjs} +1 -1
  4. package/dist/gateway.mjs +1 -1
  5. package/package.json +1 -1
  6. package/templates/scaffold/.agents/skills/format-checker/check.mjs +83 -2
  7. package/templates/scaffold/.claude/skills/format-checker/check.mjs +83 -2
  8. package/templates/scaffold/AGENTS.md +49 -0
  9. package/templates/scaffold/Dockerfile +10 -6
  10. package/templates/scaffold/README.md +3 -2
  11. package/templates/scaffold/dockerignore +5 -0
  12. package/templates/scaffold/knowledge/what-is-a-ksor.flashcards.yaml +25 -0
  13. package/templates/scaffold/knowledge/what-is-a-ksor.summary.md +15 -0
  14. package/templates/scaffold/system/site/app/docs/[[...slug]]/page.tsx +45 -7
  15. package/templates/scaffold/system/site/components/document-actions.tsx +106 -0
  16. package/templates/scaffold/system/site/components/flashcards.tsx +743 -0
  17. package/templates/scaffold/system/site/components/governance.tsx +17 -25
  18. package/templates/scaffold/system/site/components/record-views.tsx +241 -0
  19. package/templates/scaffold/system/site/components/study-aids.tsx +61 -0
  20. package/templates/scaffold/system/site/components/ui/card.tsx +76 -0
  21. package/templates/scaffold/system/site/components/ui/dropdown-menu.tsx +229 -0
  22. package/templates/scaffold/system/site/components/ui/progress.tsx +29 -0
  23. package/templates/scaffold/system/site/lib/attachment-rule.ts +124 -0
  24. package/templates/scaffold/system/site/lib/attachments.ts +105 -0
  25. package/templates/scaffold/system/site/lib/deck.ts +59 -0
  26. package/templates/scaffold/system/site/lib/reading-time.ts +45 -0
  27. package/templates/scaffold/system/site/lib/srs.ts +219 -0
  28. package/templates/scaffold/system/site/lib/stage-knowledge.ts +68 -0
  29. package/templates/scaffold/system/site/source.config.ts +54 -1
  30. package/templates/scaffold/system/site/components/copy-markdown.tsx +0 -70
@@ -0,0 +1,106 @@
1
+ "use client";
2
+
3
+ import { Check, ChevronDown, Copy, Download, FileText } from "lucide-react";
4
+ import { useCallback, useEffect, useRef, useState, type ReactElement } from "react";
5
+
6
+ import { Button } from "@/components/ui/button";
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuTrigger,
12
+ } from "@/components/ui/dropdown-menu";
13
+
14
+ /**
15
+ * What a reader can DO with this document, behind one control.
16
+ *
17
+ * Opening the markdown twin and handing it to an agent are different acts, and
18
+ * a reader who wants the second should not have to perform the first — but two
19
+ * bare controls sitting on a row of read-only facts made the row look half
20
+ * clickable. One trigger says "there are actions here" once, and the menu says
21
+ * what they are.
22
+ *
23
+ * Putting the markdown LINK behind a click is safe for the audience that reads
24
+ * bytes: `generateMetadata` already advertises the twin as
25
+ * `<link rel="alternate" type="text/markdown">` in the head, so a crawler and
26
+ * an agent find the address without opening anything. Verified in the built
27
+ * HTML before this moved.
28
+ */
29
+ export function DocumentActions({ href }: { readonly href: string }): ReactElement {
30
+ const [failed, setFailed] = useState(false);
31
+ const [copied, setCopied] = useState(false);
32
+ const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
33
+
34
+ // The shell ships `useCopyButton`, which owns this timing — but it hands back
35
+ // a MouseEventHandler, and a menu item reports selection as a CustomEvent.
36
+ // Casting one to the other to reuse six lines is worse than the six lines.
37
+ useEffect(
38
+ () => () => {
39
+ if (timer.current !== null) clearTimeout(timer.current);
40
+ },
41
+ [],
42
+ );
43
+
44
+ const onCopy = useCallback(async () => {
45
+ try {
46
+ const markdown = await fetch(href).then((response) => response.text());
47
+ await navigator.clipboard.writeText(markdown);
48
+ setFailed(false);
49
+ setCopied(true);
50
+ if (timer.current !== null) clearTimeout(timer.current);
51
+ timer.current = setTimeout(() => setCopied(false), 1600);
52
+ } catch {
53
+ // A refused clipboard or a failed fetch is not an error where a document
54
+ // should be: the menu says so, and View markdown still works.
55
+ setFailed(true);
56
+ }
57
+ }, [href]);
58
+
59
+ return (
60
+ <DropdownMenu>
61
+ <DropdownMenuTrigger asChild>
62
+ <Button
63
+ variant="ghost"
64
+ size="sm"
65
+ className="h-auto gap-1.5 px-2 py-1 font-mono text-[0.6875rem] tracking-[0.14em] text-fd-muted-foreground uppercase hover:text-fd-foreground"
66
+ >
67
+ {/* "Export", not "Markdown": the word appeared three times in one
68
+ small control, and naming the FORMAT locks the trigger to it — a
69
+ later Download or Cite would make it wrong. Not "Source", which
70
+ collides with the provenance block below. Not "Share", which in a
71
+ record where `visibility:` decides who may read a document is the
72
+ wrong verb entirely. */}
73
+ <Download aria-hidden className="size-3.5" />
74
+ Export
75
+ <ChevronDown aria-hidden className="size-3 opacity-60" />
76
+ </Button>
77
+ </DropdownMenuTrigger>
78
+
79
+ <DropdownMenuContent align="start" className="w-52">
80
+ <DropdownMenuItem asChild>
81
+ <a href={href}>
82
+ <FileText aria-hidden className="size-4" />
83
+ View markdown
84
+ </a>
85
+ </DropdownMenuItem>
86
+
87
+ {/* onSelect is prevented so the menu stays open long enough to show
88
+ that the copy landed — closing on the click would take the only
89
+ feedback away with it. */}
90
+ <DropdownMenuItem
91
+ onSelect={(event) => {
92
+ event.preventDefault();
93
+ void onCopy();
94
+ }}
95
+ >
96
+ {copied ? (
97
+ <Check aria-hidden className="size-4 text-fd-primary" />
98
+ ) : (
99
+ <Copy aria-hidden className="size-4" />
100
+ )}
101
+ {failed ? "Copy failed — open it instead" : copied ? "Copied" : "Copy markdown"}
102
+ </DropdownMenuItem>
103
+ </DropdownMenuContent>
104
+ </DropdownMenu>
105
+ );
106
+ }