@unterberg/nivel 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -1,70 +1,33 @@
1
1
  # nivel engine
2
2
 
3
- docs builder proof of concept for generating vike-based documentation sites with a single docs graph as the source of truth.
3
+ `@unterberg/nivel` is the docs runtime for this repo's Vike-based documentation sites.
4
4
 
5
- monorepo structure:
6
-
7
- - `packages/engine`: the reusable `@unterberg/nivel` package
8
- - `packages/consumer-test`: the reference consumer used to exercise the engine against real docs content, currently based on the [Telefunc docs](https://telefunc.com)
9
-
10
- ## Alpha Status
11
-
12
- This project is an early proof of concept and should be expected to have rough edges. The main goal is to validate the core engine ideas and architecture, not to provide a polished general-purpose doc builder right now. Some specific things to keep in mind:
13
-
14
- - Expect breaking changes.
15
- - The public API is not stable yet. (blackbox)
16
- - The supported stack fixed currently to Vike + Vite + React.
17
- - `basePath` is currently fixed to `/docs`.
18
- - The consumer app in this repo is still the main integration example.
19
-
20
- If you need a polished general-purpose docpress replacement today, this is not that yet.
21
-
22
- ## What It Does
23
-
24
- The engine currently owns the core docs runtime:
5
+ It currently owns:
25
6
 
26
7
  - docs graph validation and resolution
27
8
  - generated Vike routes from MDX content
28
- - shared docs layout pieces such as navbar, sidebar, table of contents, pagination, and meta head wiring
9
+ - docs layout primitives such as navbar, sidebar, table of contents, pagination, and meta head wiring
29
10
  - MDX setup with built-in docs components and code-block transforms
30
- - asset handling for engine-owned fonts and shared static assets
11
+ - optional Algolia search wiring
12
+ - engine-owned fonts and shared assets
31
13
 
32
- The intended split is:
14
+ The supported stack is currently Vike + Vite + React. Expect breaking changes while the package is still alpha.
33
15
 
34
- - the engine owns behavior, runtime wiring, and reusable UI primitives
35
- - the consumer owns docs content, `docs/docs.graph.ts`, `pages/+docs.ts`, and brand/theme assets
36
-
37
- ## Minimal Shape
38
-
39
- At the moment, a consumer looks roughly like this:
16
+ ## Public Helpers
40
17
 
41
18
  ```ts
42
- // pages/+docs.ts
43
- import { defineDocsConfig } from '@unterberg/nivel'
44
- import { docsGraph } from '../docs/docs.graph'
45
-
46
- export default defineDocsConfig({
47
- siteTitle: 'My Docs',
48
- basePath: '/docs',
49
- graph: docsGraph,
50
- algolia: {
51
- appId: 'YOUR_APP_ID',
52
- apiKey: 'YOUR_SEARCH_ONLY_API_KEY',
53
- indexName: 'YOUR_INDEX_NAME',
54
- },
55
- })
19
+ import { defineDocsConfig, defineDocsGraph } from '@unterberg/nivel/config'
56
20
  ```
57
21
 
58
- ```ts
59
- // docs/docs.graph.ts
60
- import { defineDocsGraph } from '@unterberg/nivel'
22
+ Both helpers are identity functions. They are also re-exported from `@unterberg/nivel`, but the dedicated config entry keeps `pages/+docs.ts` and `docs/docs.graph.ts` on a lean config-time import path.
61
23
 
62
- export const docsGraph = defineDocsGraph({
24
+ ```ts
25
+ const docsGraph = defineDocsGraph({
63
26
  items: [
64
27
  {
65
28
  kind: 'section',
66
29
  id: 'docs',
67
- title: 'Documentation',
30
+ title: 'Docs',
68
31
  items: [
69
32
  {
70
33
  kind: 'page',
@@ -77,31 +40,91 @@ export const docsGraph = defineDocsGraph({
77
40
  },
78
41
  ],
79
42
  })
43
+
44
+ export default defineDocsConfig({
45
+ siteTitle: 'My Docs',
46
+ siteDescription: 'Documentation site powered by @unterberg/nivel.',
47
+ basePath: '/docs',
48
+ graph: docsGraph,
49
+ })
80
50
  ```
81
51
 
82
- Then the consumer wires:
52
+ ## Recommended Consumer Files
83
53
 
84
- - `@unterberg/nivel/vike` into Vike config
85
- - `MetaHead` in global `+Head`
86
- - `AppLayout` in global `+Layout`
87
- - `nivel prepare` before dev/build/typecheck
88
- - `@import '@unterberg/nivel/tailwind-sources.css'` in the consumer Tailwind entry
54
+ A consumer should keep these files explicit and local:
89
55
 
90
- Algolia search is optional. When configured, `apiKey` must be a search-only public key because requests are made from the browser.
56
+ - hand-authored: `pages/+docs.ts`, `docs/docs.graph.ts`, docs content, brand assets, and consumer CSS/Tailwind/theme files
57
+ - scaffolded once but still editable: `pages/+config.ts`, `pages/+Head.tsx`, `pages/+Layout.tsx`, `pages/+onCreateGlobalContext.ts`, `pages/+Wrapper.tsx`, and `global.d.ts`
91
58
 
92
- ## Current Limitations
59
+ Only `(nivel-generated)` stays engine-generated.
93
60
 
94
- - The package is still alpha and should be expected to change.
95
- - The supported stack is currently narrow: Vike + Vite + React.
96
- - `basePath` is currently fixed to `/docs`.
97
- - The package is still validated mainly through one real consumer, not a broad set of independent adopters.
98
- - The setup and examples are still catching up with the implementation, so the integration story is not fully polished yet.
61
+ ## Standard Vike Config
99
62
 
100
- ## Future Plans
63
+ Keep `pages/+config.ts` looking like normal Vike config and spread in the engine-owned config from `@unterberg/nivel/vike`:
64
+
65
+ ```ts
66
+ // pages/+docs.ts
67
+ import { defineDocsConfig } from '@unterberg/nivel/config'
68
+ import { docsGraph } from '../docs/docs.graph'
69
+
70
+ export default defineDocsConfig({
71
+ siteTitle: 'My Docs',
72
+ siteDescription: 'Documentation site powered by @unterberg/nivel.',
73
+ basePath: '/docs',
74
+ graph: docsGraph,
75
+ })
76
+ ```
77
+
78
+ ```ts
79
+ // pages/+config.ts
80
+ import nivel from '@unterberg/nivel/vike'
81
+ import type { Config } from 'vike/types'
82
+ import vikeReact from 'vike-react/config'
83
+ import docsConfig from './+docs'
84
+
85
+ export { config }
86
+
87
+ const themePreference = docsConfig.theme?.defaultPreference ?? 'light'
88
+ const dataTheme =
89
+ themePreference === 'dark'
90
+ ? (docsConfig.theme?.dark ?? 'consumer-dark')
91
+ : (docsConfig.theme?.light ?? 'consumer-light')
92
+
93
+ const config: Config = {
94
+ ...nivel,
95
+ extends: [vikeReact],
96
+ title: docsConfig.siteTitle,
97
+ description: docsConfig.siteDescription ?? `${docsConfig.siteTitle} documentation`,
98
+ htmlAttributes: { 'data-theme': dataTheme },
99
+ passToClient: ['docs'],
100
+
101
+ // User-facing Vike levers stay visible here.
102
+ prerender: true,
103
+ // ssr: true,
104
+ // prefetchStaticAssets: 'viewport',
105
+ }
106
+ ```
107
+
108
+ The engine still owns the MDX, Vite, route-generation, and runtime wiring. The consumer keeps the normal Vike entry file and can adjust visible levers such as `prerender`, `ssr`, and prefetch-related settings directly in `+config.ts`.
109
+
110
+ ## CLI
111
+
112
+ `nivel prepare` generates docs pages from `pages/+docs.ts`.
113
+
114
+ `nivel init` scaffolds the visible consumer shell files and updates the standard docs scripts in `package.json`.
115
+
116
+ ```bash
117
+ nivel init
118
+ nivel prepare
119
+ ```
120
+
121
+ `nivel init` does not create or overwrite consumer CSS/Tailwind/theme files. Keep those hand-authored. Add the engine Tailwind helper manually in your stylesheet:
122
+
123
+ ```css
124
+ @import '@unterberg/nivel/tailwind-sources.css';
125
+ ```
101
126
 
102
- - Continue hardening the engine/consumer split so docs behavior stays in `@unterberg/nivel` and the consumer remains thin.
103
- - Improve the package-level docs and examples so setup is easier to understand without reading the consumer app in detail.
104
- - Reduce hard-coded assumptions where it makes sense, starting with the areas that currently make the engine feel too tied to its first consumer.
127
+ If you use Algolia, `apiKey` must be a search-only public key because requests are made from the browser.
105
128
 
106
129
  ## Commands
107
130
 
@@ -1,7 +1,3 @@
1
- import {
2
- UniversalMdxProvider,
3
- renderInlineMarkdown
4
- } from "./chunk-L6ZVB6XH.js";
5
1
  import {
6
2
  createHeadingSlugger,
7
3
  getActiveSectionByPathname,
@@ -10,6 +6,10 @@ import {
10
6
  isSamePagePathname,
11
7
  normalizeHeadingTitle
12
8
  } from "./chunk-D7IAGT53.js";
9
+ import {
10
+ UniversalMdxProvider,
11
+ renderInlineMarkdown
12
+ } from "./chunk-L6ZVB6XH.js";
13
13
  import {
14
14
  withSiteBaseUrl
15
15
  } from "./chunk-PYYPYIBD.js";
@@ -1535,4 +1535,4 @@ export {
1535
1535
  ProseContainer,
1536
1536
  DocsPage
1537
1537
  };
1538
- //# sourceMappingURL=chunk-UDOIFPCZ.js.map
1538
+ //# sourceMappingURL=chunk-2EDJWL3U.js.map
@@ -6,87 +6,22 @@ import {
6
6
  withSiteBaseUrl
7
7
  } from "./chunk-PYYPYIBD.js";
8
8
 
9
- // src/mdx/components/Alert.tsx
10
- import cm, { cmMerge } from "@classmatejs/react";
11
- import { Check, CircleX, Info, TriangleAlert } from "lucide-react";
12
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
- var alertIconMap = {
14
- info: Info,
15
- warning: TriangleAlert,
16
- error: CircleX,
17
- success: Check
18
- };
19
- var Alert = ({
20
- type = "info",
21
- heading,
22
- children,
23
- icon = true
24
- }) => {
25
- const AlertIcon = icon === true ? alertIconMap[type] : typeof icon === "object" ? () => /* @__PURE__ */ jsx(Fragment, { children: icon }) : null;
26
- const alertIconTextColorClass = {
27
- info: "text-info",
28
- warning: "text-warning",
29
- error: "text-error",
30
- success: "text-success"
31
- }[type];
32
- return /* @__PURE__ */ jsxs(AlertOuter, { $variant: type, children: [
33
- !!heading && AlertIcon && /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-2", children: [
34
- /* @__PURE__ */ jsx(AlertIcon, { className: cmMerge(alertIconTextColorClass, "float-left h-5 w-5") }),
35
- /* @__PURE__ */ jsx(AlertHeading, { children: heading })
36
- ] }),
37
- !(!!heading && AlertIcon) && !!heading && /* @__PURE__ */ jsx(AlertHeading, { children: heading }),
38
- !(!!heading && AlertIcon) && AlertIcon && /* @__PURE__ */ jsx("div", { className: cmMerge(alertIconTextColorClass, "float-left mr-2"), children: /* @__PURE__ */ jsx(AlertIcon, { className: "mt-1 h-5 w-5" }) }),
39
- children
40
- ] });
41
- };
42
- var AlertOuter = cm.section.variants({
43
- base: `
44
- p-4
45
- mt-5
46
- mb-5
47
- border
48
- rounded-lg
49
- prose-p:last:mb-0
50
- prose-p:mt-0
51
- prose-headings:first:mt-0
52
- prose-headings:last:mb-0
53
- prose-ul:first:mt-0
54
- prose-ul:last:mb-0
55
- text-sm
56
- `,
57
- variants: {
58
- $variant: {
59
- info: "bg-info/10 border-info/30",
60
- warning: "bg-warning/10 border-warning/30",
61
- error: "bg-error/10 border-error/25",
62
- success: "bg-success/10 border-success/35"
63
- }
64
- },
65
- defaultVariants: {
66
- $variant: "info"
67
- }
68
- });
69
- var AlertHeading = cm.header`
70
- font-bold
71
- text-base
72
- `;
73
-
74
9
  // src/mdx/code-blocks/ChoiceGroup.tsx
75
10
  import { Children, isValidElement, useRef as useRef2 } from "react";
76
11
 
77
12
  // src/mdx/code-blocks/CodeBlockHeaderMeta.tsx
78
- import cm2 from "@classmatejs/react";
79
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
13
+ import cm from "@classmatejs/react";
14
+ import { jsx, jsxs } from "react/jsx-runtime";
80
15
  var CodeBlockHeaderMeta = ({ env, label }) => {
81
16
  const effectiveEnv = env === "server" || env === "client" ? env : void 0;
82
- return /* @__PURE__ */ jsxs2("div", { className: "flex min-w-0 items-center gap-2", children: [
83
- env && /* @__PURE__ */ jsx2(StyledDivider, { $env: env === "server" || env === "client" ? env : void 0 }),
84
- env && /* @__PURE__ */ jsx2(StyledBgShade, { $env: env === "server" || env === "client" ? env : void 0 }),
85
- /* @__PURE__ */ jsx2("div", { className: "font-mono text-xs font-semibold text-base-muted", children: label }),
86
- env && /* @__PURE__ */ jsx2(StyledBadge, { $env: effectiveEnv, children: env })
17
+ return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
18
+ env && /* @__PURE__ */ jsx(StyledDivider, { $env: env === "server" || env === "client" ? env : void 0 }),
19
+ env && /* @__PURE__ */ jsx(StyledBgShade, { $env: env === "server" || env === "client" ? env : void 0 }),
20
+ /* @__PURE__ */ jsx("div", { className: "font-mono text-xs font-semibold text-base-muted", children: label }),
21
+ env && /* @__PURE__ */ jsx(StyledBadge, { $env: effectiveEnv, children: env })
87
22
  ] });
88
23
  };
89
- var StyledDivider = cm2.div.variants({
24
+ var StyledDivider = cm.div.variants({
90
25
  base: "absolute h-1 -bottom-px left-0 w-full pointer-events-none",
91
26
  variants: {
92
27
  $env: {
@@ -96,7 +31,7 @@ var StyledDivider = cm2.div.variants({
96
31
  },
97
32
  defaultVariants: { $env: "server" }
98
33
  });
99
- var StyledBadge = cm2.div.variants({
34
+ var StyledBadge = cm.div.variants({
100
35
  base: "shrink-0 badge badge-sm rounded-field badge-soft border pointer-events-none",
101
36
  variants: {
102
37
  $env: {
@@ -106,7 +41,7 @@ var StyledBadge = cm2.div.variants({
106
41
  },
107
42
  defaultVariants: { $env: "server" }
108
43
  });
109
- var StyledBgShade = cm2.div.variants({
44
+ var StyledBgShade = cm.div.variants({
110
45
  base: "absolute inset-0 opacity-5 bg-linear-to-t via-40% via-transparent pointer-events-none",
111
46
  variants: {
112
47
  $env: {
@@ -118,10 +53,10 @@ var StyledBgShade = cm2.div.variants({
118
53
  });
119
54
 
120
55
  // src/mdx/code-blocks/CopyButton.tsx
121
- import { cmMerge as cmMerge2 } from "@classmatejs/react";
122
- import { Check as Check2, Copy } from "lucide-react";
56
+ import { cmMerge } from "@classmatejs/react";
57
+ import { Check, Copy } from "lucide-react";
123
58
  import { useState } from "react";
124
- import { jsx as jsx3 } from "react/jsx-runtime";
59
+ import { jsx as jsx2 } from "react/jsx-runtime";
125
60
  var trimTrailingWhitespace = (text) => {
126
61
  return text.split("\n").map((line) => line.trimEnd()).join("\n");
127
62
  };
@@ -130,18 +65,18 @@ var CodeBlockCopyButton = ({
130
65
  className = ""
131
66
  }) => {
132
67
  const [copyState, setCopyState] = useState("idle");
133
- return /* @__PURE__ */ jsx3(
68
+ return /* @__PURE__ */ jsx2(
134
69
  "button",
135
70
  {
136
71
  type: "button",
137
- className: cmMerge2("btn btn-ghost btn-xs h-8 min-h-8 px-2 text-base-muted hover:text-base-content", className),
72
+ className: cmMerge("btn btn-ghost btn-xs h-8 min-h-8 px-2 text-base-muted hover:text-base-content", className),
138
73
  onClick: async () => {
139
74
  const success = await onCopy();
140
75
  setCopyState(success ? "success" : "error");
141
76
  window.setTimeout(() => setCopyState("idle"), 900);
142
77
  },
143
78
  "aria-label": copyState === "idle" ? "Copy to clipboard" : copyState === "success" ? "Copied" : "Copy failed",
144
- children: copyState === "success" ? /* @__PURE__ */ jsx3(Check2, { size: 14 }) : /* @__PURE__ */ jsx3(Copy, { size: 14 })
79
+ children: copyState === "success" ? /* @__PURE__ */ jsx2(Check, { size: 14 }) : /* @__PURE__ */ jsx2(Copy, { size: 14 })
145
80
  }
146
81
  );
147
82
  };
@@ -200,7 +135,7 @@ var useSelectedChoice = (choiceGroupName, defaultValue) => {
200
135
  };
201
136
 
202
137
  // src/mdx/code-blocks/ChoiceGroup.tsx
203
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
138
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
204
139
  var isChoiceElement = (node) => {
205
140
  return isValidElement(node) && typeof node.props?.["data-choice-value"] === "string";
206
141
  };
@@ -237,28 +172,28 @@ var ChoiceGroup = ({
237
172
  const choiceElements = Children.toArray(children).filter(isChoiceElement);
238
173
  const activeChoiceElement = choiceElements.find((choiceElement) => choiceElement.props["data-choice-value"] === selectedChoice) ?? choiceElements[0];
239
174
  if (!activeChoiceElement) {
240
- return /* @__PURE__ */ jsx4(Fragment2, { children });
175
+ return /* @__PURE__ */ jsx3(Fragment, { children });
241
176
  }
242
177
  const activeCodeBlockMeta = getActiveCodeBlockMeta(activeChoiceElement.props.children);
243
178
  const headerLabel = activeCodeBlockMeta.title ?? activeChoiceElement.props["data-choice-value"] ?? "";
244
179
  if (hide) {
245
- return /* @__PURE__ */ jsx4(Fragment2, { children: activeChoiceElement.props.children });
180
+ return /* @__PURE__ */ jsx3(Fragment, { children: activeChoiceElement.props.children });
246
181
  }
247
- return /* @__PURE__ */ jsxs3(
182
+ return /* @__PURE__ */ jsxs2(
248
183
  "div",
249
184
  {
250
185
  "data-choice-group-outer": true,
251
186
  className: "mt-5 mb-5 flex h-full flex-col overflow-hidden rounded-box border border-base-muted-light",
252
187
  children: [
253
- /* @__PURE__ */ jsxs3(
188
+ /* @__PURE__ */ jsxs2(
254
189
  "div",
255
190
  {
256
191
  className: "not-prose flex min-h-10 items-center relative justify-between gap-3 border-b border-base-muted-light bg-base-muted-superlight px-4",
257
192
  "data-choice-group-header": true,
258
193
  children: [
259
- /* @__PURE__ */ jsx4(CodeBlockHeaderMeta, { label: headerLabel, env: activeCodeBlockMeta.env }),
260
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1", children: [
261
- /* @__PURE__ */ jsx4("label", { className: "select select-xs min-w-28 w-fit", children: /* @__PURE__ */ jsx4(
194
+ /* @__PURE__ */ jsx3(CodeBlockHeaderMeta, { label: headerLabel, env: activeCodeBlockMeta.env }),
195
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-1", children: [
196
+ /* @__PURE__ */ jsx3("label", { className: "select select-xs min-w-28 w-fit", children: /* @__PURE__ */ jsx3(
262
197
  "select",
263
198
  {
264
199
  name: `choicesFor-${choiceGroup.name}`,
@@ -270,10 +205,10 @@ var ChoiceGroup = ({
270
205
  };
271
206
  setSelectedChoice(event.currentTarget.value);
272
207
  },
273
- children: choiceGroup.choices.map((choice) => /* @__PURE__ */ jsx4("option", { value: choice, disabled: choiceGroup.disabled.includes(choice), children: choice }, choice))
208
+ children: choiceGroup.choices.map((choice) => /* @__PURE__ */ jsx3("option", { value: choice, disabled: choiceGroup.disabled.includes(choice), children: choice }, choice))
274
209
  }
275
210
  ) }),
276
- !activeCodeBlockMeta.hideCopy && /* @__PURE__ */ jsx4(
211
+ !activeCodeBlockMeta.hideCopy && /* @__PURE__ */ jsx3(
277
212
  CodeBlockCopyButton,
278
213
  {
279
214
  onCopy: async () => {
@@ -291,36 +226,36 @@ var ChoiceGroup = ({
291
226
  ]
292
227
  }
293
228
  ),
294
- /* @__PURE__ */ jsx4("div", { ref: bodyRef, className: "h-full flex-1 bg-base-200! [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children: /* @__PURE__ */ jsx4(CodeBlockGroupProvider, { value: true, children: activeChoiceElement.props.children }) })
229
+ /* @__PURE__ */ jsx3("div", { ref: bodyRef, className: "h-full flex-1 bg-base-200! [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", children: /* @__PURE__ */ jsx3(CodeBlockGroupProvider, { value: true, children: activeChoiceElement.props.children }) })
295
230
  ]
296
231
  }
297
232
  );
298
233
  };
299
234
 
300
235
  // src/mdx/code-blocks/CodeBlockTransformer.tsx
301
- import { jsx as jsx5 } from "react/jsx-runtime";
236
+ import { jsx as jsx4 } from "react/jsx-runtime";
302
237
  var CodeBlockTransformer = ({ children, lineBreak }) => {
303
238
  const className = `with-line-break_${lineBreak}`;
304
- return /* @__PURE__ */ jsx5("div", { className, children });
239
+ return /* @__PURE__ */ jsx4("div", { className, children });
305
240
  };
306
241
 
307
242
  // src/mdx/code-blocks/FileState.tsx
308
- import { jsx as jsx6 } from "react/jsx-runtime";
243
+ import { jsx as jsx5 } from "react/jsx-runtime";
309
244
  var FileAdded = ({ children }) => {
310
- return /* @__PURE__ */ jsx6("div", { className: "doc-code-file-state doc-code-file-added", children });
245
+ return /* @__PURE__ */ jsx5("div", { className: "doc-code-file-state doc-code-file-added", children });
311
246
  };
312
247
  var FileRemoved = ({ children }) => {
313
- return /* @__PURE__ */ jsx6("div", { className: "doc-code-file-state doc-code-file-removed", children });
248
+ return /* @__PURE__ */ jsx5("div", { className: "doc-code-file-state doc-code-file-removed", children });
314
249
  };
315
250
 
316
251
  // src/mdx/code-blocks/Pre.tsx
317
- import { cmMerge as cmMerge3 } from "@classmatejs/react";
252
+ import { cmMerge as cmMerge2 } from "@classmatejs/react";
318
253
  import {
319
254
  Children as Children2,
320
255
  isValidElement as isValidElement2,
321
256
  useRef as useRef3
322
257
  } from "react";
323
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
258
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
324
259
  var asTrimmedString2 = (value) => {
325
260
  return typeof value === "string" && value.trim() ? value.trim() : null;
326
261
  };
@@ -353,7 +288,7 @@ var Pre = ({ children, className, ...props }) => {
353
288
  const env = asTrimmedString2(props["data-code-env"]);
354
289
  const fileState = props["file-added"] ? "added" : props["file-removed"] ? "removed" : null;
355
290
  const hideMenu = props["hide-menu"] === "true";
356
- const copyButton = hideMenu || isInChoiceGroup ? null : /* @__PURE__ */ jsx7(
291
+ const copyButton = hideMenu || isInChoiceGroup ? null : /* @__PURE__ */ jsx6(
357
292
  CodeBlockCopyButton,
358
293
  {
359
294
  onCopy: async () => {
@@ -367,10 +302,10 @@ var Pre = ({ children, className, ...props }) => {
367
302
  }
368
303
  }
369
304
  );
370
- return /* @__PURE__ */ jsxs4(
305
+ return /* @__PURE__ */ jsxs3(
371
306
  "div",
372
307
  {
373
- className: cmMerge3(
308
+ className: cmMerge2(
374
309
  "group relative h-full not-prose overflow-hidden",
375
310
  isInChoiceGroup ? "" : "mb-6 rounded-box border border-base-muted-light",
376
311
  className
@@ -378,23 +313,23 @@ var Pre = ({ children, className, ...props }) => {
378
313
  "data-code-block-frame": "",
379
314
  "data-file-state": fileState ?? void 0,
380
315
  children: [
381
- !isInChoiceGroup && /* @__PURE__ */ jsxs4(
316
+ !isInChoiceGroup && /* @__PURE__ */ jsxs3(
382
317
  "div",
383
318
  {
384
319
  className: "flex min-h-10 relative items-center justify-between gap-3 border-b border-base-muted-light bg-base-muted-superlight! px-4",
385
320
  "data-code-block-header": "",
386
321
  children: [
387
- /* @__PURE__ */ jsx7(CodeBlockHeaderMeta, { label, env }),
322
+ /* @__PURE__ */ jsx6(CodeBlockHeaderMeta, { label, env }),
388
323
  copyButton
389
324
  ]
390
325
  }
391
326
  ),
392
- /* @__PURE__ */ jsx7(
327
+ /* @__PURE__ */ jsx6(
393
328
  "pre",
394
329
  {
395
330
  ...props,
396
331
  ref: preRef,
397
- className: cmMerge3("doc-code-pre m-0 h-full overflow-x-auto bg-base-200! p-4 text-sm", className),
332
+ className: cmMerge2("doc-code-pre m-0 h-full overflow-x-auto bg-base-200! p-4 text-sm", className),
398
333
  "data-code-block-content": "",
399
334
  children
400
335
  }
@@ -404,6 +339,71 @@ var Pre = ({ children, className, ...props }) => {
404
339
  );
405
340
  };
406
341
 
342
+ // src/mdx/components/Alert.tsx
343
+ import cm2, { cmMerge as cmMerge3 } from "@classmatejs/react";
344
+ import { Check as Check2, CircleX, Info, TriangleAlert } from "lucide-react";
345
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
346
+ var alertIconMap = {
347
+ info: Info,
348
+ warning: TriangleAlert,
349
+ error: CircleX,
350
+ success: Check2
351
+ };
352
+ var Alert = ({
353
+ type = "info",
354
+ heading,
355
+ children,
356
+ icon = true
357
+ }) => {
358
+ const AlertIcon = icon === true ? alertIconMap[type] : typeof icon === "object" ? () => /* @__PURE__ */ jsx7(Fragment2, { children: icon }) : null;
359
+ const alertIconTextColorClass = {
360
+ info: "text-info",
361
+ warning: "text-warning",
362
+ error: "text-error",
363
+ success: "text-success"
364
+ }[type];
365
+ return /* @__PURE__ */ jsxs4(AlertOuter, { $variant: type, children: [
366
+ !!heading && AlertIcon && /* @__PURE__ */ jsxs4("div", { className: "mb-3 flex items-center gap-2", children: [
367
+ /* @__PURE__ */ jsx7(AlertIcon, { className: cmMerge3(alertIconTextColorClass, "float-left h-5 w-5") }),
368
+ /* @__PURE__ */ jsx7(AlertHeading, { children: heading })
369
+ ] }),
370
+ !(!!heading && AlertIcon) && !!heading && /* @__PURE__ */ jsx7(AlertHeading, { children: heading }),
371
+ !(!!heading && AlertIcon) && AlertIcon && /* @__PURE__ */ jsx7("div", { className: cmMerge3(alertIconTextColorClass, "float-left mr-2"), children: /* @__PURE__ */ jsx7(AlertIcon, { className: "mt-1 h-5 w-5" }) }),
372
+ children
373
+ ] });
374
+ };
375
+ var AlertOuter = cm2.section.variants({
376
+ base: `
377
+ p-4
378
+ mt-5
379
+ mb-5
380
+ border
381
+ rounded-lg
382
+ prose-p:last:mb-0
383
+ prose-p:mt-0
384
+ prose-headings:first:mt-0
385
+ prose-headings:last:mb-0
386
+ prose-ul:first:mt-0
387
+ prose-ul:last:mb-0
388
+ text-sm
389
+ `,
390
+ variants: {
391
+ $variant: {
392
+ info: "bg-info/10 border-info/30",
393
+ warning: "bg-warning/10 border-warning/30",
394
+ error: "bg-error/10 border-error/25",
395
+ success: "bg-success/10 border-success/35"
396
+ }
397
+ },
398
+ defaultVariants: {
399
+ $variant: "info"
400
+ }
401
+ });
402
+ var AlertHeading = cm2.header`
403
+ font-bold
404
+ text-base
405
+ `;
406
+
407
407
  // src/mdx/components/Link.tsx
408
408
  import { cmMerge as cmMerge4 } from "@classmatejs/react";
409
409
  import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
@@ -637,15 +637,15 @@ var StyledTable = cm3.table.variants({
637
637
  });
638
638
 
639
639
  export {
640
- Alert,
641
640
  ChoiceGroup,
642
641
  CodeBlockTransformer,
643
642
  FileAdded,
644
643
  FileRemoved,
645
644
  Pre,
645
+ Alert,
646
646
  Link,
647
647
  Overview,
648
648
  RepoLink,
649
649
  Table
650
650
  };
651
- //# sourceMappingURL=chunk-FARXFRHG.js.map
651
+ //# sourceMappingURL=chunk-4RLPVGMZ.js.map