specra 0.1.13 → 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 (276) hide show
  1. package/LICENSE.MD +25 -4
  2. package/README.md +67 -58
  3. package/config/specra.config.schema.json +16 -0
  4. package/config/svelte-config.js +63 -0
  5. package/dist/api-parser.types.d.ts +59 -0
  6. package/dist/api-parser.types.js +5 -0
  7. package/dist/api.types.d.ts +137 -0
  8. package/dist/api.types.js +5 -0
  9. package/dist/category.d.ts +21 -0
  10. package/dist/category.js +48 -0
  11. package/dist/components/ConfigProvider.svelte +13 -0
  12. package/dist/components/ConfigProvider.svelte.d.ts +31 -0
  13. package/dist/components/docs/Accordion.svelte +18 -0
  14. package/dist/components/docs/Accordion.svelte.d.ts +10 -0
  15. package/dist/components/docs/AccordionItem.svelte +41 -0
  16. package/dist/components/docs/AccordionItem.svelte.d.ts +10 -0
  17. package/dist/components/docs/Badge.svelte +28 -0
  18. package/dist/components/docs/Badge.svelte.d.ts +9 -0
  19. package/dist/components/docs/Breadcrumb.svelte +80 -0
  20. package/dist/components/docs/Breadcrumb.svelte.d.ts +8 -0
  21. package/dist/components/docs/Callout.svelte +96 -0
  22. package/dist/components/docs/Callout.svelte.d.ts +10 -0
  23. package/dist/components/docs/Card.svelte +63 -0
  24. package/dist/components/docs/Card.svelte.d.ts +12 -0
  25. package/dist/components/docs/CardGrid.svelte +24 -0
  26. package/dist/components/docs/CardGrid.svelte.d.ts +8 -0
  27. package/dist/components/docs/CategoryIndex.svelte +110 -0
  28. package/dist/components/docs/CategoryIndex.svelte.d.ts +29 -0
  29. package/dist/components/docs/CodeBlock.svelte +172 -0
  30. package/dist/components/docs/CodeBlock.svelte.d.ts +8 -0
  31. package/dist/components/docs/Column.svelte +25 -0
  32. package/dist/components/docs/Column.svelte.d.ts +8 -0
  33. package/dist/components/docs/Columns.svelte +38 -0
  34. package/dist/components/docs/Columns.svelte.d.ts +13 -0
  35. package/dist/components/docs/DevModeBadge.svelte +15 -0
  36. package/dist/components/docs/DevModeBadge.svelte.d.ts +18 -0
  37. package/dist/components/docs/DocBadge.svelte +28 -0
  38. package/dist/components/docs/DocBadge.svelte.d.ts +9 -0
  39. package/dist/components/docs/DocLayout.svelte +107 -0
  40. package/dist/components/docs/DocLayout.svelte.d.ts +32 -0
  41. package/dist/components/docs/DocLoading.svelte +53 -0
  42. package/dist/components/docs/DocLoading.svelte.d.ts +18 -0
  43. package/dist/components/docs/DocMetadata.svelte +106 -0
  44. package/dist/components/docs/DocMetadata.svelte.d.ts +18 -0
  45. package/dist/components/docs/DocNavigation.svelte +56 -0
  46. package/dist/components/docs/DocNavigation.svelte.d.ts +12 -0
  47. package/dist/components/docs/DocTags.svelte +22 -0
  48. package/dist/components/docs/DocTags.svelte.d.ts +6 -0
  49. package/dist/components/docs/DraftBadge.svelte +10 -0
  50. package/dist/components/docs/DraftBadge.svelte.d.ts +18 -0
  51. package/dist/components/docs/Footer.svelte +72 -0
  52. package/dist/components/docs/Footer.svelte.d.ts +7 -0
  53. package/dist/components/docs/Frame.svelte +27 -0
  54. package/dist/components/docs/Frame.svelte.d.ts +9 -0
  55. package/dist/components/docs/Header.svelte +123 -0
  56. package/dist/components/docs/Header.svelte.d.ts +9 -0
  57. package/dist/components/docs/HeaderWithMenu.svelte +34 -0
  58. package/dist/components/docs/HeaderWithMenu.svelte.d.ts +17 -0
  59. package/dist/components/docs/HotReloadIndicator.svelte +44 -0
  60. package/dist/components/docs/HotReloadIndicator.svelte.d.ts +3 -0
  61. package/dist/components/docs/Icon.svelte +103 -0
  62. package/dist/components/docs/Icon.svelte.d.ts +11 -0
  63. package/dist/components/docs/Image.svelte +88 -0
  64. package/dist/components/docs/Image.svelte.d.ts +11 -0
  65. package/dist/components/docs/ImageCard.svelte +91 -0
  66. package/dist/components/docs/ImageCard.svelte.d.ts +12 -0
  67. package/dist/components/docs/ImageCardGrid.svelte +25 -0
  68. package/dist/components/docs/ImageCardGrid.svelte.d.ts +8 -0
  69. package/dist/components/docs/LayoutProviders.svelte +57 -0
  70. package/dist/components/docs/LayoutProviders.svelte.d.ts +9 -0
  71. package/dist/components/docs/Logo.svelte +25 -0
  72. package/dist/components/docs/Logo.svelte.d.ts +11 -0
  73. package/dist/components/docs/Math.svelte +54 -0
  74. package/dist/components/docs/Math.svelte.d.ts +7 -0
  75. package/dist/components/docs/MdxContent.svelte +41 -0
  76. package/dist/components/docs/MdxHotReload.svelte +78 -0
  77. package/dist/components/docs/MdxHotReload.svelte.d.ts +9 -0
  78. package/dist/components/docs/MdxLayout.svelte +16 -0
  79. package/dist/components/docs/MdxLayout.svelte.d.ts +6 -0
  80. package/dist/components/docs/Mermaid.svelte +88 -0
  81. package/dist/components/docs/Mermaid.svelte.d.ts +7 -0
  82. package/dist/components/docs/MobileDocLayout.svelte +211 -0
  83. package/dist/components/docs/MobileDocLayout.svelte.d.ts +35 -0
  84. package/dist/components/docs/MobileSidebar.svelte +122 -0
  85. package/dist/components/docs/MobileSidebar.svelte.d.ts +31 -0
  86. package/dist/components/docs/MobileSidebarWrapper.svelte +122 -0
  87. package/dist/components/docs/MobileSidebarWrapper.svelte.d.ts +32 -0
  88. package/dist/components/docs/NotFoundContent.svelte +40 -0
  89. package/dist/components/docs/NotFoundContent.svelte.d.ts +6 -0
  90. package/dist/components/docs/SearchHighlight.svelte +116 -0
  91. package/dist/components/docs/SearchHighlight.svelte.d.ts +3 -0
  92. package/dist/components/docs/SearchModal.svelte +239 -0
  93. package/dist/components/docs/SearchModal.svelte.d.ts +9 -0
  94. package/dist/components/docs/Sidebar.svelte +69 -0
  95. package/dist/components/docs/Sidebar.svelte.d.ts +31 -0
  96. package/dist/components/docs/SidebarMenuItems.svelte +344 -0
  97. package/dist/components/docs/SidebarMenuItems.svelte.d.ts +33 -0
  98. package/dist/components/docs/SidebarSkeleton.svelte +50 -0
  99. package/dist/components/docs/SidebarSkeleton.svelte.d.ts +18 -0
  100. package/dist/components/docs/SiteBanner.svelte +92 -0
  101. package/dist/components/docs/SiteBanner.svelte.d.ts +7 -0
  102. package/dist/components/docs/Step.svelte +44 -0
  103. package/dist/components/docs/Step.svelte.d.ts +8 -0
  104. package/dist/components/docs/Steps.svelte +15 -0
  105. package/dist/components/docs/Steps.svelte.d.ts +7 -0
  106. package/dist/components/docs/Tab.svelte +40 -0
  107. package/dist/components/docs/Tab.svelte.d.ts +8 -0
  108. package/dist/components/docs/TabGroups.svelte +183 -0
  109. package/dist/components/docs/TabGroups.svelte.d.ts +25 -0
  110. package/dist/components/docs/TableOfContents.svelte +100 -0
  111. package/dist/components/docs/TableOfContents.svelte.d.ts +9 -0
  112. package/dist/components/docs/Tabs.svelte +69 -0
  113. package/dist/components/docs/Tabs.svelte.d.ts +8 -0
  114. package/dist/components/docs/ThemeToggle.svelte +16 -0
  115. package/dist/components/docs/ThemeToggle.svelte.d.ts +18 -0
  116. package/dist/components/docs/Tooltip.svelte +44 -0
  117. package/dist/components/docs/Tooltip.svelte.d.ts +10 -0
  118. package/dist/components/docs/VersionSwitcher.svelte +95 -0
  119. package/dist/components/docs/VersionSwitcher.svelte.d.ts +7 -0
  120. package/dist/components/docs/Video.svelte +84 -0
  121. package/dist/components/docs/Video.svelte.d.ts +12 -0
  122. package/dist/components/docs/api/ApiEndpoint.svelte +61 -0
  123. package/dist/components/docs/api/ApiEndpoint.svelte.d.ts +11 -0
  124. package/dist/components/docs/api/ApiParams.svelte +80 -0
  125. package/dist/components/docs/api/ApiParams.svelte.d.ts +14 -0
  126. package/dist/components/docs/api/ApiPlayground.svelte +259 -0
  127. package/dist/components/docs/api/ApiPlayground.svelte.d.ts +16 -0
  128. package/dist/components/docs/api/ApiReference.svelte +278 -0
  129. package/dist/components/docs/api/ApiReference.svelte.d.ts +23 -0
  130. package/dist/components/docs/api/ApiResponse.svelte +66 -0
  131. package/dist/components/docs/api/ApiResponse.svelte.d.ts +9 -0
  132. package/dist/components/docs/api/index.d.ts +5 -0
  133. package/dist/components/docs/api/index.js +5 -0
  134. package/dist/components/docs/componentTextProps.d.ts +3 -0
  135. package/dist/components/docs/componentTextProps.js +61 -0
  136. package/dist/components/docs/index.d.ts +54 -0
  137. package/dist/components/docs/index.js +56 -0
  138. package/dist/components/global/VersionNotFound.svelte +48 -0
  139. package/dist/components/global/VersionNotFound.svelte.d.ts +7 -0
  140. package/dist/components/global/index.d.ts +1 -0
  141. package/dist/components/global/index.js +1 -0
  142. package/dist/components/index.d.ts +6 -822
  143. package/dist/components/index.js +11 -3854
  144. package/dist/components/ui/Badge.svelte +48 -0
  145. package/dist/components/ui/Badge.svelte.d.ts +15 -0
  146. package/dist/components/ui/Button.svelte +58 -0
  147. package/dist/components/ui/Button.svelte.d.ts +17 -0
  148. package/dist/components/ui/Dialog.svelte +16 -0
  149. package/dist/components/ui/Dialog.svelte.d.ts +9 -0
  150. package/dist/components/ui/DialogClose.svelte +16 -0
  151. package/dist/components/ui/DialogClose.svelte.d.ts +9 -0
  152. package/dist/components/ui/DialogContent.svelte +43 -0
  153. package/dist/components/ui/DialogContent.svelte.d.ts +10 -0
  154. package/dist/components/ui/DialogDescription.svelte +21 -0
  155. package/dist/components/ui/DialogDescription.svelte.d.ts +9 -0
  156. package/dist/components/ui/DialogFooter.svelte +20 -0
  157. package/dist/components/ui/DialogFooter.svelte.d.ts +9 -0
  158. package/dist/components/ui/DialogHeader.svelte +20 -0
  159. package/dist/components/ui/DialogHeader.svelte.d.ts +9 -0
  160. package/dist/components/ui/DialogTitle.svelte +21 -0
  161. package/dist/components/ui/DialogTitle.svelte.d.ts +9 -0
  162. package/dist/components/ui/Input.svelte +23 -0
  163. package/dist/components/ui/Input.svelte.d.ts +8 -0
  164. package/dist/components/ui/Textarea.svelte +19 -0
  165. package/dist/components/ui/Textarea.svelte.d.ts +7 -0
  166. package/dist/components/ui/index.d.ts +11 -0
  167. package/dist/components/ui/index.js +11 -0
  168. package/dist/config.d.ts +8 -0
  169. package/dist/config.js +9 -0
  170. package/dist/config.schema.json +471 -0
  171. package/dist/config.server.d.ts +46 -0
  172. package/dist/config.server.js +149 -0
  173. package/dist/{mdx-ColN3Cyg.d.mts → config.types.d.ts} +22 -75
  174. package/dist/config.types.js +39 -0
  175. package/dist/dev-utils.d.ts +29 -0
  176. package/dist/dev-utils.js +63 -0
  177. package/dist/index.d.ts +19 -4
  178. package/dist/index.js +25 -4861
  179. package/dist/mdx-cache.d.ts +41 -0
  180. package/dist/mdx-cache.js +160 -0
  181. package/dist/mdx-components.js +50 -1931
  182. package/dist/mdx-security.d.ts +76 -0
  183. package/dist/mdx-security.js +217 -0
  184. package/dist/mdx.d.ts +73 -0
  185. package/dist/mdx.js +1099 -0
  186. package/dist/middleware/index.d.ts +1 -0
  187. package/dist/middleware/index.js +2 -0
  188. package/dist/middleware/security.d.ts +22 -47
  189. package/dist/middleware/security.js +111 -137
  190. package/dist/parsers/base-parser.d.ts +14 -0
  191. package/dist/parsers/base-parser.js +1 -0
  192. package/dist/parsers/index.d.ts +16 -0
  193. package/dist/parsers/index.js +51 -0
  194. package/dist/parsers/openapi-parser.d.ts +18 -0
  195. package/dist/parsers/openapi-parser.js +209 -0
  196. package/dist/parsers/postman-parser.d.ts +20 -0
  197. package/dist/parsers/postman-parser.js +260 -0
  198. package/dist/parsers/specra-parser.d.ts +10 -0
  199. package/dist/parsers/specra-parser.js +18 -0
  200. package/dist/redirects.d.ts +12 -0
  201. package/dist/redirects.js +30 -0
  202. package/dist/remark-code-meta.d.ts +6 -0
  203. package/dist/remark-code-meta.js +21 -0
  204. package/dist/sidebar-utils.d.ts +59 -0
  205. package/dist/sidebar-utils.js +144 -0
  206. package/dist/stores/config.d.ts +20 -0
  207. package/dist/stores/config.js +45 -0
  208. package/dist/stores/index.d.ts +4 -0
  209. package/dist/stores/index.js +4 -0
  210. package/dist/stores/sidebar.d.ts +7 -0
  211. package/dist/stores/sidebar.js +12 -0
  212. package/dist/stores/tabs.d.ts +6 -0
  213. package/dist/stores/tabs.js +41 -0
  214. package/dist/stores/theme.d.ts +7 -0
  215. package/dist/stores/theme.js +75 -0
  216. package/dist/{styles.css → styles/globals.css} +136 -6
  217. package/dist/toc.d.ts +9 -0
  218. package/dist/toc.js +15 -0
  219. package/dist/utils.d.ts +13 -0
  220. package/dist/utils.js +30 -0
  221. package/package.json +47 -90
  222. package/dist/app/api/mdx-watch/route.d.mts +0 -10
  223. package/dist/app/api/mdx-watch/route.d.ts +0 -10
  224. package/dist/app/api/mdx-watch/route.js +0 -118
  225. package/dist/app/api/mdx-watch/route.js.map +0 -1
  226. package/dist/app/api/mdx-watch/route.mjs +0 -91
  227. package/dist/app/api/mdx-watch/route.mjs.map +0 -1
  228. package/dist/chunk-6S3EJVEO.mjs +0 -259
  229. package/dist/chunk-6S3EJVEO.mjs.map +0 -1
  230. package/dist/chunk-BE7EROIW.mjs +0 -212
  231. package/dist/chunk-BE7EROIW.mjs.map +0 -1
  232. package/dist/chunk-CWHRZHZO.mjs +0 -168
  233. package/dist/chunk-CWHRZHZO.mjs.map +0 -1
  234. package/dist/chunk-D5VDVYFY.mjs +0 -1325
  235. package/dist/chunk-D5VDVYFY.mjs.map +0 -1
  236. package/dist/chunk-WMCO2UX5.mjs +0 -585
  237. package/dist/chunk-WMCO2UX5.mjs.map +0 -1
  238. package/dist/chunk-XEMGCPZZ.mjs +0 -475
  239. package/dist/chunk-XEMGCPZZ.mjs.map +0 -1
  240. package/dist/components/index.d.mts +0 -822
  241. package/dist/components/index.js.map +0 -1
  242. package/dist/components/index.mjs +0 -3741
  243. package/dist/components/index.mjs.map +0 -1
  244. package/dist/index.d.mts +0 -4
  245. package/dist/index.js.map +0 -1
  246. package/dist/index.mjs +0 -1897
  247. package/dist/index.mjs.map +0 -1
  248. package/dist/layouts/index.d.mts +0 -34
  249. package/dist/layouts/index.d.ts +0 -34
  250. package/dist/layouts/index.js +0 -453
  251. package/dist/layouts/index.js.map +0 -1
  252. package/dist/layouts/index.mjs +0 -173
  253. package/dist/layouts/index.mjs.map +0 -1
  254. package/dist/lib/index.d.mts +0 -583
  255. package/dist/lib/index.d.ts +0 -583
  256. package/dist/lib/index.js +0 -1595
  257. package/dist/lib/index.js.map +0 -1
  258. package/dist/lib/index.mjs +0 -111
  259. package/dist/lib/index.mjs.map +0 -1
  260. package/dist/mdx-ColN3Cyg.d.ts +0 -352
  261. package/dist/mdx-components.d.mts +0 -86
  262. package/dist/mdx-components.d.ts +0 -86
  263. package/dist/mdx-components.js.map +0 -1
  264. package/dist/mdx-components.mjs +0 -206
  265. package/dist/mdx-components.mjs.map +0 -1
  266. package/dist/middleware/security.d.mts +0 -82
  267. package/dist/middleware/security.js.map +0 -1
  268. package/dist/middleware/security.mjs +0 -84
  269. package/dist/middleware/security.mjs.map +0 -1
  270. package/dist/styles.css.map +0 -1
  271. package/dist/styles.d.mts +0 -2
  272. package/dist/styles.d.ts +0 -2
  273. package/dist/styles.js +0 -2
  274. package/dist/styles.js.map +0 -1
  275. package/dist/styles.mjs +0 -1
  276. package/dist/styles.mjs.map +0 -1
@@ -0,0 +1,172 @@
1
+ <script lang="ts">
2
+ import { Copy, Check } from 'lucide-svelte';
3
+
4
+ interface Props {
5
+ code: string;
6
+ language: string;
7
+ filename?: string;
8
+ }
9
+
10
+ let { code, language, filename }: Props = $props();
11
+
12
+ let copied = $state(false);
13
+ let copyTimeout: ReturnType<typeof setTimeout> | undefined;
14
+
15
+ function handleCopy() {
16
+ navigator.clipboard.writeText(code).then(() => {
17
+ copied = true;
18
+ if (copyTimeout) clearTimeout(copyTimeout);
19
+ copyTimeout = setTimeout(() => {
20
+ copied = false;
21
+ }, 2000);
22
+ });
23
+ }
24
+
25
+ // Basic syntax tokenizer matching the React version's pattern-based approach
26
+ interface Token {
27
+ type: string;
28
+ value: string;
29
+ }
30
+
31
+ function tokenizeLine(line: string): Token[] {
32
+ const tokens: Token[] = [];
33
+ let currentPos = 0;
34
+
35
+ const patterns: Array<{ type: string; regex: RegExp }> = [
36
+ { type: 'comment', regex: /(\/\/.*$|\/\*[\s\S]*?\*\/|#.*$)/ },
37
+ { type: 'string', regex: /("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|`(?:[^`\\]|\\.)*`)/ },
38
+ {
39
+ type: 'keyword',
40
+ regex:
41
+ /\b(const|let|var|function|return|if|else|for|while|do|break|continue|switch|case|default|import|export|from|as|class|extends|implements|interface|type|enum|namespace|async|await|try|catch|finally|throw|new|this|super|static|public|private|protected|readonly|abstract|void|null|undefined|true|false|typeof|instanceof|delete|in|of)\b/,
42
+ },
43
+ { type: 'operator', regex: /([+\-*/%=<>!&|^~?:]+)/ },
44
+ { type: 'number', regex: /\b(0x[a-fA-F0-9]+|0b[01]+|\d+\.?\d*(?:e[+-]?\d+)?)\b/ },
45
+ { type: 'function', regex: /\b([a-zA-Z_$][\w$]*)\s*(?=\()/ },
46
+ { type: 'property', regex: /\.([a-zA-Z_$][\w$]*)/ },
47
+ { type: 'punctuation', regex: /([{}[\]();,])/ },
48
+ ];
49
+
50
+ while (currentPos < line.length) {
51
+ let matched = false;
52
+
53
+ for (const { type, regex } of patterns) {
54
+ const match = line.slice(currentPos).match(regex);
55
+ if (match && match.index === 0) {
56
+ tokens.push({ type, value: match[0] });
57
+ currentPos += match[0].length;
58
+ matched = true;
59
+ break;
60
+ }
61
+ }
62
+
63
+ if (!matched) {
64
+ const nextSpecialChar = line.slice(currentPos).search(/["'`/\w.+\-*/%=<>!&|^~?:;,()[\]{}#]/);
65
+ if (nextSpecialChar === -1) {
66
+ tokens.push({ type: 'text', value: line.slice(currentPos) });
67
+ break;
68
+ } else if (nextSpecialChar > 0) {
69
+ tokens.push({ type: 'text', value: line.slice(currentPos, currentPos + nextSpecialChar) });
70
+ currentPos += nextSpecialChar;
71
+ } else {
72
+ tokens.push({ type: 'text', value: line[currentPos] });
73
+ currentPos++;
74
+ }
75
+ }
76
+ }
77
+
78
+ return tokens;
79
+ }
80
+
81
+ let lines = $derived(code.split('\n'));
82
+ </script>
83
+
84
+ <div class="relative group my-2">
85
+ <!-- Header - always visible -->
86
+ <div class="bg-muted/50 dark:bg-muted/30 px-4 py-2 rounded-t-xl border border-b-0 border-border/50 flex items-center justify-between">
87
+ <!-- Left section: Safari-style dots + filename -->
88
+ <div class="flex items-center gap-3">
89
+ <!-- Safari-style window controls -->
90
+ <div class="flex items-center gap-1.5">
91
+ <div class="w-3 h-3 rounded-full bg-red-500/80 dark:bg-red-500/60"></div>
92
+ <div class="w-3 h-3 rounded-full bg-yellow-500/80 dark:bg-yellow-500/60"></div>
93
+ <div class="w-3 h-3 rounded-full bg-green-500/80 dark:bg-green-500/60"></div>
94
+ </div>
95
+ <!-- Filename or "Code" -->
96
+ <span class="text-xs font-mono text-foreground">{filename || 'Code'}</span>
97
+ </div>
98
+
99
+ <!-- Right section: Language + Copy button -->
100
+ <div class="flex items-center gap-2">
101
+ <span class="text-xs text-muted-foreground/60 font-mono uppercase tracking-wide">{language}</span>
102
+ <button
103
+ onclick={handleCopy}
104
+ class="p-1.5 rounded-md hover:bg-muted/50 transition-colors"
105
+ aria-label="Copy code"
106
+ >
107
+ {#if copied}
108
+ <Check class="h-4 w-4 text-green-400" />
109
+ {:else}
110
+ <Copy class="h-4 w-4 text-muted-foreground" />
111
+ {/if}
112
+ </button>
113
+ </div>
114
+ </div>
115
+
116
+ <!-- Code content -->
117
+ <div class="bg-gray-200/50 dark:bg-[#0d1117] rounded-b-xl overflow-x-auto border border-border/50">
118
+ <pre class="p-2 text-[13px] font-mono leading-relaxed text-gray-800 dark:text-gray-200"><code class="table w-full">{#each lines as line, i}{@const isDeletion = line.startsWith('-')}{@const isAddition = line.startsWith('+')}{@const isDiff = isDeletion || isAddition}{@const diffBgClass = isDeletion ? 'bg-red-500/5 dark:bg-red-500/10' : isAddition ? 'bg-green-500/5 dark:bg-green-500/10' : ''}{@const diffMarkerClass = isDeletion ? 'text-red-600 dark:text-red-400' : isAddition ? 'text-green-600 dark:text-green-400' : ''}{@const tokens = tokenizeLine(line)}<div class="table-row {diffBgClass}"><span class="table-cell pr-4 text-right select-none text-muted-foreground/40 w-8 align-top">{i + 1}</span><span class="table-cell align-top">{#if tokens.length === 0}&nbsp;{:else}{#each tokens as token, j}{#if j === 0 && isDiff && token.value.length > 0 && (token.value[0] === '+' || token.value[0] === '-')}<span class="{diffMarkerClass} font-bold">{token.value[0]}</span>{#if token.value.length > 1}<span class="token-{token.type}">{token.value.slice(1)}</span>{/if}{:else}<span class="token-{token.type}">{token.value}</span>{/if}{/each}{/if}</span></div>{/each}</code></pre>
119
+ </div>
120
+ </div>
121
+
122
+ <style>
123
+ .token-keyword {
124
+ color: #cf222e;
125
+ }
126
+ :global(.dark) .token-keyword {
127
+ color: #ff7b72;
128
+ }
129
+ .token-string {
130
+ color: #0a3069;
131
+ }
132
+ :global(.dark) .token-string {
133
+ color: #a5d6ff;
134
+ }
135
+ .token-comment {
136
+ color: #6e7781;
137
+ font-style: italic;
138
+ }
139
+ :global(.dark) .token-comment {
140
+ color: #8b949e;
141
+ }
142
+ .token-number {
143
+ color: #0550ae;
144
+ }
145
+ :global(.dark) .token-number {
146
+ color: #79c0ff;
147
+ }
148
+ .token-function {
149
+ color: #8250df;
150
+ }
151
+ :global(.dark) .token-function {
152
+ color: #d2a8ff;
153
+ }
154
+ .token-operator {
155
+ color: #cf222e;
156
+ }
157
+ :global(.dark) .token-operator {
158
+ color: #ff7b72;
159
+ }
160
+ .token-property {
161
+ color: #0550ae;
162
+ }
163
+ :global(.dark) .token-property {
164
+ color: #79c0ff;
165
+ }
166
+ .token-punctuation {
167
+ color: #24292f;
168
+ }
169
+ :global(.dark) .token-punctuation {
170
+ color: #c9d1d9;
171
+ }
172
+ </style>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ code: string;
3
+ language: string;
4
+ filename?: string;
5
+ }
6
+ declare const CodeBlock: import("svelte").Component<Props, {}, "">;
7
+ type CodeBlock = ReturnType<typeof CodeBlock>;
8
+ export default CodeBlock;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ span?: 1 | 2 | 3 | 4;
6
+ children?: Snippet;
7
+ }
8
+
9
+ let { span = 1, children }: Props = $props();
10
+
11
+ const spanClasses: Record<number, string> = {
12
+ 1: 'col-span-1',
13
+ 2: 'col-span-2',
14
+ 3: 'col-span-3',
15
+ 4: 'col-span-4',
16
+ };
17
+
18
+ let spanClass = $derived(spanClasses[span] || spanClasses[1]);
19
+ </script>
20
+
21
+ <div class={spanClass}>
22
+ {#if children}
23
+ {@render children()}
24
+ {/if}
25
+ </div>
@@ -0,0 +1,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ span?: 1 | 2 | 3 | 4;
4
+ children?: Snippet;
5
+ }
6
+ declare const Column: import("svelte").Component<Props, {}, "">;
7
+ type Column = ReturnType<typeof Column>;
8
+ export default Column;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ cols?: {
6
+ sm?: 1 | 2 | 3 | 4;
7
+ md?: 1 | 2 | 3 | 4;
8
+ lg?: 1 | 2 | 3 | 4;
9
+ xl?: 1 | 2 | 3 | 4;
10
+ };
11
+ children?: Snippet;
12
+ }
13
+
14
+ let { cols = { sm: 1, md: 2, lg: 3 }, children }: Props = $props();
15
+
16
+ const colClasses: Record<number, string> = {
17
+ 1: 'grid-cols-1',
18
+ 2: 'grid-cols-2',
19
+ 3: 'grid-cols-3',
20
+ 4: 'grid-cols-4',
21
+ };
22
+
23
+ // Build responsive class string matching React original
24
+ // sm is the base, md/lg/xl get responsive prefixes
25
+ let gridClasses = $derived(() => {
26
+ const smClass = cols.sm ? colClasses[cols.sm] : 'grid-cols-1';
27
+ const mdClass = cols.md ? `md:${colClasses[cols.md]}` : '';
28
+ const lgClass = cols.lg ? `lg:${colClasses[cols.lg]}` : '';
29
+ const xlClass = cols.xl ? `xl:${colClasses[cols.xl]}` : '';
30
+ return `${smClass} ${mdClass} ${lgClass} ${xlClass}`.trim();
31
+ });
32
+ </script>
33
+
34
+ <div class="grid {gridClasses()} gap-4 my-6">
35
+ {#if children}
36
+ {@render children()}
37
+ {/if}
38
+ </div>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ cols?: {
4
+ sm?: 1 | 2 | 3 | 4;
5
+ md?: 1 | 2 | 3 | 4;
6
+ lg?: 1 | 2 | 3 | 4;
7
+ xl?: 1 | 2 | 3 | 4;
8
+ };
9
+ children?: Snippet;
10
+ }
11
+ declare const Columns: import("svelte").Component<Props, {}, "">;
12
+ type Columns = ReturnType<typeof Columns>;
13
+ export default Columns;
@@ -0,0 +1,15 @@
1
+ <script lang="ts">
2
+ import { Wrench } from 'lucide-svelte';
3
+ import { browser } from '$app/environment';
4
+ import { dev } from '$app/environment';
5
+ </script>
6
+
7
+ {#if dev}
8
+ <div
9
+ class="fixed bottom-4 left-4 z-50 inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-orange-500/90 text-white text-xs font-medium shadow-lg backdrop-blur-sm"
10
+ title="Development mode"
11
+ >
12
+ <Wrench class="h-3 w-3" />
13
+ <span>Dev</span>
14
+ </div>
15
+ {/if}
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const DevModeBadge: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type DevModeBadge = InstanceType<typeof DevModeBadge>;
18
+ export default DevModeBadge;
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'info';
5
+
6
+ interface Props {
7
+ variant?: BadgeVariant;
8
+ children?: Snippet;
9
+ }
10
+
11
+ let { variant = 'default', children }: Props = $props();
12
+
13
+ const variants: Record<BadgeVariant, string> = {
14
+ default: 'bg-muted text-foreground border-border',
15
+ success: 'bg-green-500/10 text-green-600 dark:text-green-400 border-green-500/20',
16
+ warning: 'bg-yellow-500/10 text-yellow-600 dark:text-yellow-400 border-yellow-500/20',
17
+ error: 'bg-red-500/10 text-red-600 dark:text-red-400 border-red-500/20',
18
+ info: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20',
19
+ };
20
+
21
+ let classes = $derived(variants[variant] || variants.default);
22
+ </script>
23
+
24
+ <span class="inline-flex items-center px-2 py-0.5 rounded-md text-xs font-medium border {classes}">
25
+ {#if children}
26
+ {@render children()}
27
+ {/if}
28
+ </span>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ type BadgeVariant = 'default' | 'success' | 'warning' | 'error' | 'info';
3
+ interface Props {
4
+ variant?: BadgeVariant;
5
+ children?: Snippet;
6
+ }
7
+ declare const DocBadge: import("svelte").Component<Props, {}, "">;
8
+ type DocBadge = ReturnType<typeof DocBadge>;
9
+ export default DocBadge;
@@ -0,0 +1,107 @@
1
+ <script lang="ts">
2
+ import { dev } from '$app/environment';
3
+ import { ExternalLink, FileEdit } from 'lucide-svelte';
4
+ import DocNavigation from './DocNavigation.svelte';
5
+ import Breadcrumb from './Breadcrumb.svelte';
6
+ import DocMetadata from './DocMetadata.svelte';
7
+ import DraftBadge from './DraftBadge.svelte';
8
+ import DocTags from './DocTags.svelte';
9
+ import type { SpecraConfig } from '../../config.types.js';
10
+ import type { Snippet } from 'svelte';
11
+
12
+ interface DocMeta {
13
+ title: string;
14
+ description?: string;
15
+ draft?: boolean;
16
+ reading_time?: number;
17
+ last_updated?: string;
18
+ locale?: string;
19
+ authors?: Array<{ id: string; name?: string }>;
20
+ tags?: string[];
21
+ [key: string]: any;
22
+ }
23
+
24
+ interface NavDoc {
25
+ title: string;
26
+ slug: string;
27
+ }
28
+
29
+ interface Props {
30
+ meta: DocMeta;
31
+ previousDoc?: NavDoc;
32
+ nextDoc?: NavDoc;
33
+ version: string;
34
+ slug: string;
35
+ config: SpecraConfig;
36
+ children: Snippet;
37
+ }
38
+
39
+ let { meta, previousDoc, nextDoc, version, slug, config, children }: Props = $props();
40
+
41
+ let isDevelopment = $derived(dev);
42
+
43
+ // Build edit URL if configured
44
+ let editUrl = $derived(
45
+ config.features?.editUrl && typeof config.features.editUrl === 'string'
46
+ ? `${config.features.editUrl}/${version}/${slug}.mdx`
47
+ : null
48
+ );
49
+ </script>
50
+
51
+ <article class="flex-1 min-w-0">
52
+ {#if config.navigation?.showBreadcrumbs}
53
+ <Breadcrumb {version} {slug} title={meta.title} />
54
+ {/if}
55
+
56
+ {#if isDevelopment && meta.draft}
57
+ <DraftBadge />
58
+ {/if}
59
+
60
+ <div class="mb-8">
61
+ <h1 class="text-4xl font-bold tracking-tight mb-3 text-foreground">{meta.title}</h1>
62
+ {#if meta.description}
63
+ <p class="text-lg text-muted-foreground leading-relaxed">{meta.description}</p>
64
+ {/if}
65
+ </div>
66
+
67
+ <DocMetadata {meta} {config} />
68
+
69
+ <div class="prose prose-slate dark:prose-invert max-w-none prose-headings:scroll-mt-24 prose-headings:font-semibold prose-h1:text-4xl prose-h2:text-3xl prose-h2:mt-12 prose-h2:mb-4 prose-h3:text-2xl prose-h3:mt-8 prose-h3:mb-3 prose-p:text-base prose-p:leading-7 prose-p:text-muted-foreground prose-p:mb-4 prose-a:font-normal prose-a:transition-all prose-code:text-primary prose-code:bg-muted/50 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded-md prose-code:text-[13px] prose-code:font-mono prose-code:border prose-code:border-border/50 prose-code:before:content-none prose-code:after:content-none prose-pre:bg-transparent prose-pre:p-0 prose-ul:list-disc prose-ul:list-inside prose-ul:space-y-2 prose-ul:mb-4 prose-ol:list-decimal prose-ol:list-inside prose-ol:space-y-2 prose-ol:mb-4 prose-li:leading-7 prose-li:text-muted-foreground prose-strong:text-foreground prose-strong:font-semibold">
70
+ {@render children()}
71
+ </div>
72
+
73
+ {#if config.features?.showTags && meta.tags && meta.tags.length > 0}
74
+ <DocTags tags={meta.tags} />
75
+ {/if}
76
+
77
+ {#if editUrl || config.social?.github}
78
+ <div class="mt-12 pt-6 border-t border-border flex items-center justify-between">
79
+ {#if editUrl}
80
+ <a
81
+ href={editUrl}
82
+ target="_blank"
83
+ rel="noopener noreferrer"
84
+ class="flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
85
+ >
86
+ <FileEdit class="h-4 w-4" />
87
+ Edit this page
88
+ </a>
89
+ {:else}
90
+ <div></div>
91
+ {/if}
92
+ {#if config.social?.github}
93
+ <a
94
+ href="{config.social.github}/issues/new"
95
+ target="_blank"
96
+ rel="noopener noreferrer"
97
+ class="flex items-center gap-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
98
+ >
99
+ <ExternalLink class="h-4 w-4" />
100
+ Report an issue
101
+ </a>
102
+ {/if}
103
+ </div>
104
+ {/if}
105
+
106
+ <DocNavigation {previousDoc} {nextDoc} {version} />
107
+ </article>
@@ -0,0 +1,32 @@
1
+ import type { SpecraConfig } from '../../config.types.js';
2
+ import type { Snippet } from 'svelte';
3
+ interface DocMeta {
4
+ title: string;
5
+ description?: string;
6
+ draft?: boolean;
7
+ reading_time?: number;
8
+ last_updated?: string;
9
+ locale?: string;
10
+ authors?: Array<{
11
+ id: string;
12
+ name?: string;
13
+ }>;
14
+ tags?: string[];
15
+ [key: string]: any;
16
+ }
17
+ interface NavDoc {
18
+ title: string;
19
+ slug: string;
20
+ }
21
+ interface Props {
22
+ meta: DocMeta;
23
+ previousDoc?: NavDoc;
24
+ nextDoc?: NavDoc;
25
+ version: string;
26
+ slug: string;
27
+ config: SpecraConfig;
28
+ children: Snippet;
29
+ }
30
+ declare const DocLayout: import("svelte").Component<Props, {}, "">;
31
+ type DocLayout = ReturnType<typeof DocLayout>;
32
+ export default DocLayout;
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ // DocLoading: Loading skeleton placeholder for documentation content
3
+ </script>
4
+
5
+ <div class="animate-pulse space-y-6 w-full max-w-3xl">
6
+ <!-- Title skeleton -->
7
+ <div class="space-y-3">
8
+ <div class="h-8 bg-muted rounded-md w-3/4"></div>
9
+ <div class="h-4 bg-muted rounded-md w-1/2"></div>
10
+ </div>
11
+
12
+ <!-- Metadata skeleton -->
13
+ <div class="flex items-center gap-4">
14
+ <div class="h-4 bg-muted rounded-md w-24"></div>
15
+ <div class="h-4 bg-muted rounded-md w-32"></div>
16
+ </div>
17
+
18
+ <!-- Content skeleton -->
19
+ <div class="space-y-4">
20
+ <div class="space-y-2">
21
+ <div class="h-4 bg-muted rounded-md w-full"></div>
22
+ <div class="h-4 bg-muted rounded-md w-full"></div>
23
+ <div class="h-4 bg-muted rounded-md w-5/6"></div>
24
+ </div>
25
+
26
+ <!-- Heading skeleton -->
27
+ <div class="h-6 bg-muted rounded-md w-2/5 mt-8"></div>
28
+
29
+ <div class="space-y-2">
30
+ <div class="h-4 bg-muted rounded-md w-full"></div>
31
+ <div class="h-4 bg-muted rounded-md w-full"></div>
32
+ <div class="h-4 bg-muted rounded-md w-3/4"></div>
33
+ </div>
34
+
35
+ <!-- Code block skeleton -->
36
+ <div class="h-32 bg-muted rounded-lg w-full"></div>
37
+
38
+ <div class="space-y-2">
39
+ <div class="h-4 bg-muted rounded-md w-full"></div>
40
+ <div class="h-4 bg-muted rounded-md w-2/3"></div>
41
+ </div>
42
+
43
+ <!-- Another heading skeleton -->
44
+ <div class="h-6 bg-muted rounded-md w-1/3 mt-8"></div>
45
+
46
+ <div class="space-y-2">
47
+ <div class="h-4 bg-muted rounded-md w-full"></div>
48
+ <div class="h-4 bg-muted rounded-md w-full"></div>
49
+ <div class="h-4 bg-muted rounded-md w-4/5"></div>
50
+ <div class="h-4 bg-muted rounded-md w-full"></div>
51
+ </div>
52
+ </div>
53
+ </div>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const DocLoading: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type DocLoading = InstanceType<typeof DocLoading>;
18
+ export default DocLoading;
@@ -0,0 +1,106 @@
1
+ <script lang="ts">
2
+ import { Clock, Calendar, User } from 'lucide-svelte';
3
+ import type { SpecraConfig } from '../../config.types.js';
4
+
5
+ interface DocMeta {
6
+ readingTime?: number;
7
+ lastUpdated?: string;
8
+ authors?: Array<string | { name: string; avatar?: string; url?: string }>;
9
+ [key: string]: unknown;
10
+ }
11
+
12
+ interface Props {
13
+ meta: DocMeta;
14
+ config: SpecraConfig;
15
+ }
16
+
17
+ let { meta, config }: Props = $props();
18
+
19
+ const showReadingTime = $derived(config.features?.showReadingTime !== false && meta.readingTime);
20
+ const showLastUpdated = $derived(config.features?.showLastUpdated !== false && meta.lastUpdated);
21
+ const showAuthors = $derived(config.features?.showAuthors && meta.authors && meta.authors.length > 0);
22
+
23
+ function formatDate(dateStr: string): string {
24
+ try {
25
+ const date = new Date(dateStr);
26
+ return date.toLocaleDateString('en-US', {
27
+ year: 'numeric',
28
+ month: 'long',
29
+ day: 'numeric'
30
+ });
31
+ } catch {
32
+ return dateStr;
33
+ }
34
+ }
35
+
36
+ function getAuthorName(author: string | { name: string }): string {
37
+ return typeof author === 'string' ? author : author.name;
38
+ }
39
+
40
+ function getAuthorUrl(author: string | { name: string; url?: string }): string | undefined {
41
+ return typeof author === 'string' ? undefined : author.url;
42
+ }
43
+
44
+ function getAuthorAvatar(author: string | { name: string; avatar?: string }): string | undefined {
45
+ return typeof author === 'string' ? undefined : author.avatar;
46
+ }
47
+ </script>
48
+
49
+ {#if showReadingTime || showLastUpdated || showAuthors}
50
+ <div class="flex flex-wrap items-center gap-4 text-sm text-muted-foreground mb-6">
51
+ {#if showReadingTime}
52
+ <span class="inline-flex items-center gap-1.5">
53
+ <Clock class="h-3.5 w-3.5" />
54
+ <span>{meta.readingTime} min read</span>
55
+ </span>
56
+ {/if}
57
+
58
+ {#if showLastUpdated && meta.lastUpdated}
59
+ <span class="inline-flex items-center gap-1.5">
60
+ <Calendar class="h-3.5 w-3.5" />
61
+ <span>Updated {formatDate(meta.lastUpdated)}</span>
62
+ </span>
63
+ {/if}
64
+
65
+ {#if showAuthors && meta.authors}
66
+ <span class="inline-flex items-center gap-1.5">
67
+ <User class="h-3.5 w-3.5" />
68
+ <span class="flex items-center gap-1">
69
+ {#each meta.authors as author, index}
70
+ {#if getAuthorUrl(author)}
71
+ <a
72
+ href={getAuthorUrl(author)}
73
+ class="hover:text-foreground transition-colors underline-offset-2 hover:underline"
74
+ target="_blank"
75
+ rel="noopener noreferrer"
76
+ >
77
+ {#if getAuthorAvatar(author)}
78
+ <img
79
+ src={getAuthorAvatar(author)}
80
+ alt={getAuthorName(author)}
81
+ class="inline-block h-5 w-5 rounded-full mr-1"
82
+ />
83
+ {/if}
84
+ {getAuthorName(author)}
85
+ </a>
86
+ {:else}
87
+ <span>
88
+ {#if getAuthorAvatar(author)}
89
+ <img
90
+ src={getAuthorAvatar(author)}
91
+ alt={getAuthorName(author)}
92
+ class="inline-block h-5 w-5 rounded-full mr-1"
93
+ />
94
+ {/if}
95
+ {getAuthorName(author)}
96
+ </span>
97
+ {/if}
98
+ {#if index < meta.authors.length - 1}
99
+ <span>,</span>
100
+ {/if}
101
+ {/each}
102
+ </span>
103
+ </span>
104
+ {/if}
105
+ </div>
106
+ {/if}