blume 0.0.0 → 0.1.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.
- package/bin/blume.mjs +18 -0
- package/dist/cli/index.js +11989 -0
- package/dist/cli/index.js.map +141 -0
- package/docs/01-quickstart.mdx +99 -0
- package/docs/02-deployment.mdx +129 -0
- package/docs/advanced/api-reference.mdx +114 -0
- package/docs/advanced/blog.mdx +121 -0
- package/docs/advanced/changelog.mdx +113 -0
- package/docs/advanced/custom-pages.mdx +187 -0
- package/docs/advanced/meta.ts +7 -0
- package/docs/changelog/v0-1-0.mdx +12 -0
- package/docs/changelog/v0-2-0.mdx +16 -0
- package/docs/configuration/ai.mdx +228 -0
- package/docs/configuration/analytics.mdx +98 -0
- package/docs/configuration/customization.mdx +91 -0
- package/docs/configuration/export.mdx +70 -0
- package/docs/configuration/index.mdx +271 -0
- package/docs/configuration/meta.ts +15 -0
- package/docs/configuration/search.mdx +172 -0
- package/docs/configuration/seo.mdx +196 -0
- package/docs/configuration/theming.mdx +178 -0
- package/docs/content/components.mdx +565 -0
- package/docs/content/i18n.mdx +205 -0
- package/docs/content/index.mdx +161 -0
- package/docs/content/islands.mdx +94 -0
- package/docs/content/meta.mdx +119 -0
- package/docs/content/meta.ts +15 -0
- package/docs/content/navigation.mdx +168 -0
- package/docs/content/sources.mdx +216 -0
- package/docs/content/syntax.mdx +445 -0
- package/docs/index.mdx +112 -0
- package/docs/reference/cli.mdx +43 -0
- package/docs/reference/frontmatter.mdx +74 -0
- package/docs/reference/meta.ts +7 -0
- package/package.json +140 -6
- package/src/ai/ask.ts +93 -0
- package/src/ai/llms.ts +65 -0
- package/src/ai/markdown.ts +31 -0
- package/src/ai/mcp/data.ts +74 -0
- package/src/ai/mcp/discovery.ts +49 -0
- package/src/ai/mcp/server.ts +225 -0
- package/src/ai/mcp/tools.ts +47 -0
- package/src/assets/icon.png +0 -0
- package/src/astro/generate.ts +878 -0
- package/src/astro/index.ts +4 -0
- package/src/astro/integration.ts +74 -0
- package/src/astro/islands.ts +131 -0
- package/src/astro/markdown-negotiation.ts +68 -0
- package/src/astro/pages.ts +28 -0
- package/src/astro/templates.ts +1199 -0
- package/src/cli/commands/add.ts +81 -0
- package/src/cli/commands/build.ts +103 -0
- package/src/cli/commands/dev.ts +108 -0
- package/src/cli/commands/doctor.ts +74 -0
- package/src/cli/commands/eject.ts +57 -0
- package/src/cli/commands/init.ts +98 -0
- package/src/cli/commands/migrate.ts +39 -0
- package/src/cli/commands/preview.ts +39 -0
- package/src/cli/commands/sync.ts +52 -0
- package/src/cli/commands/validate.ts +60 -0
- package/src/cli/index.ts +35 -0
- package/src/cli/log.ts +37 -0
- package/src/cli/prepare.ts +80 -0
- package/src/components/Icon.astro +99 -0
- package/src/components/content/Accordion.astro +8 -0
- package/src/components/content/AccordionItem.astro +121 -0
- package/src/components/content/AutoTypeTable.astro +51 -0
- package/src/components/content/Badge.astro +124 -0
- package/src/components/content/Callout.astro +73 -0
- package/src/components/content/Card.astro +104 -0
- package/src/components/content/CardGroup.astro +14 -0
- package/src/components/content/CodeGroup.astro +13 -0
- package/src/components/content/Color.astro +15 -0
- package/src/components/content/ColorItem.astro +87 -0
- package/src/components/content/ColorRow.astro +10 -0
- package/src/components/content/Column.astro +6 -0
- package/src/components/content/Columns.astro +9 -0
- package/src/components/content/Expandable.astro +11 -0
- package/src/components/content/FileTree.astro +8 -0
- package/src/components/content/Frame.astro +70 -0
- package/src/components/content/GithubInfo.astro +110 -0
- package/src/components/content/Math.astro +24 -0
- package/src/components/content/Panel.astro +20 -0
- package/src/components/content/Prompt.astro +129 -0
- package/src/components/content/Step.astro +34 -0
- package/src/components/content/Steps.astro +20 -0
- package/src/components/content/Tab.astro +40 -0
- package/src/components/content/Tabs.astro +273 -0
- package/src/components/content/Tile.astro +42 -0
- package/src/components/content/Tooltip.astro +68 -0
- package/src/components/content/Tree.astro +300 -0
- package/src/components/content/TreeFile.astro +15 -0
- package/src/components/content/TreeFolder.astro +62 -0
- package/src/components/content/TypeTable.astro +106 -0
- package/src/components/content/Update.astro +66 -0
- package/src/components/content/Visibility.astro +12 -0
- package/src/components/content/Warning.astro +9 -0
- package/src/components/content/auto-type-table.ts +141 -0
- package/src/components/content/github-info.ts +79 -0
- package/src/components/content/mermaid-element.ts +68 -0
- package/src/components/github-mark.ts +9 -0
- package/src/components/index.ts +14 -0
- package/src/components/islands/AskAI.astro +12 -0
- package/src/components/islands/ask-ai.tsx +156 -0
- package/src/components/layout/Analytics.astro +63 -0
- package/src/components/layout/Banner.astro +50 -0
- package/src/components/layout/Breadcrumbs.astro +31 -0
- package/src/components/layout/Favicon.astro +15 -0
- package/src/components/layout/Fonts.astro +14 -0
- package/src/components/layout/Header.astro +188 -0
- package/src/components/layout/LanguageSwitcher.astro +56 -0
- package/src/components/layout/NavTree.astro +462 -0
- package/src/components/layout/PageActions.astro +438 -0
- package/src/components/layout/PageFeedback.astro +58 -0
- package/src/components/layout/Pagination.astro +56 -0
- package/src/components/layout/ReferenceLayout.astro +102 -0
- package/src/components/layout/RootLayout.astro +533 -0
- package/src/components/layout/Search.astro +608 -0
- package/src/components/layout/TableOfContents.astro +68 -0
- package/src/components/layout/analytics-client.ts +38 -0
- package/src/components/layout/nav-utils.ts +87 -0
- package/src/components/layout/overrides.ts +32 -0
- package/src/components/layout/search/algolia.ts +43 -0
- package/src/components/layout/search/endpoint.ts +22 -0
- package/src/components/layout/search/flexsearch.ts +52 -0
- package/src/components/layout/search/orama-cloud.ts +41 -0
- package/src/components/layout/search/orama.ts +26 -0
- package/src/components/layout/search/pagefind.ts +43 -0
- package/src/components/layout/search/types.ts +163 -0
- package/src/components/layout/search/typesense.ts +60 -0
- package/src/components/layout/toc-element.ts +108 -0
- package/src/core/bridge.ts +92 -0
- package/src/core/config.ts +112 -0
- package/src/core/content.ts +50 -0
- package/src/core/define-components.ts +34 -0
- package/src/core/define-meta.ts +20 -0
- package/src/core/deployment-env.ts +73 -0
- package/src/core/diagnostics.ts +104 -0
- package/src/core/graph.ts +128 -0
- package/src/core/i18n-ui.ts +171 -0
- package/src/core/i18n.ts +169 -0
- package/src/core/last-modified.ts +88 -0
- package/src/core/links.ts +336 -0
- package/src/core/load-module.ts +15 -0
- package/src/core/manifest.ts +126 -0
- package/src/core/meta.ts +97 -0
- package/src/core/navigation.ts +392 -0
- package/src/core/package-root.ts +37 -0
- package/src/core/project-graph.ts +153 -0
- package/src/core/project.ts +56 -0
- package/src/core/schema.ts +1057 -0
- package/src/core/server-features.ts +23 -0
- package/src/core/sources/assets.ts +77 -0
- package/src/core/sources/cache.ts +122 -0
- package/src/core/sources/filesystem.ts +99 -0
- package/src/core/sources/mdx-remote.ts +216 -0
- package/src/core/sources/mintlify.ts +161 -0
- package/src/core/sources/normalize.ts +227 -0
- package/src/core/sources/notion.ts +440 -0
- package/src/core/sources/portable-text.ts +143 -0
- package/src/core/sources/read.ts +36 -0
- package/src/core/sources/resolve.ts +158 -0
- package/src/core/sources/sanity.ts +218 -0
- package/src/core/sources/types.ts +105 -0
- package/src/core/types.ts +261 -0
- package/src/core/ui-packs/ar.ts +47 -0
- package/src/core/ui-packs/bg.ts +47 -0
- package/src/core/ui-packs/bn.ts +47 -0
- package/src/core/ui-packs/ca.ts +47 -0
- package/src/core/ui-packs/cs.ts +47 -0
- package/src/core/ui-packs/da.ts +47 -0
- package/src/core/ui-packs/de.ts +47 -0
- package/src/core/ui-packs/el.ts +47 -0
- package/src/core/ui-packs/es.ts +47 -0
- package/src/core/ui-packs/fa.ts +47 -0
- package/src/core/ui-packs/fi.ts +47 -0
- package/src/core/ui-packs/fr.ts +47 -0
- package/src/core/ui-packs/he.ts +47 -0
- package/src/core/ui-packs/hi.ts +47 -0
- package/src/core/ui-packs/hr.ts +47 -0
- package/src/core/ui-packs/hu.ts +47 -0
- package/src/core/ui-packs/id.ts +47 -0
- package/src/core/ui-packs/index.ts +87 -0
- package/src/core/ui-packs/it.ts +47 -0
- package/src/core/ui-packs/ja.ts +47 -0
- package/src/core/ui-packs/ko.ts +47 -0
- package/src/core/ui-packs/nl.ts +47 -0
- package/src/core/ui-packs/no.ts +47 -0
- package/src/core/ui-packs/pl.ts +47 -0
- package/src/core/ui-packs/pt-br.ts +47 -0
- package/src/core/ui-packs/pt.ts +47 -0
- package/src/core/ui-packs/ro.ts +47 -0
- package/src/core/ui-packs/ru.ts +47 -0
- package/src/core/ui-packs/sk.ts +47 -0
- package/src/core/ui-packs/sr.ts +47 -0
- package/src/core/ui-packs/sv.ts +47 -0
- package/src/core/ui-packs/th.ts +47 -0
- package/src/core/ui-packs/tr.ts +47 -0
- package/src/core/ui-packs/uk.ts +47 -0
- package/src/core/ui-packs/vi.ts +47 -0
- package/src/core/ui-packs/zh-tw.ts +47 -0
- package/src/core/ui-packs/zh.ts +47 -0
- package/src/core/version.ts +23 -0
- package/src/deploy/robots.ts +20 -0
- package/src/deploy/rss.ts +128 -0
- package/src/deploy/sitemap.ts +28 -0
- package/src/index.ts +27 -0
- package/src/markdown/code-title.ts +71 -0
- package/src/markdown/directives.ts +83 -0
- package/src/markdown/heading-anchors.ts +137 -0
- package/src/markdown/index.ts +159 -0
- package/src/markdown/inline-code.ts +108 -0
- package/src/markdown/language-icon.ts +172 -0
- package/src/markdown/math.ts +32 -0
- package/src/markdown/mdast.ts +48 -0
- package/src/markdown/mermaid.ts +37 -0
- package/src/markdown/package-commands.ts +159 -0
- package/src/markdown/package-install.ts +40 -0
- package/src/migrate/fumadocs/config.ts +106 -0
- package/src/migrate/fumadocs/content.ts +365 -0
- package/src/migrate/fumadocs/frontmatter.ts +18 -0
- package/src/migrate/fumadocs/index.ts +252 -0
- package/src/migrate/fumadocs/meta.ts +114 -0
- package/src/migrate/migrate.ts +53 -0
- package/src/migrate/mintlify/config.ts +1040 -0
- package/src/migrate/mintlify/content.ts +98 -0
- package/src/migrate/mintlify/frontmatter.ts +126 -0
- package/src/migrate/mintlify/i18n.ts +51 -0
- package/src/migrate/mintlify/icons.ts +128 -0
- package/src/migrate/mintlify/index.ts +266 -0
- package/src/migrate/mintlify/snippets.ts +305 -0
- package/src/migrate/mintlify/transform.ts +81 -0
- package/src/migrate/nextra/content.ts +46 -0
- package/src/migrate/nextra/frontmatter.ts +40 -0
- package/src/migrate/nextra/index.ts +374 -0
- package/src/migrate/nextra/meta.ts +266 -0
- package/src/migrate/shared.ts +623 -0
- package/src/migrate/starlight/config.ts +459 -0
- package/src/migrate/starlight/content.ts +78 -0
- package/src/migrate/starlight/frontmatter.ts +111 -0
- package/src/migrate/starlight/i18n.ts +54 -0
- package/src/migrate/starlight/index.ts +131 -0
- package/src/og/card.ts +92 -0
- package/src/og/index.ts +2 -0
- package/src/openapi/scalar.ts +246 -0
- package/src/registry/eject.ts +263 -0
- package/src/registry/registry.ts +100 -0
- package/src/registry/rewrite-imports.ts +39 -0
- package/src/runtime/index.ts +14 -0
- package/src/search/build.ts +23 -0
- package/src/search/documents.ts +165 -0
- package/src/search/orama-index.ts +66 -0
- package/src/search/providers.ts +91 -0
- package/src/search/sync/algolia.ts +30 -0
- package/src/search/sync/index.ts +50 -0
- package/src/search/sync/orama-cloud.ts +40 -0
- package/src/search/sync/typesense.ts +65 -0
- package/src/seo/jsonld.ts +113 -0
- package/src/theme/entry.ts +608 -0
- package/src/theme/fonts.ts +198 -0
- package/src/theme/icons.ts +184 -0
- package/src/theme/palette.ts +143 -0
- package/src/theme/twoslash.ts +81 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import { join } from "pathe";
|
|
5
|
+
|
|
6
|
+
import { BlumeError } from "../../core/diagnostics.ts";
|
|
7
|
+
import { validateLinks } from "../../core/links.ts";
|
|
8
|
+
import { scanProject } from "../../core/project-graph.ts";
|
|
9
|
+
import type { Diagnostic } from "../../core/types.ts";
|
|
10
|
+
import { logger, reportDiagnostics } from "../log.ts";
|
|
11
|
+
|
|
12
|
+
export const validateCommand = defineCommand({
|
|
13
|
+
args: {
|
|
14
|
+
external: {
|
|
15
|
+
description: "Check external (HTTP) links over the network.",
|
|
16
|
+
type: "boolean",
|
|
17
|
+
},
|
|
18
|
+
strict: {
|
|
19
|
+
description: "Treat warnings as errors.",
|
|
20
|
+
type: "boolean",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
meta: {
|
|
24
|
+
description: "Validate internal, anchor, asset, and external links.",
|
|
25
|
+
name: "validate",
|
|
26
|
+
},
|
|
27
|
+
async run({ args }) {
|
|
28
|
+
const root = process.cwd();
|
|
29
|
+
const diagnostics: Diagnostic[] = [];
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const project = await scanProject(root, { mode: "build" });
|
|
33
|
+
// Surface content/graph problems too: a page that fails to parse is a
|
|
34
|
+
// link-validation blind spot, so silently passing would be misleading.
|
|
35
|
+
diagnostics.push(...project.diagnostics);
|
|
36
|
+
|
|
37
|
+
const publicDir = join(root, "public");
|
|
38
|
+
diagnostics.push(
|
|
39
|
+
...(await validateLinks(project.graph, {
|
|
40
|
+
checkExternal: Boolean(args.external),
|
|
41
|
+
publicDir: existsSync(publicDir) ? publicDir : null,
|
|
42
|
+
}))
|
|
43
|
+
);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error instanceof BlumeError) {
|
|
46
|
+
diagnostics.push(error.diagnostic);
|
|
47
|
+
} else {
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const hadErrors = reportDiagnostics(diagnostics, root);
|
|
53
|
+
if (diagnostics.length === 0) {
|
|
54
|
+
logger.success("No broken links found.");
|
|
55
|
+
}
|
|
56
|
+
if (hadErrors || (Boolean(args.strict) && diagnostics.length > 0)) {
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
});
|
package/src/cli/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineCommand, runMain } from "citty";
|
|
2
|
+
|
|
3
|
+
import { getBlumeVersion } from "../core/version.ts";
|
|
4
|
+
import { addCommand } from "./commands/add.ts";
|
|
5
|
+
import { buildCommand } from "./commands/build.ts";
|
|
6
|
+
import { devCommand } from "./commands/dev.ts";
|
|
7
|
+
import { doctorCommand } from "./commands/doctor.ts";
|
|
8
|
+
import { ejectCommand } from "./commands/eject.ts";
|
|
9
|
+
import { initCommand } from "./commands/init.ts";
|
|
10
|
+
import { migrateCommand } from "./commands/migrate.ts";
|
|
11
|
+
import { previewCommand } from "./commands/preview.ts";
|
|
12
|
+
import { syncCommand } from "./commands/sync.ts";
|
|
13
|
+
import { validateCommand } from "./commands/validate.ts";
|
|
14
|
+
|
|
15
|
+
const main = defineCommand({
|
|
16
|
+
meta: {
|
|
17
|
+
description: "Markdown-first documentation powered by Astro and Vite.",
|
|
18
|
+
name: "blume",
|
|
19
|
+
version: getBlumeVersion(),
|
|
20
|
+
},
|
|
21
|
+
subCommands: {
|
|
22
|
+
add: addCommand,
|
|
23
|
+
build: buildCommand,
|
|
24
|
+
dev: devCommand,
|
|
25
|
+
doctor: doctorCommand,
|
|
26
|
+
eject: ejectCommand,
|
|
27
|
+
init: initCommand,
|
|
28
|
+
migrate: migrateCommand,
|
|
29
|
+
preview: previewCommand,
|
|
30
|
+
sync: syncCommand,
|
|
31
|
+
validate: validateCommand,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
runMain(main);
|
package/src/cli/log.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { consola } from "consola";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
countBySeverity,
|
|
5
|
+
formatDiagnostic,
|
|
6
|
+
hasErrors,
|
|
7
|
+
} from "../core/diagnostics.ts";
|
|
8
|
+
import type { Diagnostic } from "../core/types.ts";
|
|
9
|
+
|
|
10
|
+
export const logger = consola.withTag("blume");
|
|
11
|
+
|
|
12
|
+
/** Print a batch of diagnostics and return whether any were errors. */
|
|
13
|
+
export const reportDiagnostics = (
|
|
14
|
+
diagnostics: Diagnostic[],
|
|
15
|
+
root?: string
|
|
16
|
+
): boolean => {
|
|
17
|
+
if (diagnostics.length === 0) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (const diagnostic of diagnostics) {
|
|
22
|
+
process.stderr.write(`${formatDiagnostic(diagnostic, root)}\n`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const counts = countBySeverity(diagnostics);
|
|
26
|
+
const summary = [
|
|
27
|
+
counts.error ? `${counts.error} error(s)` : null,
|
|
28
|
+
counts.warning ? `${counts.warning} warning(s)` : null,
|
|
29
|
+
]
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
.join(", ");
|
|
32
|
+
if (summary) {
|
|
33
|
+
process.stderr.write(`\n${summary}\n`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return hasErrors(diagnostics);
|
|
37
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { generateRuntime } from "../astro/generate.ts";
|
|
2
|
+
import { BlumeError, hasErrors } from "../core/diagnostics.ts";
|
|
3
|
+
import { scanProject } from "../core/project-graph.ts";
|
|
4
|
+
import type { BlumeProject, BuildMode } from "../core/project-graph.ts";
|
|
5
|
+
import { serverFeatures } from "../core/server-features.ts";
|
|
6
|
+
import { logger, reportDiagnostics } from "./log.ts";
|
|
7
|
+
|
|
8
|
+
export interface PrepareOptions {
|
|
9
|
+
root: string;
|
|
10
|
+
mode?: BuildMode;
|
|
11
|
+
strict?: boolean;
|
|
12
|
+
/** Local dev server URL, used as the `deployment.site` fallback (dev only). */
|
|
13
|
+
devServerUrl?: string;
|
|
14
|
+
/** Render drafts and fetch unpublished CMS content. */
|
|
15
|
+
preview?: boolean;
|
|
16
|
+
/** Force remote sources to re-fetch instead of serving the cached snapshot. */
|
|
17
|
+
refresh?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Scan the project, surface diagnostics, and (re)generate the `.blume` runtime.
|
|
22
|
+
* In strict mode, any error aborts. Returns the resolved project.
|
|
23
|
+
*/
|
|
24
|
+
export const prepareProject = async (
|
|
25
|
+
options: PrepareOptions
|
|
26
|
+
): Promise<BlumeProject> => {
|
|
27
|
+
let project: BlumeProject;
|
|
28
|
+
try {
|
|
29
|
+
project = await scanProject(options.root, {
|
|
30
|
+
devServerUrl: options.devServerUrl,
|
|
31
|
+
mode: options.mode,
|
|
32
|
+
preview: options.preview,
|
|
33
|
+
refresh: options.refresh,
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error instanceof BlumeError) {
|
|
37
|
+
reportDiagnostics([error.diagnostic], options.root);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Hard gate: server-only features cannot ship in a static build.
|
|
44
|
+
if (
|
|
45
|
+
options.mode === "build" &&
|
|
46
|
+
project.config.deployment.output === "static"
|
|
47
|
+
) {
|
|
48
|
+
const features = serverFeatures(project.config);
|
|
49
|
+
if (features.length > 0) {
|
|
50
|
+
reportDiagnostics(
|
|
51
|
+
[
|
|
52
|
+
{
|
|
53
|
+
code: "BLUME_SERVER_FEATURE_REQUIRED",
|
|
54
|
+
message: `${features.join(", ")} require server output, but deployment.output is "static".`,
|
|
55
|
+
severity: "error",
|
|
56
|
+
suggestion:
|
|
57
|
+
'Set deployment: { output: "server", adapter: "vercel" } in blume.config.ts.',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
options.root
|
|
61
|
+
);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const hadErrors = reportDiagnostics(project.diagnostics, options.root);
|
|
67
|
+
if (hadErrors && options.strict) {
|
|
68
|
+
logger.error("Aborting due to errors (strict mode).");
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
if (hasErrors(project.diagnostics) && !options.strict) {
|
|
72
|
+
logger.warn("Continuing despite errors. Use --strict to fail the build.");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const { warnings } = await generateRuntime(project);
|
|
76
|
+
for (const warning of warnings) {
|
|
77
|
+
logger.warn(warning);
|
|
78
|
+
}
|
|
79
|
+
return project;
|
|
80
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { resolveIcon } from "../theme/icons.ts";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
name?: unknown;
|
|
6
|
+
icon?: unknown;
|
|
7
|
+
iconType?: string;
|
|
8
|
+
size?: number;
|
|
9
|
+
class?: string;
|
|
10
|
+
className?: string;
|
|
11
|
+
color?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
color,
|
|
17
|
+
icon,
|
|
18
|
+
iconType,
|
|
19
|
+
name,
|
|
20
|
+
size = 16,
|
|
21
|
+
class: astroClass,
|
|
22
|
+
className,
|
|
23
|
+
label,
|
|
24
|
+
} = Astro.props;
|
|
25
|
+
const rawIcon = name ?? icon;
|
|
26
|
+
const customIcon =
|
|
27
|
+
rawIcon !== undefined && rawIcon !== null && typeof rawIcon !== "string"
|
|
28
|
+
? rawIcon
|
|
29
|
+
: null;
|
|
30
|
+
const iconName = typeof rawIcon === "string" ? rawIcon : null;
|
|
31
|
+
const rawSvg =
|
|
32
|
+
iconName && /^\s*<svg[\s\S]*<\/svg>\s*$/u.test(iconName)
|
|
33
|
+
? iconName.trim()
|
|
34
|
+
: null;
|
|
35
|
+
const isImageIcon = (value: string): boolean =>
|
|
36
|
+
/^(?:https?:\/\/|data:image\/|\/|\.{1,2}\/)/u.test(value) ||
|
|
37
|
+
/\.(?:avif|gif|jpe?g|png|svg|webp)$/iu.test(value);
|
|
38
|
+
const imageSrc = iconName && !rawSvg && isImageIcon(iconName) ? iconName : null;
|
|
39
|
+
const resolvedIcon =
|
|
40
|
+
iconName && !(imageSrc || rawSvg) ? resolveIcon(iconName, iconType) : null;
|
|
41
|
+
const markup = resolvedIcon?.markup;
|
|
42
|
+
const resolvedClass = astroClass ?? className;
|
|
43
|
+
const customStyle = `display:inline-flex;width:${size}px;height:${size}px;${
|
|
44
|
+
color ? `color:${color}` : ""
|
|
45
|
+
}`;
|
|
46
|
+
const style = color ? `color:${color}` : undefined;
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
customIcon ? (
|
|
51
|
+
<span
|
|
52
|
+
aria-hidden={label ? undefined : "true"}
|
|
53
|
+
aria-label={label}
|
|
54
|
+
class={resolvedClass}
|
|
55
|
+
role={label ? "img" : undefined}
|
|
56
|
+
style={customStyle}
|
|
57
|
+
>
|
|
58
|
+
{customIcon}
|
|
59
|
+
</span>
|
|
60
|
+
) : rawSvg ? (
|
|
61
|
+
<span
|
|
62
|
+
aria-hidden={label ? undefined : "true"}
|
|
63
|
+
aria-label={label}
|
|
64
|
+
class={resolvedClass}
|
|
65
|
+
role={label ? "img" : undefined}
|
|
66
|
+
set:html={rawSvg}
|
|
67
|
+
style={customStyle}
|
|
68
|
+
/>
|
|
69
|
+
) : imageSrc ? (
|
|
70
|
+
<img
|
|
71
|
+
alt={label ?? ""}
|
|
72
|
+
aria-hidden={label ? undefined : "true"}
|
|
73
|
+
class={resolvedClass}
|
|
74
|
+
height={size}
|
|
75
|
+
src={imageSrc}
|
|
76
|
+
width={size}
|
|
77
|
+
/>
|
|
78
|
+
) : (
|
|
79
|
+
markup && (
|
|
80
|
+
<svg
|
|
81
|
+
aria-hidden={label ? undefined : "true"}
|
|
82
|
+
aria-label={label}
|
|
83
|
+
class={resolvedClass}
|
|
84
|
+
fill="none"
|
|
85
|
+
height={size}
|
|
86
|
+
role={label ? "img" : undefined}
|
|
87
|
+
set:html={markup}
|
|
88
|
+
stroke="currentColor"
|
|
89
|
+
stroke-linecap="round"
|
|
90
|
+
stroke-linejoin="round"
|
|
91
|
+
stroke-width="2"
|
|
92
|
+
style={style}
|
|
93
|
+
viewBox="0 0 24 24"
|
|
94
|
+
width={size}
|
|
95
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
96
|
+
/>
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Icon from "../Icon.astro";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
title: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
id?: string;
|
|
9
|
+
icon?: string;
|
|
10
|
+
iconType?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { defaultOpen = false, description, icon, iconType, id, title } =
|
|
14
|
+
Astro.props;
|
|
15
|
+
const slugify = (value: string): string =>
|
|
16
|
+
value
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.trim()
|
|
19
|
+
.replaceAll(/[^\w\s-]/gu, "")
|
|
20
|
+
.replaceAll(/[\s_]+/gu, "-")
|
|
21
|
+
.replaceAll(/-+/gu, "-")
|
|
22
|
+
.replaceAll(/^-|-$/gu, "");
|
|
23
|
+
const accordionId = id ?? slugify(title);
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
<details
|
|
27
|
+
class="not-prose group"
|
|
28
|
+
data-blume-accordion
|
|
29
|
+
id={accordionId}
|
|
30
|
+
open={defaultOpen}
|
|
31
|
+
>
|
|
32
|
+
<summary
|
|
33
|
+
class="flex cursor-pointer list-none items-center justify-between p-4 font-medium [&::-webkit-details-marker]:hidden"
|
|
34
|
+
>
|
|
35
|
+
<span class="flex min-w-0 items-start gap-2">
|
|
36
|
+
{
|
|
37
|
+
icon && (
|
|
38
|
+
<Icon
|
|
39
|
+
class="mt-0.5 shrink-0 text-muted-foreground"
|
|
40
|
+
iconType={iconType}
|
|
41
|
+
name={icon}
|
|
42
|
+
size={16}
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
<span class="min-w-0">
|
|
47
|
+
<span class="block">{title}</span>
|
|
48
|
+
{
|
|
49
|
+
description && (
|
|
50
|
+
<span class="block font-normal text-muted-foreground text-sm">
|
|
51
|
+
{description}
|
|
52
|
+
</span>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
</span>
|
|
56
|
+
</span>
|
|
57
|
+
<Icon
|
|
58
|
+
class="text-muted-foreground transition-transform group-open:rotate-180"
|
|
59
|
+
name="chevron-down"
|
|
60
|
+
size={16}
|
|
61
|
+
/>
|
|
62
|
+
</summary>
|
|
63
|
+
<div class="px-4 pb-4 [&>:first-child]:mt-0! [&>:last-child]:mb-0!">
|
|
64
|
+
<slot />
|
|
65
|
+
</div>
|
|
66
|
+
</details>
|
|
67
|
+
|
|
68
|
+
<script>
|
|
69
|
+
const state = window as Window & { __blumeAccordionHash?: boolean };
|
|
70
|
+
if (!state.__blumeAccordionHash) {
|
|
71
|
+
state.__blumeAccordionHash = true;
|
|
72
|
+
|
|
73
|
+
const accordionFromHash = () => {
|
|
74
|
+
const id = decodeURIComponent(window.location.hash.slice(1));
|
|
75
|
+
if (!id) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
return document.getElementById(id)?.matches("[data-blume-accordion]")
|
|
79
|
+
? (document.getElementById(id) as HTMLDetailsElement)
|
|
80
|
+
: null;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const openHashAccordion = () => {
|
|
84
|
+
const accordion = accordionFromHash();
|
|
85
|
+
if (!accordion) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
accordion.open = true;
|
|
89
|
+
requestAnimationFrame(() => {
|
|
90
|
+
accordion.scrollIntoView({ block: "start" });
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
document.addEventListener(
|
|
95
|
+
"toggle",
|
|
96
|
+
(event) => {
|
|
97
|
+
const accordion = event.target;
|
|
98
|
+
if (
|
|
99
|
+
!(accordion instanceof HTMLDetailsElement) ||
|
|
100
|
+
!accordion.matches("[data-blume-accordion]") ||
|
|
101
|
+
!accordion.open ||
|
|
102
|
+
!accordion.id
|
|
103
|
+
) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
history.replaceState(null, "", `#${encodeURIComponent(accordion.id)}`);
|
|
108
|
+
},
|
|
109
|
+
true
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
window.addEventListener("hashchange", openHashAccordion);
|
|
113
|
+
if (document.readyState === "loading") {
|
|
114
|
+
document.addEventListener("DOMContentLoaded", openHashAccordion, {
|
|
115
|
+
once: true,
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
openHashAccordion();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
</script>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Generate a <TypeTable> from a TypeScript interface or type alias. Point it at
|
|
3
|
+
// a file (`path`, relative to the project root) and a type `name`, or pass inline
|
|
4
|
+
// source via `type`. Extraction runs at build time through the TypeScript
|
|
5
|
+
// compiler API; failures degrade to an inline notice rather than breaking the
|
|
6
|
+
// build.
|
|
7
|
+
import { extractTypeTable } from "./auto-type-table.ts";
|
|
8
|
+
import TypeTable from "./TypeTable.astro";
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
name: string;
|
|
12
|
+
path?: string;
|
|
13
|
+
type?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { name, path, type: source } = Astro.props;
|
|
17
|
+
|
|
18
|
+
let typeMap: Record<
|
|
19
|
+
string,
|
|
20
|
+
{ default?: string; description?: string; required: boolean; type: string }
|
|
21
|
+
> = {};
|
|
22
|
+
let error: string | undefined;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const rows = await extractTypeTable({ name, path, source });
|
|
26
|
+
typeMap = Object.fromEntries(
|
|
27
|
+
rows.map((row) => [
|
|
28
|
+
row.name,
|
|
29
|
+
{
|
|
30
|
+
default: row.default,
|
|
31
|
+
description: row.description,
|
|
32
|
+
required: row.required,
|
|
33
|
+
type: row.type,
|
|
34
|
+
},
|
|
35
|
+
])
|
|
36
|
+
);
|
|
37
|
+
} catch (cause) {
|
|
38
|
+
error = cause instanceof Error ? cause.message : String(cause);
|
|
39
|
+
}
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
{
|
|
43
|
+
error ? (
|
|
44
|
+
<div class="not-prose my-6 rounded-blume border border-border px-3 py-2 text-muted-foreground text-sm">
|
|
45
|
+
Could not generate a type table for <code class="font-mono">{name}</code>:{" "}
|
|
46
|
+
{error}
|
|
47
|
+
</div>
|
|
48
|
+
) : (
|
|
49
|
+
<TypeTable type={typeMap} />
|
|
50
|
+
)
|
|
51
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Icon from "../Icon.astro";
|
|
3
|
+
|
|
4
|
+
type BadgeVariant = "default" | "accent" | "success" | "warning" | "danger";
|
|
5
|
+
type BadgeSize = "xs" | "sm" | "md" | "lg";
|
|
6
|
+
type BadgeShape = "rounded" | "pill";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
variant?: BadgeVariant;
|
|
10
|
+
color?: string;
|
|
11
|
+
disabled?: boolean | string;
|
|
12
|
+
icon?: unknown;
|
|
13
|
+
iconType?: string;
|
|
14
|
+
shape?: BadgeShape;
|
|
15
|
+
size?: BadgeSize;
|
|
16
|
+
stroke?: boolean | string;
|
|
17
|
+
tooltip?: string;
|
|
18
|
+
class?: string;
|
|
19
|
+
className?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
color,
|
|
24
|
+
disabled = false,
|
|
25
|
+
icon,
|
|
26
|
+
iconType,
|
|
27
|
+
shape = "rounded",
|
|
28
|
+
size = "md",
|
|
29
|
+
stroke = false,
|
|
30
|
+
tooltip,
|
|
31
|
+
variant = "default",
|
|
32
|
+
class: astroClass,
|
|
33
|
+
className,
|
|
34
|
+
} = Astro.props;
|
|
35
|
+
|
|
36
|
+
const activeStroke = stroke === true || stroke === "true";
|
|
37
|
+
const isDisabled = disabled === true || disabled === "true";
|
|
38
|
+
const colorName =
|
|
39
|
+
color ??
|
|
40
|
+
{
|
|
41
|
+
accent: "blue",
|
|
42
|
+
danger: "red",
|
|
43
|
+
default: "gray",
|
|
44
|
+
success: "green",
|
|
45
|
+
warning: "orange",
|
|
46
|
+
}[variant];
|
|
47
|
+
const customColor = colorName.startsWith("#") ? colorName : null;
|
|
48
|
+
|
|
49
|
+
const filledColorClass: Record<string, string> = {
|
|
50
|
+
blue: "bg-blue-500/15 text-blue-700 dark:text-blue-300",
|
|
51
|
+
gray: "bg-muted text-muted-foreground",
|
|
52
|
+
green: "bg-green-500/15 text-green-700 dark:text-green-300",
|
|
53
|
+
orange: "bg-orange-500/15 text-orange-700 dark:text-orange-300",
|
|
54
|
+
purple: "bg-purple-500/15 text-purple-700 dark:text-purple-300",
|
|
55
|
+
red: "bg-red-500/15 text-red-700 dark:text-red-300",
|
|
56
|
+
surface: "bg-background text-muted-foreground ring-1 ring-border",
|
|
57
|
+
"surface-destructive":
|
|
58
|
+
"bg-background text-red-700 ring-1 ring-red-500/30 dark:text-red-300",
|
|
59
|
+
white: "bg-white text-muted-foreground ring-1 ring-border dark:bg-white/10",
|
|
60
|
+
"white-destructive":
|
|
61
|
+
"bg-white text-red-700 ring-1 ring-red-500/30 dark:bg-white/10 dark:text-red-300",
|
|
62
|
+
yellow: "bg-yellow-500/20 text-yellow-800 dark:text-yellow-300",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const strokeColorClass: Record<string, string> = {
|
|
66
|
+
blue: "border-blue-500/40 text-blue-700 dark:text-blue-300",
|
|
67
|
+
gray: "border-border text-muted-foreground",
|
|
68
|
+
green: "border-green-500/40 text-green-700 dark:text-green-300",
|
|
69
|
+
orange: "border-orange-500/40 text-orange-700 dark:text-orange-300",
|
|
70
|
+
purple: "border-purple-500/40 text-purple-700 dark:text-purple-300",
|
|
71
|
+
red: "border-red-500/40 text-red-700 dark:text-red-300",
|
|
72
|
+
surface: "border-border text-muted-foreground",
|
|
73
|
+
"surface-destructive": "border-red-500/40 text-red-700 dark:text-red-300",
|
|
74
|
+
white: "border-border text-muted-foreground",
|
|
75
|
+
"white-destructive": "border-red-500/40 text-red-700 dark:text-red-300",
|
|
76
|
+
yellow: "border-yellow-500/40 text-yellow-800 dark:text-yellow-300",
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const sizeClass: Record<BadgeSize, string> = {
|
|
80
|
+
lg: "gap-1.5 px-2.5 py-1 text-sm",
|
|
81
|
+
md: "gap-1 px-2 py-0.5 text-xs",
|
|
82
|
+
sm: "gap-1 px-1.5 py-0.5 text-[0.6875rem]",
|
|
83
|
+
xs: "gap-0.5 px-1.5 py-px text-[0.625rem]",
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const iconSize: Record<BadgeSize, number> = {
|
|
87
|
+
lg: 14,
|
|
88
|
+
md: 12,
|
|
89
|
+
sm: 11,
|
|
90
|
+
xs: 10,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const shapeClass: Record<BadgeShape, string> = {
|
|
94
|
+
pill: "rounded-full",
|
|
95
|
+
rounded: "rounded-md",
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const resolvedClass = astroClass ?? className;
|
|
99
|
+
const colorClass = activeStroke
|
|
100
|
+
? strokeColorClass[colorName] ?? strokeColorClass.gray
|
|
101
|
+
: filledColorClass[colorName] ?? filledColorClass.gray;
|
|
102
|
+
const customStyle = customColor
|
|
103
|
+
? activeStroke
|
|
104
|
+
? `border-color:${customColor};color:${customColor}`
|
|
105
|
+
: `background:${customColor}20;color:${customColor}`
|
|
106
|
+
: undefined;
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
<span
|
|
110
|
+
class:list={[
|
|
111
|
+
"not-prose inline-flex w-fit items-center border font-medium leading-5",
|
|
112
|
+
activeStroke ? "bg-transparent" : "border-transparent",
|
|
113
|
+
colorClass,
|
|
114
|
+
sizeClass[size],
|
|
115
|
+
shapeClass[shape],
|
|
116
|
+
isDisabled ? "opacity-50" : "",
|
|
117
|
+
resolvedClass,
|
|
118
|
+
]}
|
|
119
|
+
style={customStyle}
|
|
120
|
+
title={tooltip}
|
|
121
|
+
>
|
|
122
|
+
{icon && <Icon icon={icon} iconType={iconType} size={iconSize[size]} />}
|
|
123
|
+
<slot />
|
|
124
|
+
</span>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Icon from "../Icon.astro";
|
|
3
|
+
|
|
4
|
+
type CalloutType =
|
|
5
|
+
| "info"
|
|
6
|
+
| "note"
|
|
7
|
+
| "tip"
|
|
8
|
+
| "success"
|
|
9
|
+
| "check"
|
|
10
|
+
| "warning"
|
|
11
|
+
| "danger";
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
type?: CalloutType;
|
|
15
|
+
title?: string;
|
|
16
|
+
icon?: unknown;
|
|
17
|
+
iconType?: string;
|
|
18
|
+
color?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { color, icon, iconType, type = "info", title } = Astro.props;
|
|
22
|
+
|
|
23
|
+
const iconByType: Record<CalloutType, string> = {
|
|
24
|
+
check: "circle-check",
|
|
25
|
+
danger: "circle-x",
|
|
26
|
+
info: "info",
|
|
27
|
+
note: "info",
|
|
28
|
+
success: "circle-check",
|
|
29
|
+
tip: "lightbulb",
|
|
30
|
+
warning: "triangle-alert",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const variantClass: Record<CalloutType, string> = {
|
|
34
|
+
check: "border-green-500/25 bg-green-500/10",
|
|
35
|
+
danger: "border-red-500/25 bg-red-500/10",
|
|
36
|
+
info: "border-blue-500/25 bg-blue-500/10",
|
|
37
|
+
note: "border-border bg-muted",
|
|
38
|
+
success: "border-green-500/25 bg-green-500/10",
|
|
39
|
+
tip: "border-accent/25 bg-accent/10",
|
|
40
|
+
warning: "border-amber-500/25 bg-amber-500/10",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const iconClass: Record<CalloutType, string> = {
|
|
44
|
+
check: "text-green-600 dark:text-green-400",
|
|
45
|
+
danger: "text-red-600 dark:text-red-400",
|
|
46
|
+
info: "text-blue-600 dark:text-blue-400",
|
|
47
|
+
note: "text-muted-foreground/70",
|
|
48
|
+
success: "text-green-600 dark:text-green-400",
|
|
49
|
+
tip: "text-accent",
|
|
50
|
+
warning: "text-amber-600 dark:text-amber-400",
|
|
51
|
+
};
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
<aside
|
|
55
|
+
class:list={[
|
|
56
|
+
"not-prose my-5 flex flex-row items-start gap-2 rounded-blume border px-4 py-3 font-sans text-muted-foreground text-sm leading-6 [&_a]:underline [&_a]:decoration-current/50 [&_code]:font-mono",
|
|
57
|
+
color ? "bg-background" : variantClass[type],
|
|
58
|
+
]}
|
|
59
|
+
style={color ? `border:1px solid ${color};color:${color}` : undefined}
|
|
60
|
+
>
|
|
61
|
+
<span class:list={["mt-0.5 shrink-0", color ? "" : iconClass[type]]}>
|
|
62
|
+
<Icon
|
|
63
|
+
color={color}
|
|
64
|
+
icon={icon ?? iconByType[type]}
|
|
65
|
+
iconType={iconType}
|
|
66
|
+
size={16}
|
|
67
|
+
/>
|
|
68
|
+
</span>
|
|
69
|
+
<div class="min-w-0 flex-1 [&>:first-child]:mt-0! [&>:last-child]:mb-0!">
|
|
70
|
+
{title && <p class="mb-1 font-semibold text-foreground">{title}</p>}
|
|
71
|
+
<slot />
|
|
72
|
+
</div>
|
|
73
|
+
</aside>
|