create-specra 0.1.7 → 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 (136) hide show
  1. package/LICENSE.MD +16 -4
  2. package/README.md +53 -17
  3. package/dist/chunk-3DKWECRK.js +45 -0
  4. package/dist/chunk-3DKWECRK.js.map +1 -0
  5. package/dist/chunk-MA7QG54W.js +74 -0
  6. package/dist/chunk-MA7QG54W.js.map +1 -0
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.js +33 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/deploy-SCEMUQNS.js +141 -0
  11. package/dist/deploy-SCEMUQNS.js.map +1 -0
  12. package/dist/index.js +11 -11
  13. package/dist/index.js.map +1 -1
  14. package/dist/login-NKDRQXRE.js +71 -0
  15. package/dist/login-NKDRQXRE.js.map +1 -0
  16. package/dist/logout-H543QEKU.js +20 -0
  17. package/dist/logout-H543QEKU.js.map +1 -0
  18. package/dist/logs-YDAUCMAV.js +71 -0
  19. package/dist/logs-YDAUCMAV.js.map +1 -0
  20. package/dist/projects-3TAY7EDJ.js +42 -0
  21. package/dist/projects-3TAY7EDJ.js.map +1 -0
  22. package/package.json +7 -3
  23. package/templates/book-docs/docs/v1.0.0/concepts.mdx +89 -0
  24. package/templates/book-docs/docs/v1.0.0/content/_category_.json +7 -0
  25. package/templates/book-docs/docs/v1.0.0/content/formatting.mdx +128 -0
  26. package/templates/book-docs/docs/v1.0.0/content/reusable-content.mdx +116 -0
  27. package/templates/book-docs/docs/v1.0.0/content/structure.mdx +92 -0
  28. package/templates/book-docs/docs/v1.0.0/customization/_category_.json +7 -0
  29. package/templates/book-docs/docs/v1.0.0/customization/branding.mdx +115 -0
  30. package/templates/book-docs/docs/v1.0.0/customization/themes.mdx +81 -0
  31. package/templates/book-docs/docs/v1.0.0/introduction.mdx +38 -0
  32. package/templates/book-docs/docs/v1.0.0/quickstart.mdx +112 -0
  33. package/templates/book-docs/docs/v2.0.0/concepts.mdx +89 -0
  34. package/templates/book-docs/docs/v2.0.0/content/_category_.json +7 -0
  35. package/templates/book-docs/docs/v2.0.0/content/formatting.mdx +128 -0
  36. package/templates/book-docs/docs/v2.0.0/content/reusable-content.mdx +116 -0
  37. package/templates/book-docs/docs/v2.0.0/content/structure.mdx +92 -0
  38. package/templates/book-docs/docs/v2.0.0/customization/_category_.json +7 -0
  39. package/templates/book-docs/docs/v2.0.0/customization/branding.mdx +115 -0
  40. package/templates/book-docs/docs/v2.0.0/customization/themes.mdx +81 -0
  41. package/templates/book-docs/docs/v2.0.0/introduction.mdx +39 -0
  42. package/templates/book-docs/docs/v2.0.0/quickstart.mdx +112 -0
  43. package/templates/book-docs/gitignore +7 -0
  44. package/templates/book-docs/package.json +28 -0
  45. package/templates/book-docs/postcss.config.mjs +8 -0
  46. package/templates/book-docs/public/api-specs/openapi-example.json +259 -0
  47. package/templates/book-docs/public/api-specs/postman-example.json +205 -0
  48. package/templates/book-docs/public/api-specs/test-api.json +256 -0
  49. package/templates/book-docs/public/api-specs/users-api.json +264 -0
  50. package/templates/book-docs/specra.config.json +77 -0
  51. package/templates/book-docs/src/app.css +2 -0
  52. package/templates/book-docs/src/app.html +12 -0
  53. package/templates/book-docs/src/routes/+layout.server.ts +11 -0
  54. package/templates/book-docs/src/routes/+layout.svelte +21 -0
  55. package/templates/book-docs/src/routes/+page.server.ts +9 -0
  56. package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +119 -0
  57. package/templates/book-docs/src/routes/docs/[version]/[...slug]/+page.svelte +129 -0
  58. package/templates/book-docs/svelte.config.js +8 -0
  59. package/templates/book-docs/tsconfig.json +12 -0
  60. package/templates/book-docs/vite.config.ts +6 -0
  61. package/templates/jbrains-docs/docs/v1.0.0/advanced/_category_.json +8 -0
  62. package/templates/jbrains-docs/docs/v1.0.0/advanced/async.mdx +95 -0
  63. package/templates/jbrains-docs/docs/v1.0.0/advanced/generics.mdx +126 -0
  64. package/templates/jbrains-docs/docs/v1.0.0/basics/_category_.json +8 -0
  65. package/templates/jbrains-docs/docs/v1.0.0/basics/control-flow.mdx +106 -0
  66. package/templates/jbrains-docs/docs/v1.0.0/basics/syntax.mdx +129 -0
  67. package/templates/jbrains-docs/docs/v1.0.0/basics/types.mdx +135 -0
  68. package/templates/jbrains-docs/docs/v1.0.0/getting-started.mdx +111 -0
  69. package/templates/jbrains-docs/docs/v1.0.0/home.mdx +37 -0
  70. package/templates/jbrains-docs/docs/v1.0.0/tools/_category_.json +8 -0
  71. package/templates/jbrains-docs/docs/v1.0.0/tools/build-tools.mdx +165 -0
  72. package/templates/jbrains-docs/docs/v1.0.0/tools/testing.mdx +112 -0
  73. package/templates/jbrains-docs/docs/v2.0.0/advanced/_category_.json +8 -0
  74. package/templates/jbrains-docs/docs/v2.0.0/advanced/async.mdx +95 -0
  75. package/templates/jbrains-docs/docs/v2.0.0/advanced/generics.mdx +126 -0
  76. package/templates/jbrains-docs/docs/v2.0.0/basics/_category_.json +8 -0
  77. package/templates/jbrains-docs/docs/v2.0.0/basics/control-flow.mdx +106 -0
  78. package/templates/jbrains-docs/docs/v2.0.0/basics/syntax.mdx +129 -0
  79. package/templates/jbrains-docs/docs/v2.0.0/basics/types.mdx +135 -0
  80. package/templates/jbrains-docs/docs/v2.0.0/getting-started.mdx +111 -0
  81. package/templates/jbrains-docs/docs/v2.0.0/home.mdx +37 -0
  82. package/templates/jbrains-docs/docs/v2.0.0/tools/_category_.json +8 -0
  83. package/templates/jbrains-docs/docs/v2.0.0/tools/build-tools.mdx +165 -0
  84. package/templates/jbrains-docs/docs/v2.0.0/tools/testing.mdx +112 -0
  85. package/templates/jbrains-docs/gitignore +7 -0
  86. package/templates/jbrains-docs/package.json +28 -0
  87. package/templates/jbrains-docs/postcss.config.mjs +8 -0
  88. package/templates/jbrains-docs/public/api-specs/openapi-example.json +259 -0
  89. package/templates/jbrains-docs/public/api-specs/postman-example.json +205 -0
  90. package/templates/jbrains-docs/public/api-specs/test-api.json +256 -0
  91. package/templates/jbrains-docs/public/api-specs/users-api.json +264 -0
  92. package/templates/jbrains-docs/specra.config.json +80 -0
  93. package/templates/jbrains-docs/src/app.css +2 -0
  94. package/templates/jbrains-docs/src/app.html +12 -0
  95. package/templates/jbrains-docs/src/routes/+layout.server.ts +11 -0
  96. package/templates/jbrains-docs/src/routes/+layout.svelte +21 -0
  97. package/templates/jbrains-docs/src/routes/+page.server.ts +9 -0
  98. package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.server.ts +119 -0
  99. package/templates/jbrains-docs/src/routes/docs/[version]/[...slug]/+page.svelte +129 -0
  100. package/templates/jbrains-docs/svelte.config.js +8 -0
  101. package/templates/jbrains-docs/tsconfig.json +12 -0
  102. package/templates/jbrains-docs/vite.config.ts +6 -0
  103. package/templates/minimal/docs/v1.0.0/about.mdx +3 -3
  104. package/templates/minimal/docs/v2.0.0/about.mdx +3 -3
  105. package/templates/minimal/gitignore +7 -0
  106. package/templates/minimal/package.json +18 -24
  107. package/templates/minimal/specra.config.json +12 -63
  108. package/templates/minimal/src/app.css +2 -0
  109. package/templates/minimal/src/app.html +12 -0
  110. package/templates/minimal/src/routes/+layout.server.ts +11 -0
  111. package/templates/minimal/src/routes/+layout.svelte +21 -0
  112. package/templates/minimal/src/routes/+page.server.ts +9 -0
  113. package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.server.ts +119 -0
  114. package/templates/minimal/src/routes/docs/[version]/[...slug]/+page.svelte +129 -0
  115. package/templates/minimal/svelte.config.js +8 -0
  116. package/templates/minimal/tsconfig.json +7 -36
  117. package/templates/minimal/vite.config.ts +6 -0
  118. package/templates/minimal/README.md +0 -132
  119. package/templates/minimal/app/api/mdx-watch/route.ts +0 -6
  120. package/templates/minimal/app/api/search/route.ts +0 -75
  121. package/templates/minimal/app/docs/[version]/[...slug]/loading.tsx +0 -7
  122. package/templates/minimal/app/docs/[version]/[...slug]/page.tsx +0 -205
  123. package/templates/minimal/app/docs/[version]/[...slug]/page.tsx.bak +0 -203
  124. package/templates/minimal/app/docs/[version]/not-found.tsx +0 -10
  125. package/templates/minimal/app/docs/[version]/page.tsx +0 -27
  126. package/templates/minimal/app/globals.css +0 -9
  127. package/templates/minimal/app/layout.tsx +0 -62
  128. package/templates/minimal/app/not-found.tsx +0 -10
  129. package/templates/minimal/app/page.tsx +0 -179
  130. package/templates/minimal/next.config.mjs +0 -1
  131. package/templates/minimal/package-lock.json +0 -7881
  132. package/templates/minimal/proxy_.ts +0 -22
  133. package/templates/minimal/scripts/generate-redirects.mjs +0 -128
  134. package/templates/minimal/scripts/generate-static-redirects.mjs +0 -115
  135. package/templates/minimal/scripts/index-search.ts +0 -182
  136. package/templates/minimal/scripts/test-search.ts +0 -83
@@ -0,0 +1,264 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "title": "Users API",
4
+ "description": "Complete API reference for managing users in the system",
5
+ "baseUrl": "https://api.example.com/v1",
6
+ "env": {
7
+ "AUTH_TOKEN": "your_api_token_here"
8
+ },
9
+ "auth": {
10
+ "type": "bearer",
11
+ "description": "All requests require a valid API token in the Authorization header",
12
+ "tokenPrefix": "Bearer"
13
+ },
14
+ "globalHeaders": [
15
+ {
16
+ "name": "Authorization",
17
+ "value": "Bearer {AUTH_TOKEN}",
18
+ "description": "Your API authentication token"
19
+ },
20
+ {
21
+ "name": "Content-Type",
22
+ "value": "application/json"
23
+ }
24
+ ],
25
+ "endpoints": [
26
+ {
27
+ "title": "Get User by ID",
28
+ "method": "GET",
29
+ "path": "/users/:id",
30
+ "description": "Retrieve detailed information about a specific user",
31
+ "pathParams": [
32
+ {
33
+ "name": "id",
34
+ "type": "string",
35
+ "required": true,
36
+ "description": "The unique identifier of the user",
37
+ "example": "user_123"
38
+ }
39
+ ],
40
+ "queryParams": [
41
+ {
42
+ "name": "fields",
43
+ "type": "string",
44
+ "description": "Comma-separated list of fields to include",
45
+ "example": "name,email,created_at"
46
+ },
47
+ {
48
+ "name": "include_metadata",
49
+ "type": "boolean",
50
+ "description": "Include additional metadata in the response",
51
+ "default": false
52
+ }
53
+ ],
54
+ "successResponse": {
55
+ "status": 200,
56
+ "description": "User retrieved successfully",
57
+ "example": {
58
+ "id": "user_123",
59
+ "name": "John Doe",
60
+ "email": "john@example.com",
61
+ "role": "admin",
62
+ "created_at": "2024-01-15T10:30:00Z",
63
+ "updated_at": "2024-01-20T14:22:00Z"
64
+ }
65
+ },
66
+ "errorResponses": [
67
+ {
68
+ "status": 404,
69
+ "description": "User not found",
70
+ "example": {
71
+ "error": "User not found",
72
+ "code": "USER_NOT_FOUND",
73
+ "message": "No user exists with the provided ID"
74
+ }
75
+ },
76
+ {
77
+ "status": 401,
78
+ "description": "Unauthorized",
79
+ "example": {
80
+ "error": "Unauthorized",
81
+ "code": "UNAUTHORIZED",
82
+ "message": "Invalid or missing authentication token"
83
+ }
84
+ }
85
+ ],
86
+ "examples": [
87
+ {
88
+ "title": "cURL",
89
+ "language": "bash",
90
+ "code": "curl -X GET \"https://api.example.com/v1/users/user_123\" \\\n -H \"Authorization: Bearer your_api_token_here\""
91
+ },
92
+ {
93
+ "title": "JavaScript (fetch)",
94
+ "language": "javascript",
95
+ "code": "const response = await fetch('https://api.example.com/v1/users/user_123', {\n headers: {\n 'Authorization': 'Bearer your_api_token_here'\n }\n});\nconst user = await response.json();"
96
+ }
97
+ ]
98
+ },
99
+ {
100
+ "title": "List All Users",
101
+ "method": "GET",
102
+ "path": "/users",
103
+ "description": "Retrieve a paginated list of all users",
104
+ "queryParams": [
105
+ {
106
+ "name": "page",
107
+ "type": "number",
108
+ "description": "Page number for pagination",
109
+ "default": 1
110
+ },
111
+ {
112
+ "name": "limit",
113
+ "type": "number",
114
+ "description": "Number of users per page",
115
+ "default": 20
116
+ },
117
+ {
118
+ "name": "role",
119
+ "type": "string",
120
+ "description": "Filter users by role",
121
+ "example": "admin"
122
+ }
123
+ ],
124
+ "successResponse": {
125
+ "status": 200,
126
+ "description": "List of users retrieved successfully",
127
+ "example": {
128
+ "data": [
129
+ {
130
+ "id": "user_123",
131
+ "name": "John Doe",
132
+ "email": "john@example.com",
133
+ "role": "admin"
134
+ },
135
+ {
136
+ "id": "user_124",
137
+ "name": "Jane Smith",
138
+ "email": "jane@example.com",
139
+ "role": "user"
140
+ }
141
+ ],
142
+ "pagination": {
143
+ "page": 1,
144
+ "limit": 20,
145
+ "total": 42,
146
+ "pages": 3
147
+ }
148
+ }
149
+ }
150
+ },
151
+ {
152
+ "title": "Create New User",
153
+ "method": "POST",
154
+ "path": "/users",
155
+ "description": "Create a new user account",
156
+ "body": {
157
+ "description": "User data to create",
158
+ "example": {
159
+ "name": "Alice Johnson",
160
+ "email": "alice@example.com",
161
+ "role": "user",
162
+ "password": "secure_password_123"
163
+ }
164
+ },
165
+ "successResponse": {
166
+ "status": 201,
167
+ "description": "User created successfully",
168
+ "example": {
169
+ "id": "user_125",
170
+ "name": "Alice Johnson",
171
+ "email": "alice@example.com",
172
+ "role": "user",
173
+ "created_at": "2024-01-21T09:15:00Z"
174
+ }
175
+ },
176
+ "errorResponses": [
177
+ {
178
+ "status": 400,
179
+ "description": "Validation error",
180
+ "example": {
181
+ "error": "Validation failed",
182
+ "code": "VALIDATION_ERROR",
183
+ "details": {
184
+ "email": "Email address already exists"
185
+ }
186
+ }
187
+ }
188
+ ],
189
+ "examples": [
190
+ {
191
+ "title": "cURL",
192
+ "language": "bash",
193
+ "code": "curl -X POST \"https://api.example.com/v1/users\" \\\n -H \"Authorization: Bearer your_api_token_here\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"name\": \"Alice Johnson\",\n \"email\": \"alice@example.com\",\n \"role\": \"user\",\n \"password\": \"secure_password_123\"\n }'"
194
+ }
195
+ ]
196
+ },
197
+ {
198
+ "title": "Update User",
199
+ "method": "PATCH",
200
+ "path": "/users/:id",
201
+ "description": "Update user information",
202
+ "pathParams": [
203
+ {
204
+ "name": "id",
205
+ "type": "string",
206
+ "required": true,
207
+ "description": "User ID to update"
208
+ }
209
+ ],
210
+ "body": {
211
+ "description": "Fields to update (all optional)",
212
+ "example": {
213
+ "name": "John Updated",
214
+ "email": "john.updated@example.com",
215
+ "role": "moderator"
216
+ }
217
+ },
218
+ "successResponse": {
219
+ "status": 200,
220
+ "description": "User updated successfully",
221
+ "example": {
222
+ "id": "user_123",
223
+ "name": "John Updated",
224
+ "email": "john.updated@example.com",
225
+ "role": "moderator",
226
+ "updated_at": "2024-01-21T10:00:00Z"
227
+ }
228
+ }
229
+ },
230
+ {
231
+ "title": "Delete User",
232
+ "method": "DELETE",
233
+ "path": "/users/:id",
234
+ "description": "Permanently delete a user account",
235
+ "pathParams": [
236
+ {
237
+ "name": "id",
238
+ "type": "string",
239
+ "required": true,
240
+ "description": "User ID to delete"
241
+ }
242
+ ],
243
+ "successResponse": {
244
+ "status": 204,
245
+ "description": "User deleted successfully"
246
+ },
247
+ "errorResponses": [
248
+ {
249
+ "status": 404,
250
+ "description": "User not found"
251
+ },
252
+ {
253
+ "status": 403,
254
+ "description": "Forbidden - Cannot delete this user",
255
+ "example": {
256
+ "error": "Forbidden",
257
+ "code": "CANNOT_DELETE_ADMIN",
258
+ "message": "Cannot delete the primary admin account"
259
+ }
260
+ }
261
+ ]
262
+ }
263
+ ]
264
+ }
@@ -0,0 +1,80 @@
1
+ {
2
+ "$schema": "./node_modules/specra/config/specra.config.schema.json",
3
+ "site": {
4
+ "title": "My Docs",
5
+ "description": "Documentation for my project",
6
+ "url": "http://localhost:5173",
7
+ "baseUrl": "/",
8
+ "language": "en",
9
+ "organizationName": "my-org",
10
+ "projectName": "my-project",
11
+ "activeVersion": "v1.0.0"
12
+ },
13
+ "theme": {
14
+ "defaultMode": "light",
15
+ "respectPrefersColorScheme": true
16
+ },
17
+ "navigation": {
18
+ "showSidebar": true,
19
+ "collapsibleSidebar": true,
20
+ "sidebarStyle": "flush",
21
+ "showBreadcrumbs": true,
22
+ "showTableOfContents": false,
23
+ "tocPosition": "right",
24
+ "tocMaxDepth": 3,
25
+ "tabGroups": [
26
+ {
27
+ "id": "language",
28
+ "label": "Language"
29
+ },
30
+ {
31
+ "id": "multiplatform",
32
+ "label": "Multiplatform"
33
+ }
34
+ ]
35
+ },
36
+ "social": {
37
+ "github": "https://github.com/your-org/your-repo"
38
+ },
39
+ "search": {
40
+ "enabled": false
41
+ },
42
+ "banner": {
43
+ "enabled": true,
44
+ "message": "Docs v2.0.0 is now available!",
45
+ "type": "info",
46
+ "dismissible": true
47
+ },
48
+ "footer": {
49
+ "copyright": "Copyright © 2025 My Project. All rights reserved.",
50
+ "links": [
51
+ {
52
+ "title": "Documentation",
53
+ "items": [
54
+ {
55
+ "label": "Getting Started",
56
+ "href": "/docs/v1.0.0/getting-started"
57
+ }
58
+ ]
59
+ },
60
+ {
61
+ "title": "Community",
62
+ "items": [
63
+ {
64
+ "label": "GitHub",
65
+ "href": "https://github.com/your-org/your-repo"
66
+ }
67
+ ]
68
+ }
69
+ ]
70
+ },
71
+ "features": {
72
+ "showLastUpdated": true,
73
+ "showReadingTime": false,
74
+ "showAuthors": false,
75
+ "showTags": true,
76
+ "versioning": true,
77
+ "showVersionBadge": true,
78
+ "i18n": false
79
+ }
80
+ }
@@ -0,0 +1,2 @@
1
+ @import "specra/styles";
2
+ @source "./**/*.{js,ts,svelte}";
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%sveltekit.assets%/favicon.svg" type="image/svg+xml" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ %sveltekit.head%
8
+ </head>
9
+ <body data-sveltekit-preload-data="hover" class="font-sans antialiased">
10
+ <div style="display: contents">%sveltekit.body%</div>
11
+ </body>
12
+ </html>
@@ -0,0 +1,11 @@
1
+ import { getConfig, initConfig } from 'specra';
2
+ import specraConfig from '../../specra.config.json';
3
+ import type { LayoutServerLoad } from './$types';
4
+ import type { SpecraConfig } from 'specra';
5
+
6
+ initConfig(specraConfig as unknown as Partial<SpecraConfig>);
7
+
8
+ export const load: LayoutServerLoad = async () => {
9
+ const config = getConfig();
10
+ return { config };
11
+ };
@@ -0,0 +1,21 @@
1
+ <script lang="ts">
2
+ import '../app.css';
3
+ import { LayoutProviders } from 'specra/components';
4
+ import type { Snippet } from 'svelte';
5
+ import type { LayoutData } from './$types';
6
+
7
+ let { data, children }: { data: LayoutData; children: Snippet } = $props();
8
+ </script>
9
+
10
+ <svelte:head>
11
+ <title>{data?.config?.site?.title || 'Documentation'}</title>
12
+ <meta name="description" content={data?.config?.site?.description || 'Modern documentation platform'} />
13
+ </svelte:head>
14
+
15
+ {#if data?.config}
16
+ <LayoutProviders config={data.config}>
17
+ {@render children?.()}
18
+ </LayoutProviders>
19
+ {:else}
20
+ {@render children?.()}
21
+ {/if}
@@ -0,0 +1,9 @@
1
+ import { redirect } from '@sveltejs/kit';
2
+ import { getConfig } from 'specra';
3
+ import type { PageServerLoad } from './$types';
4
+
5
+ export const load: PageServerLoad = async () => {
6
+ const config = getConfig();
7
+ const activeVersion = config.site?.activeVersion || 'v1.0.0';
8
+ redirect(302, `/docs/${activeVersion}/home`);
9
+ };
@@ -0,0 +1,119 @@
1
+ import {
2
+ extractTableOfContents,
3
+ getAdjacentDocs,
4
+ isCategoryPage,
5
+ getCachedVersions,
6
+ getCachedAllDocs,
7
+ getCachedDocBySlug,
8
+ getI18nConfig,
9
+ getConfig,
10
+ } from 'specra';
11
+ import type { PageServerLoad } from './$types';
12
+
13
+ export const load: PageServerLoad = async ({ params }) => {
14
+ const { version, slug: slugArray } = params;
15
+ const slug = slugArray;
16
+
17
+ const i18nConfig = getI18nConfig();
18
+ const slugParts = slug.split('/');
19
+ let locale: string | undefined;
20
+ if (i18nConfig && i18nConfig.locales.includes(slugParts[0])) {
21
+ locale = slugParts[0];
22
+ }
23
+
24
+ const allDocs = await getCachedAllDocs(version, locale);
25
+ const versions = getCachedVersions();
26
+ const config = getConfig();
27
+ const isCategory = isCategoryPage(slug, allDocs);
28
+ const doc = await getCachedDocBySlug(slug, version);
29
+
30
+ let title = 'Page Not Found';
31
+ let description = 'The requested documentation page could not be found.';
32
+ let ogUrl = `/docs/${version}/${slug}`;
33
+
34
+ if (doc) {
35
+ title = doc.meta.title || doc.title;
36
+ description = doc.meta.description || `Documentation for ${title}`;
37
+ }
38
+
39
+ // Category page without doc content
40
+ if (!doc && isCategory) {
41
+ const categoryDoc = allDocs.find((d) => d.slug.startsWith(slug + '/'));
42
+ const categoryTabGroup = categoryDoc?.meta?.tab_group || categoryDoc?.categoryTabGroup;
43
+ const categoryTitle = slug
44
+ .split('/')
45
+ .pop()
46
+ ?.replace(/-/g, ' ')
47
+ .replace(/\b\w/g, (l) => l.toUpperCase()) || 'Category';
48
+
49
+ return {
50
+ version,
51
+ slug,
52
+ allDocs,
53
+ versions,
54
+ config,
55
+ isCategory: true,
56
+ isNotFound: false,
57
+ doc: null,
58
+ categoryTitle,
59
+ categoryDescription: 'Browse the documentation in this section.',
60
+ categoryTabGroup,
61
+ toc: [],
62
+ previous: null,
63
+ next: null,
64
+ title,
65
+ description,
66
+ ogUrl,
67
+ };
68
+ }
69
+
70
+ // Not found
71
+ if (!doc) {
72
+ return {
73
+ version,
74
+ slug,
75
+ allDocs,
76
+ versions,
77
+ config,
78
+ isCategory: false,
79
+ isNotFound: true,
80
+ doc: null,
81
+ categoryTitle: null,
82
+ categoryDescription: null,
83
+ categoryTabGroup: undefined,
84
+ toc: [],
85
+ previous: null,
86
+ next: null,
87
+ title,
88
+ description,
89
+ ogUrl,
90
+ };
91
+ }
92
+
93
+ // Normal doc page
94
+ const toc = extractTableOfContents(doc.meta.content || doc.content);
95
+ const { previous, next } = getAdjacentDocs(slug, allDocs);
96
+ const showCategoryIndex = isCategory && !!doc;
97
+ const matchingDoc = allDocs.find((d) => d.slug === slug);
98
+ const currentPageTabGroup = doc.meta?.tab_group || matchingDoc?.categoryTabGroup;
99
+
100
+ return {
101
+ version,
102
+ slug,
103
+ allDocs,
104
+ versions,
105
+ config,
106
+ isCategory: showCategoryIndex,
107
+ isNotFound: false,
108
+ doc,
109
+ categoryTitle: null,
110
+ categoryDescription: null,
111
+ categoryTabGroup: currentPageTabGroup,
112
+ toc,
113
+ previous: previous ? { title: previous.meta.title, slug: previous.slug } : null,
114
+ next: next ? { title: next.meta.title, slug: next.slug } : null,
115
+ title,
116
+ description,
117
+ ogUrl,
118
+ };
119
+ };
@@ -0,0 +1,129 @@
1
+ <script lang="ts">
2
+ import {
3
+ TableOfContents,
4
+ Header,
5
+ DocLayout,
6
+ CategoryIndex,
7
+ HotReloadIndicator,
8
+ DevModeBadge,
9
+ MdxHotReload,
10
+ MdxContent,
11
+ NotFoundContent,
12
+ SearchHighlight,
13
+ MobileDocLayout,
14
+ mdxComponents,
15
+ } from 'specra/components';
16
+ import type { PageData } from './$types';
17
+
18
+ let { data }: { data: PageData } = $props();
19
+
20
+ let allDocsCompat: any[] = $derived(data.allDocs);
21
+ let previousDoc = $derived(data.previous ?? undefined);
22
+ let nextDoc = $derived(data.next ?? undefined);
23
+ let categoryTitle = $derived(data.categoryTitle ?? undefined);
24
+ let categoryDescription = $derived(data.categoryDescription ?? undefined);
25
+ </script>
26
+
27
+ <svelte:head>
28
+ <title>{data.title}</title>
29
+ <meta name="description" content={data.description} />
30
+ <meta property="og:title" content={data.title} />
31
+ <meta property="og:description" content={data.description} />
32
+ <meta property="og:url" content={data.ogUrl} />
33
+ <meta property="og:type" content="article" />
34
+ <meta name="twitter:card" content="summary_large_image" />
35
+ <meta name="twitter:title" content={data.title} />
36
+ <meta name="twitter:description" content={data.description} />
37
+ </svelte:head>
38
+
39
+ {#if !data.doc && data.isCategory}
40
+ <MobileDocLayout
41
+ docs={allDocsCompat}
42
+ version={data.version}
43
+ config={data.config}
44
+ activeTabGroup={data.categoryTabGroup}
45
+ >
46
+ {#snippet header()}
47
+ <Header currentVersion={data.version} versions={data.versions} config={data.config} />
48
+ {/snippet}
49
+ <CategoryIndex
50
+ categoryPath={data.slug}
51
+ version={data.version}
52
+ allDocs={allDocsCompat}
53
+ title={categoryTitle}
54
+ description={categoryDescription}
55
+ config={data.config}
56
+ />
57
+ </MobileDocLayout>
58
+ <MdxHotReload />
59
+ <HotReloadIndicator />
60
+ <DevModeBadge />
61
+ {:else if data.isNotFound}
62
+ <MobileDocLayout
63
+ docs={allDocsCompat}
64
+ version={data.version}
65
+ config={data.config}
66
+ >
67
+ {#snippet header()}
68
+ <Header currentVersion={data.version} versions={data.versions} config={data.config} />
69
+ {/snippet}
70
+ <NotFoundContent version={data.version} />
71
+ </MobileDocLayout>
72
+ <MdxHotReload />
73
+ <HotReloadIndicator />
74
+ <DevModeBadge />
75
+ {:else if data.doc}
76
+ <MobileDocLayout
77
+ docs={allDocsCompat}
78
+ version={data.version}
79
+ config={data.config}
80
+ activeTabGroup={data.categoryTabGroup}
81
+ >
82
+ {#snippet header()}
83
+ <Header currentVersion={data.version} versions={data.versions} config={data.config} />
84
+ {/snippet}
85
+ {#snippet toc()}
86
+ {#if !data.isCategory}
87
+ <TableOfContents items={data.toc} config={data.config} />
88
+ {/if}
89
+ {/snippet}
90
+
91
+ {#if data.isCategory}
92
+ {#snippet categoryContent()}
93
+ {#if data.doc?.contentNodes}
94
+ <MdxContent nodes={data.doc.contentNodes} components={mdxComponents} />
95
+ {:else if data.doc?.content}
96
+ {@html data.doc.content}
97
+ {/if}
98
+ {/snippet}
99
+ <CategoryIndex
100
+ categoryPath={data.slug}
101
+ version={data.version}
102
+ allDocs={allDocsCompat}
103
+ title={data.doc.meta.title}
104
+ description={data.doc.meta.description}
105
+ content={categoryContent}
106
+ config={data.config}
107
+ />
108
+ {:else}
109
+ <SearchHighlight />
110
+ <DocLayout
111
+ meta={data.doc.meta}
112
+ previousDoc={previousDoc}
113
+ nextDoc={nextDoc}
114
+ version={data.version}
115
+ slug={data.slug}
116
+ config={data.config}
117
+ >
118
+ {#if data.doc.contentNodes}
119
+ <MdxContent nodes={data.doc.contentNodes} components={mdxComponents} />
120
+ {:else}
121
+ {@html data.doc.content}
122
+ {/if}
123
+ </DocLayout>
124
+ {/if}
125
+ </MobileDocLayout>
126
+ <MdxHotReload />
127
+ <HotReloadIndicator />
128
+ <DevModeBadge />
129
+ {/if}
@@ -0,0 +1,8 @@
1
+ import { specraConfig } from 'specra/svelte-config';
2
+ import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3
+
4
+ const config = specraConfig({
5
+ vitePreprocess: { vitePreprocess }
6
+ });
7
+
8
+ export default config;
@@ -0,0 +1,12 @@
1
+ {
2
+ "extends": "./.svelte-kit/tsconfig.json",
3
+ "compilerOptions": {
4
+ "allowJs": true,
5
+ "checkJs": true,
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "resolveJsonModule": true,
9
+ "skipLibCheck": true,
10
+ "strict": true
11
+ }
12
+ }
@@ -0,0 +1,6 @@
1
+ import { sveltekit } from '@sveltejs/kit/vite';
2
+ import { defineConfig } from 'vite';
3
+
4
+ export default defineConfig({
5
+ plugins: [sveltekit()]
6
+ });