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.
Files changed (42) hide show
  1. package/dist/app/docs-page.js +164 -148
  2. package/dist/app/docs-page.js.map +1 -1
  3. package/dist/app/docs-page.mjs +3 -3
  4. package/dist/app/layout.js +84 -5
  5. package/dist/app/layout.js.map +1 -1
  6. package/dist/app/layout.mjs +3 -3
  7. package/dist/{chunk-NXRIAL7T.mjs → chunk-4QHOMV5A.mjs} +8 -5
  8. package/dist/chunk-4QHOMV5A.mjs.map +1 -0
  9. package/dist/{chunk-IZFGEAD6.mjs → chunk-5AYOV2KD.mjs} +5 -4
  10. package/dist/chunk-5AYOV2KD.mjs.map +1 -0
  11. package/dist/chunk-I3ELVEK2.mjs +56 -0
  12. package/dist/chunk-I3ELVEK2.mjs.map +1 -0
  13. package/dist/{chunk-INL2EC72.mjs → chunk-RLMSINLY.mjs} +2 -5
  14. package/dist/{chunk-INL2EC72.mjs.map → chunk-RLMSINLY.mjs.map} +1 -1
  15. package/dist/components/index.d.mts +39 -3
  16. package/dist/components/index.d.ts +39 -3
  17. package/dist/components/index.js +100 -62
  18. package/dist/components/index.js.map +1 -1
  19. package/dist/components/index.mjs +83 -48
  20. package/dist/components/index.mjs.map +1 -1
  21. package/dist/index.d.mts +39 -3
  22. package/dist/index.d.ts +39 -3
  23. package/dist/index.js +129 -94
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +10 -4
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/lib/index.d.mts +7 -0
  28. package/dist/lib/index.d.ts +7 -0
  29. package/dist/lib/index.js +1 -4
  30. package/dist/lib/index.js.map +1 -1
  31. package/dist/lib/index.mjs +1 -1
  32. package/package.json +2 -2
  33. package/src/app/layout.tsx +6 -3
  34. package/src/components/docs/header.tsx +7 -3
  35. package/src/components/docs/index.ts +3 -0
  36. package/src/lib/config.context.tsx +65 -0
  37. package/src/lib/config.server.ts +9 -5
  38. package/src/lib/index.ts +1 -0
  39. package/dist/chunk-IZFGEAD6.mjs.map +0 -1
  40. package/dist/chunk-MZJHJ6BV.mjs +0 -21
  41. package/dist/chunk-MZJHJ6BV.mjs.map +0 -1
  42. package/dist/chunk-NXRIAL7T.mjs.map +0 -1
@@ -43,7 +43,7 @@ import {
43
43
  reloadConfig,
44
44
  replaceEnvVariables,
45
45
  validateConfig
46
- } from "../chunk-INL2EC72.mjs";
46
+ } from "../chunk-RLMSINLY.mjs";
47
47
  export {
48
48
  OpenApiParser,
49
49
  PerfTimer,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specra",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A modern documentation library for Next.js with built-in versioning, API reference generation, full-text search, and MDX support",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -56,7 +56,7 @@
56
56
  "license": "MIT",
57
57
  "repository": {
58
58
  "type": "git",
59
- "url": "https://github.com/yourusername/specra"
59
+ "url": "https://github.com/dalmasonto/specra"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "next": "^14.0.0 || ^15.0.0 || ^16.0.0",
@@ -3,6 +3,7 @@ import type { Metadata } from "next"
3
3
  import { Geist, Geist_Mono } from "next/font/google"
4
4
  import { getConfig } from "../lib/config"
5
5
  import { getAssetPath } from "../lib/utils"
6
+ import { ConfigProvider } from "../lib/config.context"
6
7
  import { TabProvider } from "../components/docs/tab-context"
7
8
  import "../styles/globals.css"
8
9
 
@@ -65,9 +66,11 @@ export default function RootLayout({
65
66
  return (
66
67
  <html lang={config.site.language || "en"} suppressHydrationWarning>
67
68
  <body className={`${geist.className} font-sans antialiased`}>
68
- <TabProvider defaultTab={defaultTab}>
69
- {children}
70
- </TabProvider>
69
+ <ConfigProvider config={config}>
70
+ <TabProvider defaultTab={defaultTab}>
71
+ {children}
72
+ </TabProvider>
73
+ </ConfigProvider>
71
74
  </body>
72
75
  </html>
73
76
  )
@@ -8,16 +8,20 @@ import { ThemeToggle } from "./theme-toggle"
8
8
  import { SearchModal } from "./search-modal"
9
9
  import { useState, useEffect } from "react"
10
10
  import type { SpecraConfig } from "@/lib/config"
11
+ import { useConfig } from "@/lib/config.context"
11
12
  import { getAssetPath } from "@/lib/utils"
12
13
 
13
14
  interface HeaderProps {
14
15
  currentVersion: string
15
16
  versions: string[]
16
17
  onMenuClick?: () => void
17
- config: SpecraConfig
18
+ config?: SpecraConfig // Made optional since we can get it from context
18
19
  }
19
20
 
20
- export function Header({ currentVersion, versions, onMenuClick, config }: HeaderProps) {
21
+ export function Header({ currentVersion, versions, onMenuClick, config: configProp }: HeaderProps) {
22
+ // Use config from context if not provided as prop
23
+ const contextConfig = useConfig()
24
+ const config = configProp || contextConfig
21
25
  const [searchOpen, setSearchOpen] = useState(false)
22
26
 
23
27
  // Keyboard shortcut for search (Cmd+K or Ctrl+K)
@@ -54,7 +58,7 @@ export function Header({ currentVersion, versions, onMenuClick, config }: Header
54
58
  </span>
55
59
  </div>
56
60
  )}
57
- <span className="font-semibold text-lg text-foreground">Specra</span>
61
+ <span className="font-semibold text-lg text-foreground">{config.site.title ?? "Specra"}</span>
58
62
  </Link>
59
63
  </div>
60
64
 
@@ -44,5 +44,8 @@ export * from "./tooltip"
44
44
  export * from "./version-switcher"
45
45
  export * from "./video"
46
46
 
47
+ // Re-export ConfigProvider from lib (client component for config context)
48
+ export { ConfigProvider, useConfig, useConfigValue } from "../../lib/config.context"
49
+
47
50
  // API documentation components
48
51
  export * from "./api"
@@ -0,0 +1,65 @@
1
+ import * as React from "react"
2
+ import { SpecraConfig, defaultConfig } from "./config.types"
3
+
4
+ const ConfigContext = React.createContext<SpecraConfig>(defaultConfig)
5
+
6
+ export interface ConfigProviderProps {
7
+ config: SpecraConfig
8
+ children: React.ReactNode
9
+ }
10
+
11
+ /**
12
+ * Provider component that makes Specra config available to all client components
13
+ * Usage: Wrap your app with this provider in your root layout
14
+ */
15
+ export function ConfigProvider({ config, children }: ConfigProviderProps) {
16
+ return <ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>
17
+ }
18
+
19
+ /**
20
+ * Hook to access Specra configuration in any client component
21
+ * @returns The current Specra configuration
22
+ * @example
23
+ * ```tsx
24
+ * function MyComponent() {
25
+ * const config = useConfig()
26
+ * return <div>{config.site.title}</div>
27
+ * }
28
+ * ```
29
+ */
30
+ export function useConfig(): SpecraConfig {
31
+ const config = React.useContext(ConfigContext)
32
+ if (!config) {
33
+ throw new Error("useConfig must be used within a ConfigProvider")
34
+ }
35
+ return config
36
+ }
37
+
38
+ /**
39
+ * Hook to access a specific configuration value by path
40
+ * @param path - Dot-separated path to the config value (e.g., "site.title")
41
+ * @returns The configuration value at the specified path
42
+ * @example
43
+ * ```tsx
44
+ * function MyComponent() {
45
+ * const title = useConfigValue<string>("site.title")
46
+ * const showSidebar = useConfigValue<boolean>("navigation.showSidebar")
47
+ * return <div>{title}</div>
48
+ * }
49
+ * ```
50
+ */
51
+ export function useConfigValue<T = any>(path: string): T | undefined {
52
+ const config = useConfig()
53
+ const keys = path.split(".")
54
+ let value: any = config
55
+
56
+ for (const key of keys) {
57
+ if (value && typeof value === "object" && key in value) {
58
+ value = value[key]
59
+ } else {
60
+ return undefined
61
+ }
62
+ }
63
+
64
+ return value as T
65
+ }
@@ -137,21 +137,25 @@ export function validateConfig(config: SpecraConfig): { valid: boolean; errors:
137
137
  // Singleton instance
138
138
  let configInstance: SpecraConfig | null = null
139
139
 
140
+ /**
141
+ * Initialize the Specra configuration
142
+ * Can be called multiple times - subsequent calls will update the config
143
+ * @param userConfig - Partial configuration to merge with defaults
144
+ * @returns The initialized configuration
145
+ */
140
146
  export function initConfig(userConfig: Partial<SpecraConfig>): SpecraConfig {
141
- if (configInstance) {
142
- throw new Error("Specra config has already been initialized")
143
- }
144
-
145
147
  configInstance = loadConfig(userConfig)
146
148
  return configInstance
147
149
  }
148
150
 
149
151
  /**
150
152
  * Get the configuration instance (cached) (SERVER ONLY)
153
+ * If not initialized, returns default config
151
154
  */
152
155
  export function getConfig(): SpecraConfig {
153
156
  if (!configInstance) {
154
- throw new Error("Specra config has not been initialized")
157
+ // Auto-initialize with defaults if not already initialized
158
+ configInstance = loadConfig({})
155
159
  }
156
160
  return configInstance
157
161
  }
package/src/lib/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from './toc'
6
6
  // Configuration
7
7
  export * from './config.server'
8
8
  export * from './config'
9
+ // NOTE: config.context is NOT exported here (it's client-only, exported from components/index)
9
10
  export type * from './config.types'
10
11
 
11
12
  // API Parsers
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/app/layout.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}"],"mappings":";;;;;;;;;AAEA,SAAS,OAAO,kBAAkB;AAiE1B;AA3DR,IAAM,QAAQ,MAAM,EAAE,SAAS,CAAC,OAAO,EAAE,CAAC;AAC1C,IAAM,YAAY,WAAW,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,oBAAC,UAAK,MAAM,OAAO,KAAK,YAAY,MAAM,0BAAwB,MAChE,8BAAC,UAAK,WAAW,GAAG,MAAM,SAAS,0BACjC,8BAAC,eAAY,YACV,UACH,GACF,GACF;AAEJ;","names":[]}
@@ -1,21 +0,0 @@
1
- // src/components/docs/tab-context.tsx
2
- import { createContext, useContext, useState } from "react";
3
- import { jsx } from "react/jsx-runtime";
4
- var TabContext = createContext(void 0);
5
- function TabProvider({ children, defaultTab }) {
6
- const [activeTabGroup, setActiveTabGroup] = useState(defaultTab);
7
- return /* @__PURE__ */ jsx(TabContext.Provider, { value: { activeTabGroup, setActiveTabGroup }, children });
8
- }
9
- function useTabContext() {
10
- const context = useContext(TabContext);
11
- if (!context) {
12
- throw new Error("useTabContext must be used within TabProvider");
13
- }
14
- return context;
15
- }
16
-
17
- export {
18
- TabProvider,
19
- useTabContext
20
- };
21
- //# sourceMappingURL=chunk-MZJHJ6BV.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/docs/tab-context.tsx"],"sourcesContent":["\"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":";AAEA,SAAS,eAAe,YAAY,gBAA2B;AAa3D;AANJ,IAAM,aAAa,cAA0C,MAAS;AAE/D,SAAS,YAAY,EAAE,UAAU,WAAW,GAAgD;AACjG,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAS,UAAU;AAE/D,SACE,oBAAC,WAAW,UAAX,EAAoB,OAAO,EAAE,gBAAgB,kBAAkB,GAC7D,UACH;AAEJ;AAEO,SAAS,gBAAgB;AAC9B,QAAM,UAAU,WAAW,UAAU;AACrC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AACA,SAAO;AACT;","names":[]}