blume 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/cli/index.js +747 -471
  2. package/dist/cli/index.js.map +45 -38
  3. package/dist/types/core/schema.d.ts +289 -278
  4. package/dist/types/migrate/mintlify/assets.d.ts +8 -0
  5. package/docs/01-quickstart.mdx +5 -16
  6. package/docs/02-deployment.mdx +21 -54
  7. package/docs/advanced/api-reference.mdx +10 -37
  8. package/docs/advanced/blog.mdx +9 -25
  9. package/docs/advanced/changelog.mdx +10 -33
  10. package/docs/advanced/custom-pages.mdx +21 -78
  11. package/docs/configuration/ai.mdx +42 -103
  12. package/docs/configuration/analytics.mdx +20 -38
  13. package/docs/configuration/customization.mdx +40 -73
  14. package/docs/configuration/export.mdx +9 -34
  15. package/docs/configuration/index.mdx +67 -87
  16. package/docs/configuration/search.mdx +17 -54
  17. package/docs/configuration/seo.mdx +17 -48
  18. package/docs/configuration/theming.mdx +20 -42
  19. package/docs/content/components.mdx +42 -101
  20. package/docs/content/i18n.mdx +21 -72
  21. package/docs/content/index.mdx +18 -48
  22. package/docs/content/islands.mdx +25 -52
  23. package/docs/content/meta.mdx +23 -50
  24. package/docs/content/navigation.mdx +23 -62
  25. package/docs/content/sources.mdx +20 -83
  26. package/docs/content/syntax.mdx +37 -105
  27. package/docs/index.mdx +11 -40
  28. package/docs/reference/cli.mdx +18 -29
  29. package/docs/reference/frontmatter.mdx +2 -5
  30. package/package.json +1 -1
  31. package/src/astro/integration.ts +26 -3
  32. package/src/astro/islands.ts +6 -2
  33. package/src/astro/markdown-negotiation.ts +17 -3
  34. package/src/astro/pages.ts +6 -1
  35. package/src/astro/static-assets.ts +117 -0
  36. package/src/astro/templates.ts +48 -26
  37. package/src/cli/args.ts +23 -0
  38. package/src/cli/commands/build.ts +23 -0
  39. package/src/cli/commands/dev.ts +11 -2
  40. package/src/cli/commands/doctor.ts +10 -1
  41. package/src/cli/commands/eject.ts +3 -1
  42. package/src/cli/commands/init.ts +21 -1
  43. package/src/cli/commands/preview.ts +2 -1
  44. package/src/cli/commands/validate.ts +12 -1
  45. package/src/cli/dev-lock.ts +84 -0
  46. package/src/cli/log.ts +11 -0
  47. package/src/components/BlumePage.astro +2 -0
  48. package/src/components/content/YouTube.astro +35 -0
  49. package/src/components/content/youtube.ts +46 -0
  50. package/src/components/islands/ask-ai.tsx +14 -14
  51. package/src/components/props.ts +3 -0
  52. package/src/core/assets.ts +31 -0
  53. package/src/core/bridge.ts +10 -0
  54. package/src/core/builtin-tags.ts +1 -0
  55. package/src/core/diagnostics.ts +6 -1
  56. package/src/core/gitignore.ts +30 -0
  57. package/src/core/links.ts +60 -19
  58. package/src/core/schema.ts +7 -0
  59. package/src/core/sources/mdx-remote.ts +54 -8
  60. package/src/core/sources/normalize.ts +6 -1
  61. package/src/core/sources/notion.ts +49 -5
  62. package/src/core/sources/sanity.ts +5 -1
  63. package/src/deploy/rss.ts +1 -8
  64. package/src/deploy/sitemap.ts +20 -1
  65. package/src/deploy/xml.ts +8 -0
  66. package/src/markdown/directives.ts +15 -7
  67. package/src/markdown/package-commands.ts +26 -4
  68. package/src/migrate/fumadocs/content.ts +14 -1
  69. package/src/migrate/fumadocs/groups.ts +7 -0
  70. package/src/migrate/fumadocs/index.ts +5 -2
  71. package/src/migrate/mintlify/assets.ts +46 -0
  72. package/src/migrate/mintlify/index.ts +53 -45
  73. package/src/migrate/shared.ts +12 -27
  74. package/src/og/card.ts +14 -2
  75. package/src/registry/eject.ts +13 -3
  76. package/src/registry/registry.ts +6 -0
  77. package/src/registry/rewrite-imports.ts +31 -19
  78. package/src/search/documents.ts +23 -5
  79. package/src/search/sync/algolia.ts +5 -1
  80. package/src/search/sync/typesense.ts +24 -16
  81. package/src/theme/palette.ts +26 -7
@@ -8,9 +8,13 @@ export interface TypesenseSyncConfig {
8
8
  }
9
9
 
10
10
  /**
11
- * Import the search records into a Typesense collection, creating the
12
- * collection on first run. Uses the admin key from `TYPESENSE_ADMIN_API_KEY`.
13
- * Throws on a missing key/config so the caller can warn.
11
+ * Import the search records into a Typesense collection. Uses the admin key
12
+ * from `TYPESENSE_ADMIN_API_KEY`. Throws on a missing key/config so the caller
13
+ * can warn.
14
+ *
15
+ * The collection is dropped and recreated on each sync so that pages deleted or
16
+ * renamed since the last sync don't linger as stale search hits that 404 when
17
+ * clicked (an upsert alone never removes them).
14
18
  */
15
19
  export const syncTypesense = async (
16
20
  records: SearchRecord[],
@@ -35,20 +39,24 @@ export const syncTypesense = async (
35
39
  ],
36
40
  });
37
41
 
38
- try {
39
- await client.collections(config.collection).retrieve();
40
- } catch {
41
- await client.collections().create({
42
- fields: [
43
- { name: "title", type: "string" },
44
- { name: "description", optional: true, type: "string" },
45
- { name: "content", type: "string" },
46
- { name: "url", type: "string" },
47
- { facet: true, name: "tag", optional: true, type: "string" },
48
- ],
49
- name: config.collection,
50
- });
42
+ const collection = client.collections(config.collection);
43
+ const exists = await collection
44
+ .retrieve()
45
+ .then(() => true)
46
+ .catch(() => false);
47
+ if (exists) {
48
+ await collection.delete();
51
49
  }
50
+ await client.collections().create({
51
+ fields: [
52
+ { name: "title", type: "string" },
53
+ { name: "description", optional: true, type: "string" },
54
+ { name: "content", type: "string" },
55
+ { name: "url", type: "string" },
56
+ { facet: true, name: "tag", optional: true, type: "string" },
57
+ ],
58
+ name: config.collection,
59
+ });
52
60
 
53
61
  const documents = records.map((record) => ({
54
62
  content: record.content,
@@ -1,8 +1,10 @@
1
1
  import type { ResolvedConfig } from "../core/schema.ts";
2
2
 
3
+ const FALLBACK_ACCENT = "oklch(0.62 0.16 250)";
4
+
3
5
  /** Named accent presets mapped to OKLCH values. */
4
6
  const ACCENTS: Record<string, string> = {
5
- blue: "oklch(0.62 0.16 250)",
7
+ blue: FALLBACK_ACCENT,
6
8
  green: "oklch(0.6 0.16 150)",
7
9
  orange: "oklch(0.68 0.17 50)",
8
10
  pink: "oklch(0.65 0.2 350)",
@@ -11,6 +13,19 @@ const ACCENTS: Record<string, string> = {
11
13
  teal: "oklch(0.6 0.12 195)",
12
14
  };
13
15
 
16
+ // Characters valid in a CSS color value (hex, rgb/hsl/oklch functions, named
17
+ // colors). Anything else — notably `;`, `{`, `}` — could break out of the
18
+ // declaration and inject rules, so such a value is rejected.
19
+ const CSS_COLOR = /^[\w\s#%.,()/+-]+$/u;
20
+
21
+ /** Pass a raw color through only if it can't break out of a CSS declaration. */
22
+ const safeColor = (value: string, fallback: string): string =>
23
+ CSS_COLOR.test(value.trim()) ? value.trim() : fallback;
24
+
25
+ /** Like {@link safeColor} but drops an unsafe/absent value to `null`. */
26
+ const safeColorOrNull = (value: string | undefined): string | null =>
27
+ value && CSS_COLOR.test(value.trim()) ? value.trim() : null;
28
+
14
29
  const RADII: Record<ResolvedConfig["theme"]["radius"], string> = {
15
30
  lg: "0.75rem",
16
31
  md: "0.5rem",
@@ -66,7 +81,7 @@ const themeRootCss = (
66
81
  "--blume-action-foreground",
67
82
  options.action ? "oklch(1 0 0)" : null
68
83
  ),
69
- ...cssToken("--blume-background", theme.background),
84
+ ...cssToken("--blume-background", safeColorOrNull(theme.background)),
70
85
  ...cssToken(
71
86
  "--blume-background-image",
72
87
  theme.backgroundImage ? backgroundImageCss(theme.backgroundImage) : null
@@ -83,7 +98,7 @@ const themeDarkCss = (
83
98
  ): string => {
84
99
  const tokens = [
85
100
  ...cssToken("--blume-accent", accentDark),
86
- ...cssToken("--blume-background", theme.backgroundDark),
101
+ ...cssToken("--blume-background", safeColorOrNull(theme.backgroundDark)),
87
102
  ...cssToken(
88
103
  "--blume-background-image",
89
104
  theme.backgroundImageDark
@@ -106,7 +121,7 @@ ${tokens.join("\n")}
106
121
  * arbitrary colors without a config change.
107
122
  */
108
123
  export const resolveAccent = (theme: ResolvedConfig["theme"]): string =>
109
- ACCENTS[theme.accent] ?? theme.accent;
124
+ ACCENTS[theme.accent] ?? safeColor(theme.accent, FALLBACK_ACCENT);
110
125
 
111
126
  /** Resolve the configured radius preset to a CSS length. */
112
127
  export const resolveRadius = (theme: ResolvedConfig["theme"]): string =>
@@ -118,11 +133,15 @@ export const resolveRadius = (theme: ResolvedConfig["theme"]): string =>
118
133
  * arbitrary colors without a config change.
119
134
  */
120
135
  export const buildThemeCss = (theme: ResolvedConfig["theme"]): string => {
121
- const accent = ACCENTS[theme.accent] ?? theme.accent;
136
+ const accent =
137
+ ACCENTS[theme.accent] ?? safeColor(theme.accent, FALLBACK_ACCENT);
122
138
  const accentDark = theme.accentDark
123
- ? (ACCENTS[theme.accentDark] ?? theme.accentDark)
139
+ ? (ACCENTS[theme.accentDark] ??
140
+ safeColor(theme.accentDark, FALLBACK_ACCENT))
141
+ : null;
142
+ const action = theme.action
143
+ ? (ACCENTS[theme.action] ?? safeColor(theme.action, FALLBACK_ACCENT))
124
144
  : null;
125
- const action = theme.action ? (ACCENTS[theme.action] ?? theme.action) : null;
126
145
  const backgroundDecoration = backgroundDecorationCss(
127
146
  theme.backgroundDecoration
128
147
  );