specra 0.1.0 → 0.1.1
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.
- package/dist/app/docs-page.js +164 -148
- package/dist/app/docs-page.js.map +1 -1
- package/dist/app/docs-page.mjs +3 -3
- package/dist/app/layout.js +84 -5
- package/dist/app/layout.js.map +1 -1
- package/dist/app/layout.mjs +3 -3
- package/dist/{chunk-NXRIAL7T.mjs → chunk-4QHOMV5A.mjs} +8 -5
- package/dist/chunk-4QHOMV5A.mjs.map +1 -0
- package/dist/{chunk-IZFGEAD6.mjs → chunk-5AYOV2KD.mjs} +5 -4
- package/dist/chunk-5AYOV2KD.mjs.map +1 -0
- package/dist/chunk-I3ELVEK2.mjs +56 -0
- package/dist/chunk-I3ELVEK2.mjs.map +1 -0
- package/dist/{chunk-INL2EC72.mjs → chunk-RLMSINLY.mjs} +2 -5
- package/dist/{chunk-INL2EC72.mjs.map → chunk-RLMSINLY.mjs.map} +1 -1
- package/dist/components/index.d.mts +39 -3
- package/dist/components/index.d.ts +39 -3
- package/dist/components/index.js +100 -62
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +83 -48
- package/dist/components/index.mjs.map +1 -1
- package/dist/index.d.mts +39 -3
- package/dist/index.d.ts +39 -3
- package/dist/index.js +129 -94
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -4
- package/dist/index.mjs.map +1 -1
- package/dist/lib/index.d.mts +7 -0
- package/dist/lib/index.d.ts +7 -0
- package/dist/lib/index.js +1 -4
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +1 -1
- package/package.json +2 -2
- package/src/app/layout.tsx +6 -3
- package/src/components/docs/header.tsx +7 -3
- package/src/components/docs/index.ts +3 -0
- package/src/lib/config.context.tsx +65 -0
- package/src/lib/config.server.ts +9 -5
- package/src/lib/index.ts +1 -0
- package/dist/chunk-IZFGEAD6.mjs.map +0 -1
- package/dist/chunk-MZJHJ6BV.mjs +0 -21
- package/dist/chunk-MZJHJ6BV.mjs.map +0 -1
- package/dist/chunk-NXRIAL7T.mjs.map +0 -1
package/dist/app/docs-page.mjs
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
DocPage,
|
|
3
3
|
generateMetadata,
|
|
4
4
|
generateStaticParams
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-4QHOMV5A.mjs";
|
|
6
|
+
import "../chunk-I3ELVEK2.mjs";
|
|
7
7
|
import "../chunk-DR4EPLMT.mjs";
|
|
8
|
-
import "../chunk-
|
|
8
|
+
import "../chunk-RLMSINLY.mjs";
|
|
9
9
|
export {
|
|
10
10
|
DocPage as default,
|
|
11
11
|
generateMetadata,
|
package/dist/app/layout.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/app/layout.tsx
|
|
@@ -27,11 +37,72 @@ __export(layout_exports, {
|
|
|
27
37
|
module.exports = __toCommonJS(layout_exports);
|
|
28
38
|
var import_google = require("next/font/google");
|
|
29
39
|
|
|
40
|
+
// src/lib/config.types.ts
|
|
41
|
+
var defaultConfig = {
|
|
42
|
+
site: {
|
|
43
|
+
title: "Documentation",
|
|
44
|
+
description: "Project documentation",
|
|
45
|
+
baseUrl: "/",
|
|
46
|
+
language: "en"
|
|
47
|
+
},
|
|
48
|
+
theme: {
|
|
49
|
+
defaultMode: "system",
|
|
50
|
+
respectPrefersColorScheme: true
|
|
51
|
+
},
|
|
52
|
+
navigation: {
|
|
53
|
+
showSidebar: true,
|
|
54
|
+
collapsibleSidebar: true,
|
|
55
|
+
showBreadcrumbs: true,
|
|
56
|
+
showTableOfContents: true,
|
|
57
|
+
tocPosition: "right",
|
|
58
|
+
tocMaxDepth: 3
|
|
59
|
+
},
|
|
60
|
+
search: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
provider: "local",
|
|
63
|
+
placeholder: "Search documentation..."
|
|
64
|
+
},
|
|
65
|
+
features: {
|
|
66
|
+
showLastUpdated: true,
|
|
67
|
+
showReadingTime: true,
|
|
68
|
+
showAuthors: false,
|
|
69
|
+
showTags: true,
|
|
70
|
+
versioning: true,
|
|
71
|
+
i18n: false
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
30
75
|
// src/lib/config.server.ts
|
|
76
|
+
function deepMerge(target, source) {
|
|
77
|
+
const result = { ...target };
|
|
78
|
+
for (const key in source) {
|
|
79
|
+
const sourceValue = source[key];
|
|
80
|
+
const targetValue = result[key];
|
|
81
|
+
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue)) {
|
|
82
|
+
result[key] = deepMerge(
|
|
83
|
+
targetValue && typeof targetValue === "object" ? targetValue : {},
|
|
84
|
+
sourceValue
|
|
85
|
+
);
|
|
86
|
+
} else if (sourceValue !== void 0) {
|
|
87
|
+
result[key] = sourceValue;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
function loadConfig(userConfig) {
|
|
93
|
+
try {
|
|
94
|
+
const config = deepMerge(defaultConfig, userConfig);
|
|
95
|
+
return config;
|
|
96
|
+
} catch (error) {
|
|
97
|
+
console.error(`\u274C Error loading configuration:`, error);
|
|
98
|
+
console.warn("Using default configuration.");
|
|
99
|
+
return defaultConfig;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
31
102
|
var configInstance = null;
|
|
32
103
|
function getConfig() {
|
|
33
104
|
if (!configInstance) {
|
|
34
|
-
|
|
105
|
+
configInstance = loadConfig({});
|
|
35
106
|
}
|
|
36
107
|
return configInstance;
|
|
37
108
|
}
|
|
@@ -50,17 +121,25 @@ function getAssetPath(path) {
|
|
|
50
121
|
return normalizedPath;
|
|
51
122
|
}
|
|
52
123
|
|
|
124
|
+
// src/lib/config.context.tsx
|
|
125
|
+
var React = __toESM(require("react"));
|
|
126
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
127
|
+
var ConfigContext = React.createContext(defaultConfig);
|
|
128
|
+
function ConfigProvider({ config, children }) {
|
|
129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfigContext.Provider, { value: config, children });
|
|
130
|
+
}
|
|
131
|
+
|
|
53
132
|
// src/components/docs/tab-context.tsx
|
|
54
133
|
var import_react = require("react");
|
|
55
|
-
var
|
|
134
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
56
135
|
var TabContext = (0, import_react.createContext)(void 0);
|
|
57
136
|
function TabProvider({ children, defaultTab }) {
|
|
58
137
|
const [activeTabGroup, setActiveTabGroup] = (0, import_react.useState)(defaultTab);
|
|
59
|
-
return /* @__PURE__ */ (0,
|
|
138
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TabContext.Provider, { value: { activeTabGroup, setActiveTabGroup }, children });
|
|
60
139
|
}
|
|
61
140
|
|
|
62
141
|
// src/app/layout.tsx
|
|
63
|
-
var
|
|
142
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
64
143
|
var geist = (0, import_google.Geist)({ subsets: ["latin"] });
|
|
65
144
|
var geistMono = (0, import_google.Geist_Mono)({ subsets: ["latin"] });
|
|
66
145
|
function generateMetadata() {
|
|
@@ -102,7 +181,7 @@ function RootLayout({
|
|
|
102
181
|
}) {
|
|
103
182
|
const config = getConfig();
|
|
104
183
|
const defaultTab = config.navigation?.tabGroups?.[0]?.id || "";
|
|
105
|
-
return /* @__PURE__ */ (0,
|
|
184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("html", { lang: config.site.language || "en", suppressHydrationWarning: true, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("body", { className: `${geist.className} font-sans antialiased`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TabProvider, { defaultTab, children }) }) }) });
|
|
106
185
|
}
|
|
107
186
|
// Annotate the CommonJS export names for ESM import in node:
|
|
108
187
|
0 && (module.exports = {
|
package/dist/app/layout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/app/layout.tsx","../../src/lib/config.server.ts","../../src/lib/utils.ts","../../src/components/docs/tab-context.tsx"],"sourcesContent":["import type React from \"react\"\nimport type { Metadata } from \"next\"\nimport { Geist, Geist_Mono } from \"next/font/google\"\nimport { getConfig } from \"../lib/config\"\nimport { getAssetPath } from \"../lib/utils\"\nimport { TabProvider } from \"../components/docs/tab-context\"\nimport \"../styles/globals.css\"\n\nconst geist = Geist({ subsets: [\"latin\"] })\nconst geistMono = Geist_Mono({ subsets: [\"latin\"] })\n\n/**\n * Generate metadata for the root layout\n * This can be imported and used by the user's app/layout.tsx\n */\nexport function generateMetadata(): Metadata {\n const config = getConfig()\n\n return {\n title: {\n default: config.site.title,\n template: `%s | ${config.site.title}`,\n },\n description: config.site.description || \"Modern documentation platform\",\n generator: \"Specra Documentation\",\n metadataBase: config.site.url ? new URL(config.site.url) : undefined,\n icons: {\n icon: getAssetPath(config.site.favicon ?? \"\") ? [\n {\n url: getAssetPath(config.site.favicon ?? \"\"),\n },\n ] : [],\n apple: getAssetPath(\"/apple-icon.png\"),\n },\n openGraph: {\n title: config.site.title,\n description: config.site.description,\n url: config.site.url,\n siteName: config.site.title,\n locale: config.site.language || \"en\",\n type: \"website\",\n },\n twitter: {\n card: \"summary_large_image\",\n title: config.site.title,\n description: config.site.description,\n },\n }\n}\n\nexport const metadata: Metadata = generateMetadata()\n\n/**\n * Root layout component for Specra documentation sites\n * This provides the HTML structure and global providers\n */\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n const config = getConfig()\n const defaultTab = config.navigation?.tabGroups?.[0]?.id || \"\"\n\n return (\n <html lang={config.site.language || \"en\"} suppressHydrationWarning>\n <body className={`${geist.className} font-sans antialiased`}>\n <TabProvider defaultTab={defaultTab}>\n {children}\n </TabProvider>\n </body>\n </html>\n )\n}","import specraConfigJson from \"../specra.config.json\"\nimport { SpecraConfig, defaultConfig } from \"./config.types\"\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {\n const result = { ...target }\n\n for (const key in source) {\n const sourceValue = source[key]\n const targetValue = result[key]\n\n if (sourceValue && typeof sourceValue === \"object\" && !Array.isArray(sourceValue)) {\n result[key] = deepMerge(\n targetValue && typeof targetValue === \"object\" ? targetValue : {},\n sourceValue,\n ) as T[Extract<keyof T, string>]\n } else if (sourceValue !== undefined) {\n result[key] = sourceValue as T[Extract<keyof T, string>]\n }\n }\n\n return result\n}\n\n/**\n * Load and parse the Specra configuration file\n * Falls back to default configuration if file doesn't exist or is invalid\n */\nexport function loadConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {\n try {\n // const userConfig = specraConfigJson as unknown as Partial<SpecraConfig>\n\n // Merge user config with defaults \n const config = deepMerge(defaultConfig, userConfig)\n\n return config\n } catch (error) {\n console.error(`❌ Error loading configuration:`, error)\n console.warn(\"Using default configuration.\")\n return defaultConfig\n }\n}\n\n/**\n * Get a specific configuration value by path (SERVER ONLY)\n * Example: getConfigValue('site.title') or getConfigValue('theme.defaultMode')\n */\nexport function getConfigValue<T = any>(path: string, config?: SpecraConfig): T | undefined {\n const cfg = config || loadConfig({})\n const keys = path.split(\".\")\n let value: any = cfg\n\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = value[key]\n } else {\n return undefined\n }\n }\n\n return value as T\n}\n\n/**\n * Replace environment variables in a string (SERVER ONLY)\n * Supports ${ENV_VAR} and {{ENV_VAR}} syntax\n */\nexport function replaceEnvVariables(text: string, config?: SpecraConfig): string {\n const cfg = config || loadConfig({})\n const envVars = cfg.env || {}\n\n let result = text\n\n // Replace ${VAR} syntax\n result = result.replace(/\\$\\{([^}]+)\\}/g, (match, varName) => {\n return envVars[varName] || match\n })\n\n // Replace {{VAR}} syntax\n result = result.replace(/\\{\\{([^}]+)\\}\\}/g, (match, varName) => {\n return envVars[varName] || match\n })\n\n return result\n}\n\n/**\n * Process content and replace all environment variables (SERVER ONLY)\n */\nexport function processContentWithEnv(content: string, config?: SpecraConfig): string {\n return replaceEnvVariables(content, config)\n}\n\n/**\n * Validate configuration (basic validation) (SERVER ONLY)\n */\nexport function validateConfig(config: SpecraConfig): { valid: boolean; errors: string[] } {\n const errors: string[] = []\n\n // Required fields\n if (!config.site?.title) {\n errors.push(\"site.title is required\")\n }\n\n // URL validation\n if (config.site?.url) {\n try {\n new URL(config.site.url)\n } catch {\n errors.push(\"site.url must be a valid URL\")\n }\n }\n\n // Social links validation\n if (config.social) {\n const socialKeys = [\"github\", \"twitter\", \"discord\", \"linkedin\", \"youtube\"] as const\n for (const key of socialKeys) {\n const url = config.social[key]\n if (url) {\n try {\n new URL(url)\n } catch {\n errors.push(`social.${key} must be a valid URL`)\n }\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}\n\n// Singleton instance\nlet configInstance: SpecraConfig | null = null\n\nexport function initConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {\n if (configInstance) {\n throw new Error(\"Specra config has already been initialized\")\n }\n\n configInstance = loadConfig(userConfig)\n return configInstance\n}\n\n/**\n * Get the configuration instance (cached) (SERVER ONLY)\n */\nexport function getConfig(): SpecraConfig {\n if (!configInstance) {\n throw new Error(\"Specra config has not been initialized\")\n }\n return configInstance\n}\n\n/**\n * Reload the configuration (useful for development) (SERVER ONLY)\n */\nexport function reloadConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {\n configInstance = loadConfig(userConfig)\n return configInstance\n}\n\n/**\n * Export the loaded config as default (SERVER ONLY)\n */\n// export default getConfig()\n","import { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\n\n/**\n * Get the correct asset path based on deployment configuration\n * Handles different deployment scenarios:\n * - Vercel/Node.js hosting (standalone build): No basePath needed\n * - GitHub Pages without custom domain: Uses basePath from config\n * - Static hosting with custom domain: No basePath needed\n *\n * @param path - The asset path (can start with or without '/')\n * @returns The properly formatted asset path\n */\nexport function getAssetPath(path: string): string {\n // Get basePath from Next.js config (set during build for static exports)\n const basePath = process.env.NEXT_PUBLIC_BASE_PATH || process.env.__NEXT_ROUTER_BASEPATH || ''\n\n // Normalize the input path: ensure it starts with '/'\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n\n // If we have a basePath (GitHub Pages without custom domain), prepend it\n if (basePath) {\n // Normalize basePath: remove trailing slash, ensure leading slash\n const normalizedBase = basePath.startsWith('/') ? basePath : `/${basePath}`\n const cleanBase = normalizedBase.replace(/\\/$/, '')\n return `${cleanBase}${normalizedPath}`\n }\n\n // Default: return the normalized path (works for Vercel, custom domains, and dev)\n return normalizedPath\n}","\"use client\"\n\nimport { createContext, useContext, useState, ReactNode } from \"react\"\n\ninterface TabContextType {\n activeTabGroup: string\n setActiveTabGroup: (tabId: string) => void\n}\n\nconst TabContext = createContext<TabContextType | undefined>(undefined)\n\nexport function TabProvider({ children, defaultTab }: { children: ReactNode; defaultTab: string }) {\n const [activeTabGroup, setActiveTabGroup] = useState(defaultTab)\n\n return (\n <TabContext.Provider value={{ activeTabGroup, setActiveTabGroup }}>\n {children}\n </TabContext.Provider>\n )\n}\n\nexport function useTabContext() {\n const context = useContext(TabContext)\n if (!context) {\n throw new Error(\"useTabContext must be used within TabProvider\")\n }\n return context\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAAkC;;;ACuIlC,IAAI,iBAAsC;AAcnC,SAAS,YAA0B;AACxC,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AACA,SAAO;AACT;;;AC5JA,kBAAsC;AACtC,4BAAwB;AAiBjB,SAAS,aAAa,MAAsB;AAEjD,QAAM,WAAW,QAAQ,IAAI,yBAAyB,QAAQ,IAAI,0BAA0B;AAG5F,QAAM,iBAAiB,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAG7D,MAAI,UAAU;AAEZ,UAAM,iBAAiB,SAAS,WAAW,GAAG,IAAI,WAAW,IAAI,QAAQ;AACzE,UAAM,YAAY,eAAe,QAAQ,OAAO,EAAE;AAClD,WAAO,GAAG,SAAS,GAAG,cAAc;AAAA,EACtC;AAGA,SAAO;AACT;;;ACjCA,mBAA+D;AAa3D;AANJ,IAAM,iBAAa,4BAA0C,MAAS;AAE/D,SAAS,YAAY,EAAE,UAAU,WAAW,GAAgD;AACjG,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAS,UAAU;AAE/D,SACE,4CAAC,WAAW,UAAX,EAAoB,OAAO,EAAE,gBAAgB,kBAAkB,GAC7D,UACH;AAEJ;;;AHgDQ,IAAAA,sBAAA;AA3DR,IAAM,YAAQ,qBAAM,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;AAC1C,IAAM,gBAAY,0BAAW,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;AAM5C,SAAS,mBAA6B;AAC3C,QAAM,SAAS,UAAU;AAEzB,SAAO;AAAA,IACL,OAAO;AAAA,MACL,SAAS,OAAO,KAAK;AAAA,MACrB,UAAU,QAAQ,OAAO,KAAK,KAAK;AAAA,IACrC;AAAA,IACA,aAAa,OAAO,KAAK,eAAe;AAAA,IACxC,WAAW;AAAA,IACX,cAAc,OAAO,KAAK,MAAM,IAAI,IAAI,OAAO,KAAK,GAAG,IAAI;AAAA,IAC3D,OAAO;AAAA,MACL,MAAM,aAAa,OAAO,KAAK,WAAW,EAAE,IAAI;AAAA,QAC9C;AAAA,UACE,KAAK,aAAa,OAAO,KAAK,WAAW,EAAE;AAAA,QAC7C;AAAA,MACF,IAAI,CAAC;AAAA,MACL,OAAO,aAAa,iBAAiB;AAAA,IACvC;AAAA,IACA,WAAW;AAAA,MACT,OAAO,OAAO,KAAK;AAAA,MACnB,aAAa,OAAO,KAAK;AAAA,MACzB,KAAK,OAAO,KAAK;AAAA,MACjB,UAAU,OAAO,KAAK;AAAA,MACtB,QAAQ,OAAO,KAAK,YAAY;AAAA,MAChC,MAAM;AAAA,IACR;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO,OAAO,KAAK;AAAA,MACnB,aAAa,OAAO,KAAK;AAAA,IAC3B;AAAA,EACF;AACF;AAEO,IAAM,WAAqB,iBAAiB;AAMpC,SAAR,WAA4B;AAAA,EACjC;AACF,GAEI;AACF,QAAM,SAAS,UAAU;AACzB,QAAM,aAAa,OAAO,YAAY,YAAY,CAAC,GAAG,MAAM;AAE5D,SACE,6CAAC,UAAK,MAAM,OAAO,KAAK,YAAY,MAAM,0BAAwB,MAChE,uDAAC,UAAK,WAAW,GAAG,MAAM,SAAS,0BACjC,uDAAC,eAAY,YACV,UACH,GACF,GACF;AAEJ;","names":["import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../../src/app/layout.tsx","../../src/lib/config.types.ts","../../src/lib/config.server.ts","../../src/lib/utils.ts","../../src/lib/config.context.tsx","../../src/components/docs/tab-context.tsx"],"sourcesContent":["import type React from \"react\"\nimport type { Metadata } from \"next\"\nimport { Geist, Geist_Mono } from \"next/font/google\"\nimport { getConfig } from \"../lib/config\"\nimport { getAssetPath } from \"../lib/utils\"\nimport { ConfigProvider } from \"../lib/config.context\"\nimport { TabProvider } from \"../components/docs/tab-context\"\nimport \"../styles/globals.css\"\n\nconst geist = Geist({ subsets: [\"latin\"] })\nconst geistMono = Geist_Mono({ subsets: [\"latin\"] })\n\n/**\n * Generate metadata for the root layout\n * This can be imported and used by the user's app/layout.tsx\n */\nexport function generateMetadata(): Metadata {\n const config = getConfig()\n\n return {\n title: {\n default: config.site.title,\n template: `%s | ${config.site.title}`,\n },\n description: config.site.description || \"Modern documentation platform\",\n generator: \"Specra Documentation\",\n metadataBase: config.site.url ? new URL(config.site.url) : undefined,\n icons: {\n icon: getAssetPath(config.site.favicon ?? \"\") ? [\n {\n url: getAssetPath(config.site.favicon ?? \"\"),\n },\n ] : [],\n apple: getAssetPath(\"/apple-icon.png\"),\n },\n openGraph: {\n title: config.site.title,\n description: config.site.description,\n url: config.site.url,\n siteName: config.site.title,\n locale: config.site.language || \"en\",\n type: \"website\",\n },\n twitter: {\n card: \"summary_large_image\",\n title: config.site.title,\n description: config.site.description,\n },\n }\n}\n\nexport const metadata: Metadata = generateMetadata()\n\n/**\n * Root layout component for Specra documentation sites\n * This provides the HTML structure and global providers\n */\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode\n}>) {\n const config = getConfig()\n const defaultTab = config.navigation?.tabGroups?.[0]?.id || \"\"\n\n return (\n <html lang={config.site.language || \"en\"} suppressHydrationWarning>\n <body className={`${geist.className} font-sans antialiased`}>\n <ConfigProvider config={config}>\n <TabProvider defaultTab={defaultTab}>\n {children}\n </TabProvider>\n </ConfigProvider>\n </body>\n </html>\n )\n}","/**\n * Configuration schema for Specra documentation system\n */\n\n/**\n * Site metadata and branding\n */\nexport interface SiteConfig {\n /** The title of the documentation site */\n title: string\n /** Short description of the documentation */\n description?: string\n /** URL where the documentation is hosted */\n url?: string\n /** Base URL path for the documentation (e.g., '/docs') */\n baseUrl?: string\n /** Path to the site logo */\n logo?: string\n /** Path to the favicon */\n favicon?: string\n /** Default language for the documentation */\n language?: string\n /** Organization or author name */\n organizationName?: string\n /** Project name */\n projectName?: string\n /** Active/default version for the documentation */\n activeVersion?: string\n}\n\n/**\n * Theme and appearance settings\n */\nexport interface ThemeConfig {\n /** Primary color for the theme */\n primaryColor?: string\n /** Default theme mode */\n defaultMode?: \"light\" | \"dark\" | \"system\"\n /** Whether to respect system preferences */\n respectPrefersColorScheme?: boolean\n /** Custom CSS file path */\n customCss?: string\n}\n\n/**\n * Tab group for organizing documentation\n */\nexport interface TabGroup {\n /** Unique identifier for the tab group */\n id: string\n /** Display label for the tab */\n label: string\n /** Optional icon name (lucide-react icon) */\n icon?: string\n}\n\n/**\n * Navigation and sidebar configuration\n */\nexport interface NavigationConfig {\n /** Whether to show the sidebar by default */\n showSidebar?: boolean\n /** Whether the sidebar is collapsible */\n collapsibleSidebar?: boolean\n /** Whether to show breadcrumbs */\n showBreadcrumbs?: boolean\n /** Whether to show table of contents */\n showTableOfContents?: boolean\n /** Position of table of contents */\n tocPosition?: \"left\" | \"right\"\n /** Maximum depth for table of contents */\n tocMaxDepth?: number\n /** Tab groups for organizing documentation sections */\n tabGroups?: TabGroup[]\n}\n\n/**\n * Social and external links\n */\nexport interface SocialLinks {\n /** GitHub repository URL */\n github?: string\n /** Twitter/X handle or URL */\n twitter?: string\n /** Discord invite URL */\n discord?: string\n /** LinkedIn profile or company page */\n linkedin?: string\n /** YouTube channel URL */\n youtube?: string\n /** Custom social links */\n custom?: Array<{\n label: string\n url: string\n icon?: string\n }>\n}\n\n/**\n * Search configuration\n */\nexport interface SearchConfig {\n /** Enable/disable search functionality */\n enabled?: boolean\n /** Placeholder text for search input */\n placeholder?: string\n /** Search provider type */\n provider?: \"meilisearch\" | \"algolia\" | \"local\"\n /** Meilisearch configuration */\n meilisearch?: {\n /** Meilisearch server URL */\n host: string\n /** API key for Meilisearch */\n apiKey?: string\n /** Index name */\n indexName: string\n }\n}\n\n/**\n * Analytics configuration\n */\nexport interface AnalyticsConfig {\n /** Google Analytics tracking ID */\n googleAnalytics?: string\n /** Google Tag Manager ID */\n googleTagManager?: string\n /** Plausible Analytics domain */\n plausible?: string\n /** Custom analytics scripts */\n custom?: Array<{\n src: string\n async?: boolean\n defer?: boolean\n }>\n}\n\n/**\n * Footer configuration\n */\nexport interface FooterConfig {\n /** Copyright text */\n copyright?: string\n /** Footer links organized by columns */\n links?: Array<{\n title: string\n items: Array<{\n label: string\n href: string\n }>\n }>\n /** Custom footer content */\n customContent?: string\n}\n\n/**\n * Documentation features\n */\nexport interface FeaturesConfig {\n /** Enable/disable edit this page links */\n editUrl?: string | false\n /** Show last updated timestamp */\n showLastUpdated?: boolean\n /** Show reading time estimate */\n showReadingTime?: boolean\n /** Show author information */\n showAuthors?: boolean\n /** Show tags */\n showTags?: boolean\n /** Enable version dropdown */\n versioning?: boolean\n /** Enable i18n (internationalization) */\n i18n?: boolean\n}\n\n/**\n * Site-wide banner configuration\n */\nexport interface BannerConfig {\n /** Whether the banner is enabled */\n enabled?: boolean\n /** Banner message */\n message?: string\n /** Banner type */\n type?: \"info\" | \"warning\" | \"success\" | \"error\"\n /** Whether the banner can be dismissed */\n dismissible?: boolean\n}\n\n/**\n * Environment variables that can be used in documentation\n * These will be replaced at build time or runtime\n */\nexport interface EnvironmentVariables {\n /** API base URL */\n API_BASE_URL?: string\n /** API version */\n API_VERSION?: string\n /** CDN URL */\n CDN_URL?: string\n /** Custom environment variables */\n [key: string]: string | undefined\n}\n\n/**\n * Deployment configuration for different hosting scenarios\n */\nexport interface DeploymentConfig {\n /**\n * Deployment target\n * - 'vercel': For Vercel or similar Node.js hosting (uses 'standalone' output)\n * - 'github-pages': For GitHub Pages static hosting (uses 'export' output)\n * - 'static': For any static hosting like Netlify, Cloudflare Pages, etc.\n * - 'custom-domain-static': For static hosting with custom domain (no basePath needed)\n */\n target?: \"vercel\" | \"github-pages\" | \"static\" | \"custom-domain-static\"\n\n /**\n * Base path for assets when deploying to GitHub Pages without custom domain\n * This should be your repository name (e.g., 'my-repo')\n * Only used when target is 'github-pages' and no custom domain is configured\n */\n basePath?: string\n\n /**\n * Whether a custom domain is configured\n * When true, basePath will be ignored even for GitHub Pages\n */\n customDomain?: boolean\n}\n\n/**\n * Main configuration interface\n */\nexport interface SpecraConfig {\n /** Site metadata and branding */\n site: SiteConfig\n /** Theme and appearance settings */\n theme?: ThemeConfig\n /** Navigation and sidebar configuration */\n navigation?: NavigationConfig\n /** Social and external links */\n social?: SocialLinks\n /** Search configuration */\n search?: SearchConfig\n /** Analytics configuration */\n analytics?: AnalyticsConfig\n /** Footer configuration */\n footer?: FooterConfig\n /** Site-wide banner */\n banner?: BannerConfig\n /** Documentation features */\n features?: FeaturesConfig\n /** Environment variables for use in docs */\n env?: EnvironmentVariables\n /** Deployment configuration */\n deployment?: DeploymentConfig\n}\n\n/**\n * Default configuration values\n */\nexport const defaultConfig: SpecraConfig = {\n site: {\n title: \"Documentation\",\n description: \"Project documentation\",\n baseUrl: \"/\",\n language: \"en\",\n },\n theme: {\n defaultMode: \"system\",\n respectPrefersColorScheme: true,\n },\n navigation: {\n showSidebar: true,\n collapsibleSidebar: true,\n showBreadcrumbs: true,\n showTableOfContents: true,\n tocPosition: \"right\",\n tocMaxDepth: 3,\n },\n search: {\n enabled: true,\n provider: \"local\",\n placeholder: \"Search documentation...\",\n },\n features: {\n showLastUpdated: true,\n showReadingTime: true,\n showAuthors: false,\n showTags: true,\n versioning: true,\n i18n: false,\n },\n}\n","import specraConfigJson from \"../specra.config.json\"\nimport { SpecraConfig, defaultConfig } from \"./config.types\"\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {\n const result = { ...target }\n\n for (const key in source) {\n const sourceValue = source[key]\n const targetValue = result[key]\n\n if (sourceValue && typeof sourceValue === \"object\" && !Array.isArray(sourceValue)) {\n result[key] = deepMerge(\n targetValue && typeof targetValue === \"object\" ? targetValue : {},\n sourceValue,\n ) as T[Extract<keyof T, string>]\n } else if (sourceValue !== undefined) {\n result[key] = sourceValue as T[Extract<keyof T, string>]\n }\n }\n\n return result\n}\n\n/**\n * Load and parse the Specra configuration file\n * Falls back to default configuration if file doesn't exist or is invalid\n */\nexport function loadConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {\n try {\n // const userConfig = specraConfigJson as unknown as Partial<SpecraConfig>\n\n // Merge user config with defaults \n const config = deepMerge(defaultConfig, userConfig)\n\n return config\n } catch (error) {\n console.error(`❌ Error loading configuration:`, error)\n console.warn(\"Using default configuration.\")\n return defaultConfig\n }\n}\n\n/**\n * Get a specific configuration value by path (SERVER ONLY)\n * Example: getConfigValue('site.title') or getConfigValue('theme.defaultMode')\n */\nexport function getConfigValue<T = any>(path: string, config?: SpecraConfig): T | undefined {\n const cfg = config || loadConfig({})\n const keys = path.split(\".\")\n let value: any = cfg\n\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = value[key]\n } else {\n return undefined\n }\n }\n\n return value as T\n}\n\n/**\n * Replace environment variables in a string (SERVER ONLY)\n * Supports ${ENV_VAR} and {{ENV_VAR}} syntax\n */\nexport function replaceEnvVariables(text: string, config?: SpecraConfig): string {\n const cfg = config || loadConfig({})\n const envVars = cfg.env || {}\n\n let result = text\n\n // Replace ${VAR} syntax\n result = result.replace(/\\$\\{([^}]+)\\}/g, (match, varName) => {\n return envVars[varName] || match\n })\n\n // Replace {{VAR}} syntax\n result = result.replace(/\\{\\{([^}]+)\\}\\}/g, (match, varName) => {\n return envVars[varName] || match\n })\n\n return result\n}\n\n/**\n * Process content and replace all environment variables (SERVER ONLY)\n */\nexport function processContentWithEnv(content: string, config?: SpecraConfig): string {\n return replaceEnvVariables(content, config)\n}\n\n/**\n * Validate configuration (basic validation) (SERVER ONLY)\n */\nexport function validateConfig(config: SpecraConfig): { valid: boolean; errors: string[] } {\n const errors: string[] = []\n\n // Required fields\n if (!config.site?.title) {\n errors.push(\"site.title is required\")\n }\n\n // URL validation\n if (config.site?.url) {\n try {\n new URL(config.site.url)\n } catch {\n errors.push(\"site.url must be a valid URL\")\n }\n }\n\n // Social links validation\n if (config.social) {\n const socialKeys = [\"github\", \"twitter\", \"discord\", \"linkedin\", \"youtube\"] as const\n for (const key of socialKeys) {\n const url = config.social[key]\n if (url) {\n try {\n new URL(url)\n } catch {\n errors.push(`social.${key} must be a valid URL`)\n }\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n }\n}\n\n// Singleton instance\nlet configInstance: SpecraConfig | null = null\n\n/**\n * Initialize the Specra configuration\n * Can be called multiple times - subsequent calls will update the config\n * @param userConfig - Partial configuration to merge with defaults\n * @returns The initialized configuration\n */\nexport function initConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {\n configInstance = loadConfig(userConfig)\n return configInstance\n}\n\n/**\n * Get the configuration instance (cached) (SERVER ONLY)\n * If not initialized, returns default config\n */\nexport function getConfig(): SpecraConfig {\n if (!configInstance) {\n // Auto-initialize with defaults if not already initialized\n configInstance = loadConfig({})\n }\n return configInstance\n}\n\n/**\n * Reload the configuration (useful for development) (SERVER ONLY)\n */\nexport function reloadConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {\n configInstance = loadConfig(userConfig)\n return configInstance\n}\n\n/**\n * Export the loaded config as default (SERVER ONLY)\n */\n// export default getConfig()\n","import { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n\n\n/**\n * Get the correct asset path based on deployment configuration\n * Handles different deployment scenarios:\n * - Vercel/Node.js hosting (standalone build): No basePath needed\n * - GitHub Pages without custom domain: Uses basePath from config\n * - Static hosting with custom domain: No basePath needed\n *\n * @param path - The asset path (can start with or without '/')\n * @returns The properly formatted asset path\n */\nexport function getAssetPath(path: string): string {\n // Get basePath from Next.js config (set during build for static exports)\n const basePath = process.env.NEXT_PUBLIC_BASE_PATH || process.env.__NEXT_ROUTER_BASEPATH || ''\n\n // Normalize the input path: ensure it starts with '/'\n const normalizedPath = path.startsWith('/') ? path : `/${path}`\n\n // If we have a basePath (GitHub Pages without custom domain), prepend it\n if (basePath) {\n // Normalize basePath: remove trailing slash, ensure leading slash\n const normalizedBase = basePath.startsWith('/') ? basePath : `/${basePath}`\n const cleanBase = normalizedBase.replace(/\\/$/, '')\n return `${cleanBase}${normalizedPath}`\n }\n\n // Default: return the normalized path (works for Vercel, custom domains, and dev)\n return normalizedPath\n}","import * as React from \"react\"\nimport { SpecraConfig, defaultConfig } from \"./config.types\"\n\nconst ConfigContext = React.createContext<SpecraConfig>(defaultConfig)\n\nexport interface ConfigProviderProps {\n config: SpecraConfig\n children: React.ReactNode\n}\n\n/**\n * Provider component that makes Specra config available to all client components\n * Usage: Wrap your app with this provider in your root layout\n */\nexport function ConfigProvider({ config, children }: ConfigProviderProps) {\n return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>\n}\n\n/**\n * Hook to access Specra configuration in any client component\n * @returns The current Specra configuration\n * @example\n * ```tsx\n * function MyComponent() {\n * const config = useConfig()\n * return <div>{config.site.title}</div>\n * }\n * ```\n */\nexport function useConfig(): SpecraConfig {\n const config = React.useContext(ConfigContext)\n if (!config) {\n throw new Error(\"useConfig must be used within a ConfigProvider\")\n }\n return config\n}\n\n/**\n * Hook to access a specific configuration value by path\n * @param path - Dot-separated path to the config value (e.g., \"site.title\")\n * @returns The configuration value at the specified path\n * @example\n * ```tsx\n * function MyComponent() {\n * const title = useConfigValue<string>(\"site.title\")\n * const showSidebar = useConfigValue<boolean>(\"navigation.showSidebar\")\n * return <div>{title}</div>\n * }\n * ```\n */\nexport function useConfigValue<T = any>(path: string): T | undefined {\n const config = useConfig()\n const keys = path.split(\".\")\n let value: any = config\n\n for (const key of keys) {\n if (value && typeof value === \"object\" && key in value) {\n value = value[key]\n } else {\n return undefined\n }\n }\n\n return value as T\n}\n","\"use client\"\n\nimport { createContext, useContext, useState, ReactNode } from \"react\"\n\ninterface TabContextType {\n activeTabGroup: string\n setActiveTabGroup: (tabId: string) => void\n}\n\nconst TabContext = createContext<TabContextType | undefined>(undefined)\n\nexport function TabProvider({ children, defaultTab }: { children: ReactNode; defaultTab: string }) {\n const [activeTabGroup, setActiveTabGroup] = useState(defaultTab)\n\n return (\n <TabContext.Provider value={{ activeTabGroup, setActiveTabGroup }}>\n {children}\n </TabContext.Provider>\n )\n}\n\nexport function useTabContext() {\n const context = useContext(TabContext)\n if (!context) {\n throw new Error(\"useTabContext must be used within TabProvider\")\n }\n return context\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime"]}
|
package/dist/app/layout.mjs
CHANGED
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
RootLayout,
|
|
3
3
|
generateMetadata,
|
|
4
4
|
metadata
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-5AYOV2KD.mjs";
|
|
6
|
+
import "../chunk-I3ELVEK2.mjs";
|
|
7
|
+
import "../chunk-RLMSINLY.mjs";
|
|
8
8
|
export {
|
|
9
9
|
RootLayout as default,
|
|
10
10
|
generateMetadata,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
useConfig,
|
|
2
3
|
useTabContext
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-I3ELVEK2.mjs";
|
|
4
5
|
import {
|
|
5
6
|
extractTableOfContents,
|
|
6
7
|
getAdjacentDocs,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
getAssetPath,
|
|
18
19
|
getConfig,
|
|
19
20
|
processContentWithEnv
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-RLMSINLY.mjs";
|
|
21
22
|
|
|
22
23
|
// src/components/docs/doc-layout.tsx
|
|
23
24
|
import { ExternalLink as ExternalLink2, FileEdit } from "lucide-react";
|
|
@@ -2136,7 +2137,9 @@ function SearchModal({ isOpen, onClose, config }) {
|
|
|
2136
2137
|
// src/components/docs/header.tsx
|
|
2137
2138
|
import { useState as useState14, useEffect as useEffect8 } from "react";
|
|
2138
2139
|
import { jsx as jsx38, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2139
|
-
function Header({ currentVersion, versions, onMenuClick, config }) {
|
|
2140
|
+
function Header({ currentVersion, versions, onMenuClick, config: configProp }) {
|
|
2141
|
+
const contextConfig = useConfig();
|
|
2142
|
+
const config = configProp || contextConfig;
|
|
2140
2143
|
const [searchOpen, setSearchOpen] = useState14(false);
|
|
2141
2144
|
useEffect8(() => {
|
|
2142
2145
|
const handleKeyDown = (e) => {
|
|
@@ -2162,7 +2165,7 @@ function Header({ currentVersion, versions, onMenuClick, config }) {
|
|
|
2162
2165
|
),
|
|
2163
2166
|
/* @__PURE__ */ jsxs28(Link5, { href: "/", className: "flex items-center gap-2", children: [
|
|
2164
2167
|
config.site.logo ? /* @__PURE__ */ jsx38("img", { src: getAssetPath(config.site.logo), alt: config.site.title, className: "h-8 w-auto" }) : /* @__PURE__ */ jsx38("div", { className: "h-8 w-8 rounded-xl bg-primary flex items-center justify-center", children: /* @__PURE__ */ jsx38("span", { className: "text-primary-foreground font-bold text-lg", children: config.site.title.charAt(0).toUpperCase() }) }),
|
|
2165
|
-
/* @__PURE__ */ jsx38("span", { className: "font-semibold text-lg text-foreground", children: "Specra" })
|
|
2168
|
+
/* @__PURE__ */ jsx38("span", { className: "font-semibold text-lg text-foreground", children: config.site.title ?? "Specra" })
|
|
2166
2169
|
] })
|
|
2167
2170
|
] }),
|
|
2168
2171
|
/* @__PURE__ */ jsxs28("div", { className: "flex items-center gap-2", children: [
|
|
@@ -3116,4 +3119,4 @@ export {
|
|
|
3116
3119
|
generateStaticParams,
|
|
3117
3120
|
DocPage
|
|
3118
3121
|
};
|
|
3119
|
-
//# sourceMappingURL=chunk-
|
|
3122
|
+
//# sourceMappingURL=chunk-4QHOMV5A.mjs.map
|