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,18 @@
1
+ import type { SpecraConfig } from '../../config.types.js';
2
+ interface DocMeta {
3
+ readingTime?: number;
4
+ lastUpdated?: string;
5
+ authors?: Array<string | {
6
+ name: string;
7
+ avatar?: string;
8
+ url?: string;
9
+ }>;
10
+ [key: string]: unknown;
11
+ }
12
+ interface Props {
13
+ meta: DocMeta;
14
+ config: SpecraConfig;
15
+ }
16
+ declare const DocMetadata: import("svelte").Component<Props, {}, "">;
17
+ type DocMetadata = ReturnType<typeof DocMetadata>;
18
+ export default DocMetadata;
@@ -0,0 +1,56 @@
1
+ <script lang="ts">
2
+ import { ChevronLeft, ChevronRight } from 'lucide-svelte';
3
+
4
+ interface NavDoc {
5
+ title: string;
6
+ slug: string;
7
+ }
8
+
9
+ interface Props {
10
+ previousDoc?: NavDoc;
11
+ nextDoc?: NavDoc;
12
+ version: string;
13
+ }
14
+
15
+ let { previousDoc, nextDoc, version }: Props = $props();
16
+ </script>
17
+
18
+ {#if previousDoc || nextDoc}
19
+ <div class="mt-12 pt-8 border-t border-border grid grid-cols-2 gap-4">
20
+ {#if previousDoc}
21
+ <a
22
+ href="/docs/{version}/{previousDoc.slug}"
23
+ class="group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all"
24
+ style="text-decoration: none !important;"
25
+ >
26
+ <div class="flex items-center gap-2 text-sm text-muted-foreground">
27
+ <ChevronLeft class="h-4 w-4" />
28
+ <span>Previous</span>
29
+ </div>
30
+ <div class="text-base font-medium text-foreground group-hover:text-primary transition-colors">
31
+ {previousDoc.title}
32
+ </div>
33
+ </a>
34
+ {:else}
35
+ <div></div>
36
+ {/if}
37
+
38
+ {#if nextDoc}
39
+ <a
40
+ href="/docs/{version}/{nextDoc.slug}"
41
+ class="group flex flex-col gap-2 p-4 rounded-xl border border-border hover:border-primary/50 hover:bg-muted/50 transition-all text-right"
42
+ style="text-decoration: none !important;"
43
+ >
44
+ <div class="flex items-center justify-end gap-2 text-sm text-muted-foreground">
45
+ <span>Next</span>
46
+ <ChevronRight class="h-4 w-4" />
47
+ </div>
48
+ <div class="text-base font-medium text-foreground group-hover:text-primary transition-colors">
49
+ {nextDoc.title}
50
+ </div>
51
+ </a>
52
+ {:else}
53
+ <div></div>
54
+ {/if}
55
+ </div>
56
+ {/if}
@@ -0,0 +1,12 @@
1
+ interface NavDoc {
2
+ title: string;
3
+ slug: string;
4
+ }
5
+ interface Props {
6
+ previousDoc?: NavDoc;
7
+ nextDoc?: NavDoc;
8
+ version: string;
9
+ }
10
+ declare const DocNavigation: import("svelte").Component<Props, {}, "">;
11
+ type DocNavigation = ReturnType<typeof DocNavigation>;
12
+ export default DocNavigation;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ import { Tag } from 'lucide-svelte';
3
+
4
+ interface Props {
5
+ tags: string[];
6
+ }
7
+
8
+ let { tags }: Props = $props();
9
+ </script>
10
+
11
+ {#if tags && tags.length > 0}
12
+ <div class="flex flex-wrap items-center gap-2 mt-6 pt-4 border-t border-border">
13
+ <Tag class="h-3.5 w-3.5 text-muted-foreground" />
14
+ {#each tags as tag}
15
+ <span
16
+ class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground"
17
+ >
18
+ {tag}
19
+ </span>
20
+ {/each}
21
+ </div>
22
+ {/if}
@@ -0,0 +1,6 @@
1
+ interface Props {
2
+ tags: string[];
3
+ }
4
+ declare const DocTags: import("svelte").Component<Props, {}, "">;
5
+ type DocTags = ReturnType<typeof DocTags>;
6
+ export default DocTags;
@@ -0,0 +1,10 @@
1
+ <script lang="ts">
2
+ import { Eye } from 'lucide-svelte';
3
+ </script>
4
+
5
+ <div
6
+ class="inline-flex items-center gap-1.5 px-3 py-1 rounded-md bg-yellow-500/10 border border-yellow-500/20 text-yellow-700 dark:text-yellow-300 text-xs font-medium mb-4"
7
+ >
8
+ <Eye class="h-3.5 w-3.5" />
9
+ <span>Draft - Not visible in production</span>
10
+ </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 DraftBadge: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type DraftBadge = InstanceType<typeof DraftBadge>;
18
+ export default DraftBadge;
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ import type { SpecraConfig } from '../../config.types.js';
3
+ import Logo from './Logo.svelte';
4
+
5
+ interface Props {
6
+ config: SpecraConfig;
7
+ }
8
+
9
+ let { config }: Props = $props();
10
+
11
+ // The watermark is ALWAYS shown by default per the license.
12
+ // It can only be hidden with an active paid subscription (Starter+).
13
+ // Setting showBranding: false without a paid tier is a license violation.
14
+ let hideBranding = $derived(config.footer?.branding?.showBranding === false);
15
+ </script>
16
+
17
+ <footer class="bg-muted/30 dark:bg-muted/10 rounded-2xl mt-24">
18
+ <div class="px-2 md:px-6 py-12">
19
+ {#if config.footer?.links && config.footer.links.length > 0}
20
+ <div class="grid grid-cols-2 md:grid-cols-4 gap-8 mb-8">
21
+ {#each config.footer.links as column, idx (idx)}
22
+ <div>
23
+ <h3 class="font-semibold text-foreground mb-4">{column.title}</h3>
24
+ <ul class="space-y-2">
25
+ {#each column.items as item, itemIdx (itemIdx)}
26
+ <li>
27
+ <a
28
+ href={item.href}
29
+ class="text-sm text-muted-foreground hover:text-foreground transition-colors"
30
+ >
31
+ {item.label}
32
+ </a>
33
+ </li>
34
+ {/each}
35
+ </ul>
36
+ </div>
37
+ {/each}
38
+ </div>
39
+ {/if}
40
+
41
+ <div class="pt-8 border-t border-border/50">
42
+ <div class="flex flex-col md:flex-row items-center justify-between gap-4">
43
+ {#if config.footer?.copyright}
44
+ <p class="text-sm text-muted-foreground text-center md:text-left">
45
+ {config.footer.copyright}
46
+ </p>
47
+ {/if}
48
+
49
+ {#if !hideBranding}
50
+ <div class="flex items-center gap-2 text-sm text-muted-foreground">
51
+ {#if config.footer?.branding?.logo}
52
+ <Logo
53
+ logo={config.footer.branding.logo}
54
+ alt={config.footer.branding.title || 'Powered by'}
55
+ className="h-5 w-auto object-contain"
56
+ />
57
+ {/if}
58
+ <span>Powered by</span>
59
+ <a
60
+ href="https://specra-docs.com"
61
+ target="_blank"
62
+ rel="noopener noreferrer"
63
+ class="font-semibold hover:text-foreground transition-colors"
64
+ >
65
+ Specra
66
+ </a>
67
+ </div>
68
+ {/if}
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </footer>
@@ -0,0 +1,7 @@
1
+ import type { SpecraConfig } from '../../config.types.js';
2
+ interface Props {
3
+ config: SpecraConfig;
4
+ }
5
+ declare const Footer: import("svelte").Component<Props, {}, "">;
6
+ type Footer = ReturnType<typeof Footer>;
7
+ export default Footer;
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ interface Props {
3
+ src: string;
4
+ title?: string;
5
+ height?: number | string;
6
+ width?: string;
7
+ }
8
+
9
+ let {
10
+ src,
11
+ title = 'Embedded content',
12
+ height = 500,
13
+ width = '100%',
14
+ }: Props = $props();
15
+ </script>
16
+
17
+ <div class="my-6 rounded-xl border border-border overflow-hidden bg-muted/30">
18
+ <iframe
19
+ {src}
20
+ {title}
21
+ {width}
22
+ {height}
23
+ class="w-full"
24
+ loading="lazy"
25
+ sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
26
+ ></iframe>
27
+ </div>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ src: string;
3
+ title?: string;
4
+ height?: number | string;
5
+ width?: string;
6
+ }
7
+ declare const Frame: import("svelte").Component<Props, {}, "">;
8
+ type Frame = ReturnType<typeof Frame>;
9
+ export default Frame;
@@ -0,0 +1,123 @@
1
+ <script lang="ts">
2
+ import { Search, Menu, Github, Twitter, MessageCircle } from 'lucide-svelte';
3
+ import { getConfigContext } from '../../stores/config.js';
4
+ import { sidebarStore } from '../../stores/sidebar.js';
5
+ import VersionSwitcher from './VersionSwitcher.svelte';
6
+ import ThemeToggle from './ThemeToggle.svelte';
7
+ import SearchModal from './SearchModal.svelte';
8
+ import Logo from './Logo.svelte';
9
+ import type { SpecraConfig } from '../../config.types.js';
10
+
11
+ interface Props {
12
+ currentVersion: string;
13
+ versions: string[];
14
+ config?: SpecraConfig;
15
+ }
16
+
17
+ let { currentVersion, versions, config: configProp }: Props = $props();
18
+
19
+ const configStore = getConfigContext();
20
+ let config = $derived(configProp || $configStore);
21
+ let searchOpen = $state(false);
22
+ let isFlush = $derived(config?.navigation?.sidebarStyle === 'flush');
23
+
24
+ $effect(() => {
25
+ const handleKeyDown = (e: KeyboardEvent) => {
26
+ if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
27
+ e.preventDefault();
28
+ searchOpen = true;
29
+ }
30
+ };
31
+ window.addEventListener('keydown', handleKeyDown);
32
+ return () => window.removeEventListener('keydown', handleKeyDown);
33
+ });
34
+ </script>
35
+
36
+ <header class="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60">
37
+ <div class="{isFlush ? '' : 'container mx-auto'} flex h-16 items-center justify-between px-4 md:px-6">
38
+ <div class="flex items-center gap-1">
39
+ <button
40
+ onclick={() => sidebarStore.toggle()}
41
+ class="lg:hidden hover:bg-muted p-2 rounded-md transition-colors"
42
+ aria-label="Toggle menu"
43
+ >
44
+ <Menu class="h-5 w-5" />
45
+ </button>
46
+ <a href="/" class="flex items-center gap-2">
47
+ {#if !config.site.hideLogo}
48
+ {#if config.site.logo}
49
+ <Logo logo={config.site.logo} alt={config.site.title} className="w-18 object-contain" />
50
+ {:else}
51
+ <div class="h-8 w-8 rounded-xl bg-primary flex items-center justify-center">
52
+ <span class="text-primary-foreground font-bold text-lg">
53
+ {config.site.title.charAt(0).toUpperCase()}
54
+ </span>
55
+ </div>
56
+ {/if}
57
+ {/if}
58
+ {#if !config.site.hideTitle}
59
+ <span class="font-semibold text-lg text-foreground">{config.site.title ?? 'Specra'}</span>
60
+ {/if}
61
+ </a>
62
+ </div>
63
+
64
+ <div class="flex items-center gap-2">
65
+ {#if config.search?.enabled}
66
+ <button
67
+ onclick={() => (searchOpen = true)}
68
+ class="flex items-center gap-2 px-3 py-2 text-sm text-muted-foreground hover:text-foreground bg-muted rounded-md transition-colors"
69
+ >
70
+ <Search class="h-4 w-4" />
71
+ <span class="hidden sm:inline">{config.search.placeholder || 'Search'}</span>
72
+ <kbd class="hidden sm:inline-flex h-5 select-none items-center gap-1 rounded border border-border bg-background px-1.5 font-mono text-xs font-medium">
73
+ ⌘K
74
+ </kbd>
75
+ </button>
76
+ {/if}
77
+
78
+ {#if config.features?.versioning}
79
+ <VersionSwitcher {currentVersion} {versions} />
80
+ {/if}
81
+
82
+ <!-- Social Links -->
83
+ {#if config.social?.github}
84
+ <a
85
+ href={config.social.github}
86
+ target="_blank"
87
+ rel="noopener noreferrer"
88
+ class="hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors"
89
+ aria-label="GitHub"
90
+ >
91
+ <Github class="h-4 w-4" />
92
+ </a>
93
+ {/if}
94
+ {#if config.social?.twitter}
95
+ <a
96
+ href={config.social.twitter}
97
+ target="_blank"
98
+ rel="noopener noreferrer"
99
+ class="hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors"
100
+ aria-label="Twitter"
101
+ >
102
+ <Twitter class="h-4 w-4" />
103
+ </a>
104
+ {/if}
105
+ {#if config.social?.discord}
106
+ <a
107
+ href={config.social.discord}
108
+ target="_blank"
109
+ rel="noopener noreferrer"
110
+ class="hidden md:flex items-center justify-center h-9 w-9 rounded-md hover:bg-muted transition-colors"
111
+ aria-label="Discord"
112
+ >
113
+ <MessageCircle class="h-4 w-4" />
114
+ </a>
115
+ {/if}
116
+
117
+ <ThemeToggle />
118
+ </div>
119
+ </div>
120
+
121
+ <!-- Search Modal -->
122
+ <SearchModal isOpen={searchOpen} onClose={() => (searchOpen = false)} {config} />
123
+ </header>
@@ -0,0 +1,9 @@
1
+ import type { SpecraConfig } from '../../config.types.js';
2
+ interface Props {
3
+ currentVersion: string;
4
+ versions: string[];
5
+ config?: SpecraConfig;
6
+ }
7
+ declare const Header: import("svelte").Component<Props, {}, "">;
8
+ type Header = ReturnType<typeof Header>;
9
+ export default Header;
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { sidebarStore } from '../../stores/sidebar.js';
3
+ import type { Snippet } from 'svelte';
4
+
5
+ /**
6
+ * HeaderWithMenu wraps a header snippet and provides mobile menu toggle functionality.
7
+ * In Svelte, instead of React's cloneElement pattern, the header component
8
+ * directly accesses the sidebarStore for toggle behavior.
9
+ * This component exists as a thin wrapper for layout composition.
10
+ */
11
+ interface Props {
12
+ /** Header content to render */
13
+ header?: Snippet;
14
+ /** Optional: override the toggle handler */
15
+ onMenuClick?: () => void;
16
+ children?: Snippet;
17
+ }
18
+
19
+ let { header, onMenuClick, children }: Props = $props();
20
+
21
+ function handleMenuClick() {
22
+ if (onMenuClick) {
23
+ onMenuClick();
24
+ } else {
25
+ sidebarStore.toggle();
26
+ }
27
+ }
28
+ </script>
29
+
30
+ {#if header}
31
+ {@render header()}
32
+ {:else if children}
33
+ {@render children()}
34
+ {/if}
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ /**
3
+ * HeaderWithMenu wraps a header snippet and provides mobile menu toggle functionality.
4
+ * In Svelte, instead of React's cloneElement pattern, the header component
5
+ * directly accesses the sidebarStore for toggle behavior.
6
+ * This component exists as a thin wrapper for layout composition.
7
+ */
8
+ interface Props {
9
+ /** Header content to render */
10
+ header?: Snippet;
11
+ /** Optional: override the toggle handler */
12
+ onMenuClick?: () => void;
13
+ children?: Snippet;
14
+ }
15
+ declare const HeaderWithMenu: import("svelte").Component<Props, {}, "">;
16
+ type HeaderWithMenu = ReturnType<typeof HeaderWithMenu>;
17
+ export default HeaderWithMenu;
@@ -0,0 +1,44 @@
1
+ <script lang="ts">
2
+ import { RefreshCw } from 'lucide-svelte';
3
+ import { browser } from '$app/environment';
4
+ import { dev } from '$app/environment';
5
+
6
+ let isReloading = $state(false);
7
+ let showIndicator = $state(false);
8
+
9
+ $effect(() => {
10
+ if (!browser || !dev) return;
11
+
12
+ // Listen for Vite HMR events
13
+ if (import.meta.hot) {
14
+ import.meta.hot.on('vite:beforeUpdate', () => {
15
+ isReloading = true;
16
+ showIndicator = true;
17
+ });
18
+
19
+ import.meta.hot.on('vite:afterUpdate', () => {
20
+ isReloading = false;
21
+ // Keep indicator visible briefly after update
22
+ setTimeout(() => {
23
+ showIndicator = false;
24
+ }, 1500);
25
+ });
26
+
27
+ import.meta.hot.on('vite:error', () => {
28
+ isReloading = false;
29
+ showIndicator = false;
30
+ });
31
+ }
32
+ });
33
+ </script>
34
+
35
+ {#if dev && showIndicator}
36
+ <div
37
+ class="fixed top-4 right-4 z-50 inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full shadow-lg backdrop-blur-sm text-xs font-medium transition-all duration-300 {isReloading
38
+ ? 'bg-blue-500/90 text-white'
39
+ : 'bg-green-500/90 text-white'}"
40
+ >
41
+ <RefreshCw class="h-3 w-3 {isReloading ? 'animate-spin' : ''}" />
42
+ <span>{isReloading ? 'Reloading...' : 'Updated'}</span>
43
+ </div>
44
+ {/if}
@@ -0,0 +1,3 @@
1
+ declare const HotReloadIndicator: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type HotReloadIndicator = ReturnType<typeof HotReloadIndicator>;
3
+ export default HotReloadIndicator;
@@ -0,0 +1,103 @@
1
+ <script lang="ts">
2
+ import * as icons from 'lucide-svelte';
3
+ import type { ComponentType } from 'svelte';
4
+
5
+ interface Props {
6
+ icon: string | ComponentType;
7
+ iconType?: 'lucide' | 'url' | 'fa' | 'auto';
8
+ color?: string;
9
+ size?: number | string;
10
+ className?: string;
11
+ }
12
+
13
+ let { icon, iconType = 'auto', color, size = 20, className = '' }: Props = $props();
14
+
15
+ // Convert kebab-case or lowercase to PascalCase for Lucide icon lookup
16
+ function toPascalCase(str: string): string {
17
+ return str
18
+ .split(/[-_\s]/)
19
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
20
+ .join('');
21
+ }
22
+
23
+ // Resolve a string icon name to a Lucide component
24
+ function getLucideIcon(name: string): ComponentType | null {
25
+ const pascalName = toPascalCase(name);
26
+ const iconMap = icons as Record<string, ComponentType>;
27
+ return iconMap[pascalName] || null;
28
+ }
29
+
30
+ // Determine icon type from the icon value
31
+ function detectIconType(iconValue: string): 'lucide' | 'url' | 'fa' | 'text' {
32
+ if (iconValue.startsWith('http') || iconValue.startsWith('/') || iconValue.startsWith('data:')) {
33
+ return 'url';
34
+ }
35
+ if (iconValue.startsWith('fa-') || iconValue.startsWith('fas ') || iconValue.startsWith('fab ') || iconValue.startsWith('far ')) {
36
+ return 'fa';
37
+ }
38
+ // Check if it's a valid Lucide icon
39
+ if (getLucideIcon(iconValue)) {
40
+ return 'lucide';
41
+ }
42
+ return 'text';
43
+ }
44
+
45
+ const resolvedType = $derived(
46
+ typeof icon === 'string'
47
+ ? iconType === 'auto'
48
+ ? detectIconType(icon)
49
+ : iconType
50
+ : 'component'
51
+ );
52
+
53
+ const lucideComponent = $derived(
54
+ typeof icon === 'string' && resolvedType === 'lucide' ? getLucideIcon(icon) : null
55
+ );
56
+
57
+ const sizeValue = $derived(typeof size === 'number' ? `${size}px` : size);
58
+ const sizeNum = $derived(typeof size === 'string' ? parseInt(size, 10) || 20 : size);
59
+ </script>
60
+
61
+ {#if typeof icon !== 'string'}
62
+ <!-- Svelte component passed directly -->
63
+ <svelte:component
64
+ this={icon}
65
+ size={sizeNum}
66
+ class="inline-block {className}"
67
+ style={color ? `color: ${color}` : undefined}
68
+ />
69
+ {:else if resolvedType === 'lucide' && lucideComponent}
70
+ <!-- Lucide icon by name -->
71
+ <svelte:component
72
+ this={lucideComponent}
73
+ size={sizeNum}
74
+ class="inline-block {className}"
75
+ style={color ? `color: ${color}` : undefined}
76
+ />
77
+ {:else if resolvedType === 'url'}
78
+ <!-- URL-based icon (image) -->
79
+ <img
80
+ src={icon}
81
+ alt=""
82
+ width={sizeNum}
83
+ height={sizeNum}
84
+ class="inline-block object-contain {className}"
85
+ style="width: {sizeValue}; height: {sizeValue};"
86
+ />
87
+ {:else if resolvedType === 'fa'}
88
+ <!-- Font Awesome icon -->
89
+ <i
90
+ class="{icon} {className}"
91
+ style="font-size: {sizeValue}; {color ? `color: ${color}` : ''}"
92
+ aria-hidden="true"
93
+ ></i>
94
+ {:else}
95
+ <!-- Fallback: render text (emoji or single char) -->
96
+ <span
97
+ class="inline-flex items-center justify-center {className}"
98
+ style="width: {sizeValue}; height: {sizeValue}; font-size: {sizeValue}; line-height: 1; {color ? `color: ${color}` : ''}"
99
+ aria-hidden="true"
100
+ >
101
+ {icon}
102
+ </span>
103
+ {/if}
@@ -0,0 +1,11 @@
1
+ import type { ComponentType } from 'svelte';
2
+ interface Props {
3
+ icon: string | ComponentType;
4
+ iconType?: 'lucide' | 'url' | 'fa' | 'auto';
5
+ color?: string;
6
+ size?: number | string;
7
+ className?: string;
8
+ }
9
+ declare const Icon: import("svelte").Component<Props, {}, "">;
10
+ type Icon = ReturnType<typeof Icon>;
11
+ export default Icon;