bsmnt 0.3.0 → 0.3.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 (77) hide show
  1. package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
  2. package/dist/helpers/integrate/sanity/config.js +11 -2
  3. package/dist/helpers/integrate/sanity/config.js.map +1 -1
  4. package/index.js +2 -2
  5. package/package.json +1 -1
  6. package/src/templates/next-default/.vscode/settings.json +1 -1
  7. package/src/templates/next-default/README.md +6 -7
  8. package/src/templates/next-default/app/layout.tsx +17 -4
  9. package/src/templates/next-default/biome.json +1 -1
  10. package/src/templates/next-default/css.d.ts +1 -0
  11. package/src/templates/next-default/lib/README.md +4 -8
  12. package/src/templates/next-default/lib/hooks/use-media.ts +3 -1
  13. package/src/templates/next-default/lib/styles/global.css +182 -0
  14. package/src/templates/next-default/lib/utils/json-ld.tsx +13 -18
  15. package/src/templates/next-default/lib/utils/portable-text-to-markdown.ts +83 -0
  16. package/src/templates/next-default/package.json +3 -3
  17. package/src/templates/next-experiments/.vscode/settings.json +1 -1
  18. package/src/templates/next-experiments/README.md +6 -7
  19. package/src/templates/next-experiments/app/layout.tsx +17 -4
  20. package/src/templates/next-experiments/biome.json +1 -1
  21. package/src/templates/next-experiments/css.d.ts +1 -0
  22. package/src/templates/next-experiments/lib/README.md +4 -8
  23. package/src/templates/next-experiments/lib/hooks/use-media.ts +3 -1
  24. package/src/templates/next-experiments/lib/styles/global.css +182 -0
  25. package/src/templates/next-experiments/lib/utils/json-ld.tsx +13 -18
  26. package/src/templates/next-experiments/lib/utils/portable-text-to-markdown.ts +83 -0
  27. package/src/templates/next-experiments/package.json +3 -3
  28. package/src/templates/next-webgl/.vscode/settings.json +1 -1
  29. package/src/templates/next-webgl/README.md +6 -7
  30. package/src/templates/next-webgl/app/layout.tsx +17 -4
  31. package/src/templates/next-webgl/biome.json +1 -1
  32. package/src/templates/next-webgl/css.d.ts +1 -0
  33. package/src/templates/next-webgl/lib/README.md +4 -8
  34. package/src/templates/next-webgl/lib/hooks/use-media.ts +3 -1
  35. package/src/templates/next-webgl/lib/styles/global.css +182 -0
  36. package/src/templates/next-webgl/lib/utils/json-ld.tsx +13 -18
  37. package/src/templates/next-webgl/lib/utils/portable-text-to-markdown.ts +83 -0
  38. package/src/templates/next-webgl/package.json +3 -3
  39. package/src/templates/next-default/lib/scripts/dev.ts +0 -32
  40. package/src/templates/next-default/lib/styles/README.md +0 -13
  41. package/src/templates/next-default/lib/styles/fonts.ts +0 -20
  42. package/src/templates/next-default/lib/styles/index.css +0 -3
  43. package/src/templates/next-default/lib/styles/tokens.css +0 -179
  44. package/src/templates/next-default/lib/utils/README.md +0 -40
  45. package/src/templates/next-default/lib/utils/easings.ts +0 -240
  46. package/src/templates/next-default/lib/utils/fetch.ts +0 -84
  47. package/src/templates/next-default/lib/utils/global-css.d.ts +0 -1
  48. package/src/templates/next-default/lib/utils/math.ts +0 -236
  49. package/src/templates/next-default/lib/utils/strings.ts +0 -246
  50. package/src/templates/next-default/lib/utils/types.d.ts +0 -15
  51. package/src/templates/next-default/lib/utils/viewport.ts +0 -199
  52. package/src/templates/next-experiments/lib/scripts/dev.ts +0 -32
  53. package/src/templates/next-experiments/lib/styles/README.md +0 -13
  54. package/src/templates/next-experiments/lib/styles/fonts.ts +0 -20
  55. package/src/templates/next-experiments/lib/styles/index.css +0 -3
  56. package/src/templates/next-experiments/lib/styles/tokens.css +0 -179
  57. package/src/templates/next-experiments/lib/utils/README.md +0 -40
  58. package/src/templates/next-experiments/lib/utils/easings.ts +0 -240
  59. package/src/templates/next-experiments/lib/utils/fetch.ts +0 -84
  60. package/src/templates/next-experiments/lib/utils/global-css.d.ts +0 -1
  61. package/src/templates/next-experiments/lib/utils/math.ts +0 -236
  62. package/src/templates/next-experiments/lib/utils/strings.ts +0 -246
  63. package/src/templates/next-experiments/lib/utils/types.d.ts +0 -15
  64. package/src/templates/next-experiments/lib/utils/viewport.ts +0 -199
  65. package/src/templates/next-webgl/lib/scripts/dev.ts +0 -32
  66. package/src/templates/next-webgl/lib/styles/README.md +0 -13
  67. package/src/templates/next-webgl/lib/styles/fonts.ts +0 -20
  68. package/src/templates/next-webgl/lib/styles/index.css +0 -3
  69. package/src/templates/next-webgl/lib/styles/tokens.css +0 -179
  70. package/src/templates/next-webgl/lib/utils/README.md +0 -40
  71. package/src/templates/next-webgl/lib/utils/easings.ts +0 -240
  72. package/src/templates/next-webgl/lib/utils/fetch.ts +0 -84
  73. package/src/templates/next-webgl/lib/utils/global-css.d.ts +0 -1
  74. package/src/templates/next-webgl/lib/utils/math.ts +0 -236
  75. package/src/templates/next-webgl/lib/utils/strings.ts +0 -246
  76. package/src/templates/next-webgl/lib/utils/types.d.ts +0 -15
  77. package/src/templates/next-webgl/lib/utils/viewport.ts +0 -199
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,EAAE,uBA4C1B,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,eAAO,MAAM,YAAY,EAAE,uBAqD1B,CAAC"}
@@ -17,8 +17,17 @@ export const sanityConfig = {
17
17
  sanity: "^5.6.0",
18
18
  "sanity-plugin-media": "^2.3.0",
19
19
  },
20
- devDependencies: {},
21
- scripts: {},
20
+ devDependencies: {
21
+ "schema-dts": "^2.0.0",
22
+ },
23
+ scripts: {
24
+ "sanity:extract": "cd lib/integrations/sanity && bun --env-file ../../../.env.local sanity schema extract",
25
+ "sanity:typegen": "cd lib/integrations/sanity && bun --env-file ../../../.env.local sanity schema extract && bun --env-file ../../../.env.local sanity typegen generate && bun biome check --write --unsafe",
26
+ predev: "bun run sanity:typegen",
27
+ dev: "next dev",
28
+ prebuild: "bun run sanity:typegen",
29
+ build: "next build",
30
+ },
22
31
  additivePaths: [
23
32
  "lib/integrations/sanity",
24
33
  "components/ui/sanity-image",
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,CAAC,MAAM,YAAY,GAA4B;IACpD,IAAI,EAAE,QAAQ;IAEd,YAAY,EAAE;QACb,gBAAgB,EAAE,QAAQ;QAC1B,QAAQ,EAAE,QAAQ;QAClB,wBAAwB,EAAE,QAAQ;QAClC,qBAAqB,EAAE,SAAS;QAChC,qBAAqB,EAAE,QAAQ;QAC/B,mBAAmB,EAAE,QAAQ;QAC7B,wBAAwB,EAAE,QAAQ;QAClC,gBAAgB,EAAE,QAAQ;QAC1B,aAAa,EAAE,UAAU;QACzB,MAAM,EAAE,QAAQ;QAChB,qBAAqB,EAAE,QAAQ;KAC/B;IAED,eAAe,EAAE,EAChB;IAED,OAAO,EAAE,EACR;IAED,aAAa,EAAE;QACd,yBAAyB;QACzB,4BAA4B;QAC5B,oBAAoB;QACpB,oBAAoB;QACpB,YAAY;QACZ,cAAc;QACd,UAAU;QACV,gBAAgB;QAChB,uBAAuB;QACvB,uBAAuB;QACvB,wCAAwC;QACxC,4BAA4B;QAC5B,UAAU;KACV;IAED,UAAU,EAAE;QACX,gBAAgB;QAChB,gBAAgB;QAChB,uCAAuC;KACvC;CACD,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../../src/helpers/integrate/sanity/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,MAAM,CAAC,MAAM,YAAY,GAA4B;IACpD,IAAI,EAAE,QAAQ;IAEd,YAAY,EAAE;QACb,gBAAgB,EAAE,QAAQ;QAC1B,QAAQ,EAAE,QAAQ;QAClB,wBAAwB,EAAE,QAAQ;QAClC,qBAAqB,EAAE,SAAS;QAChC,qBAAqB,EAAE,QAAQ;QAC/B,mBAAmB,EAAE,QAAQ;QAC7B,wBAAwB,EAAE,QAAQ;QAClC,gBAAgB,EAAE,QAAQ;QAC1B,aAAa,EAAE,UAAU;QACzB,MAAM,EAAE,QAAQ;QAChB,qBAAqB,EAAE,QAAQ;KAC/B;IAED,eAAe,EAAE;QAChB,YAAY,EAAE,QAAQ;KACtB;IAED,OAAO,EAAE;QACR,gBAAgB,EACf,wFAAwF;QACzF,gBAAgB,EACf,0LAA0L;QAC3L,MAAM,EAAE,wBAAwB;QAChC,GAAG,EAAE,UAAU;QACf,QAAQ,EAAE,wBAAwB;QAClC,KAAK,EAAE,YAAY;KACnB;IAED,aAAa,EAAE;QACd,yBAAyB;QACzB,4BAA4B;QAC5B,oBAAoB;QACpB,oBAAoB;QACpB,YAAY;QACZ,cAAc;QACd,UAAU;QACV,gBAAgB;QAChB,uBAAuB;QACvB,uBAAuB;QACvB,wCAAwC;QACxC,4BAA4B;QAC5B,UAAU;KACV;IAED,UAAU,EAAE;QACX,gBAAgB;QAChB,gBAAgB;QAChB,uCAAuC;KACvC;CACD,CAAC"}
package/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { existsSync } from "node:fs";
4
- import { fileURLToPath } from "node:url";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { dirname, join } from "node:path";
6
6
 
7
7
  const __filename = fileURLToPath(import.meta.url);
@@ -10,7 +10,7 @@ const __dirname = dirname(__filename);
10
10
  const distEntry = join(__dirname, "dist", "index.js");
11
11
 
12
12
  if (existsSync(distEntry)) {
13
- await import(distEntry);
13
+ await import(pathToFileURL(distEntry).href);
14
14
  } else {
15
15
  // Dev mode: run TypeScript source via local tsx
16
16
  const { execFileSync } = await import("node:child_process");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bsmnt",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "packageManager": "bun@1.2.20",
5
5
  "description": "CLI to scaffold basement projects and add integrations",
6
6
  "type": "module",
@@ -82,7 +82,7 @@
82
82
  ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^\"'`]*)(?:'|\"|`)"],
83
83
  ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
84
84
  ],
85
- "tailwindCSS.experimental.configFile": "./lib/styles/css/tailwind.css",
85
+ "tailwindCSS.experimental.configFile": "./lib/styles/global.css",
86
86
  "tailwindCSS.includeLanguages": {
87
87
  "typescriptreact": "html"
88
88
  },
@@ -34,17 +34,16 @@ lib/
34
34
  scripts/
35
35
  store/
36
36
  styles/
37
- index.css
38
- tokens.css
39
37
  global.css
40
- fonts.ts
41
38
  cn.ts
42
39
  utils/
40
+ metadata.ts
41
+ portable-text-to-markdown.ts
42
+ json-ld.ts
43
43
  ```
44
44
 
45
45
  ## Styling
46
46
 
47
- - Import `@/lib/styles/index.css` once in `app/layout.tsx`.
48
- - Edit `lib/styles/tokens.css` for theme variables, breakpoints, and custom Tailwind utilities.
49
- - Edit `lib/styles/global.css` for reset rules and app-wide global styles.
50
- - `lib/styles/fonts.ts` handles font variables.
47
+ - Import `@/lib/styles/global.css` once in `app/layout.tsx`.
48
+ - `lib/styles/global.css` includes Tailwind utilities, theme tokens, and app-wide global styles.
49
+ - `lib/styles/cn.ts` is the shared class merge helper.
@@ -1,10 +1,9 @@
1
1
  import type { Metadata, Viewport } from "next";
2
- import { Geist } from "next/font/google";
2
+ import { Geist, Geist_Mono } from "next/font/google";
3
3
  import { type PropsWithChildren, Suspense } from "react";
4
4
  import { Link } from "@/components/ui/link";
5
- import { fontsVariable } from "@/lib/styles/fonts";
6
5
  import AppData from "@/package.json";
7
- import "@/lib/styles/index.css";
6
+ import "@/lib/styles/global.css";
8
7
  import { cn } from "@/lib/styles/cn";
9
8
  import {
10
9
  JsonLd,
@@ -23,6 +22,20 @@ const geist = Geist({
23
22
  subsets: ["latin"],
24
23
  });
25
24
 
25
+ const mono = Geist_Mono({
26
+ subsets: ["latin"],
27
+ display: "swap",
28
+ variable: "--geist-mono",
29
+ fallback: [
30
+ "ui-monospace",
31
+ "SFMono-Regular",
32
+ "Consolas",
33
+ "Liberation Mono",
34
+ "Menlo",
35
+ "monospace",
36
+ ],
37
+ });
38
+
26
39
  export const metadata: Metadata = {
27
40
  alternates: {
28
41
  canonical: "/",
@@ -86,7 +99,7 @@ export default async function Layout({ children }: PropsWithChildren) {
86
99
  <html
87
100
  lang="en"
88
101
  dir="ltr"
89
- className={cn(fontsVariable, geist.className)}
102
+ className={cn(mono.variable, geist.className)}
90
103
  // NOTE: This is due to the data-theme attribute being set which causes hydration errors
91
104
  suppressHydrationWarning
92
105
  >
@@ -214,7 +214,7 @@
214
214
  }
215
215
  },
216
216
  {
217
- "includes": ["lib/styles/tokens.css"],
217
+ "includes": ["lib/styles/global.css"],
218
218
  "linter": {
219
219
  "rules": {
220
220
  "suspicious": {
@@ -0,0 +1 @@
1
+ declare module "*.css"
@@ -7,12 +7,8 @@ Non-UI code: hooks, integrations, styles, and utilities.
7
7
  ## Quick Imports
8
8
 
9
9
  ```tsx
10
- // Utilities - explicit imports for better tree-shaking
11
- import { clamp, lerp } from '@/lib/utils/math'
12
- import { slugify } from '@/lib/utils/strings'
13
-
14
- // Styles
15
- import { colors, themes, breakpoints } from '@/lib/styles/config'
10
+ import { generatePageMetadata } from '@/lib/utils/metadata'
11
+ import { createJsonLd, serializeJsonLd } from '@/lib/utils/json-ld'
16
12
  ```
17
13
 
18
14
  ## Directories
@@ -20,8 +16,8 @@ import { colors, themes, breakpoints } from '@/lib/styles/config'
20
16
  | Directory | Purpose | Optional? |
21
17
  |-----------|---------|-----------|
22
18
  | [hooks/](hooks/README.md) | React hooks + Zustand store | ❌ Core |
23
- | [styles/](styles/README.md) | CSS & Tailwind config | ❌ Core |
24
- | [utils/](utils/README.md) | Pure utility functions | ❌ Core |
19
+ | `styles/` | Global styles and class utilities | ❌ Core |
20
+ | `utils/` | Metadata and content serialization helpers | ❌ Core |
25
21
 
26
22
  ## Scripts
27
23
 
@@ -6,7 +6,7 @@ export function useMedia(mediaQuery: string, initialValue?: boolean) {
6
6
  useEffect(() => {
7
7
  if (typeof window === "undefined" || !("matchMedia" in window)) {
8
8
  console.warn("matchMedia is not supported by your current browser")
9
- return
9
+ return undefined
10
10
  }
11
11
  const mediaQueryList = window.matchMedia(mediaQuery)
12
12
  const changeHandler = () => setIsVerified(!!mediaQueryList.matches)
@@ -23,6 +23,8 @@ export function useMedia(mediaQuery: string, initialValue?: boolean) {
23
23
  mediaQueryList.removeListener(changeHandler)
24
24
  }
25
25
  }
26
+
27
+ return undefined
26
28
  }, [mediaQuery])
27
29
 
28
30
  return isVerified
@@ -1,3 +1,185 @@
1
+ @import "tailwindcss/utilities.css";
2
+
3
+ @custom-media --hover (hover: hover);
4
+ @custom-media --reduced-motion (prefers-reduced-motion: reduce);
5
+ @custom-media --mobile-only (width < 768px);
6
+ @custom-media --tablet (width >= 768px);
7
+ @custom-media --tablet-lg (width >= 1024px);
8
+ @custom-media --desktop (width >= 1440px);
9
+ @custom-media --desktop-large (width >= 1920px);
10
+
11
+ :root {
12
+ --device-width: 640;
13
+ --device-height: 650;
14
+ --columns: 4;
15
+ --gap: 16px;
16
+ --safe: 16px;
17
+ --header-height: 58px;
18
+ --layout-width: calc(100vw - (2 * var(--safe)));
19
+ --column-width: calc(
20
+ (var(--layout-width) - (var(--columns) - 1) * var(--gap)) / var(--columns)
21
+ );
22
+ --ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
23
+ --ease-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19);
24
+ --ease-in-quart: cubic-bezier(0.895, 0.03, 0.685, 0.22);
25
+ --ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06);
26
+ --ease-in-expo: cubic-bezier(0.95, 0.05, 0.795, 0.035);
27
+ --ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.335);
28
+ --ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
29
+ --ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
30
+ --ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
31
+ --ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
32
+ --ease-out-expo: cubic-bezier(0.19, 1, 0.22, 1);
33
+ --ease-out-circ: cubic-bezier(0.075, 0.82, 0.165, 1);
34
+ --ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
35
+ --ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
36
+ --ease-in-out-quart: cubic-bezier(0.77, 0, 0.175, 1);
37
+ --ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1);
38
+ --ease-in-out-expo: cubic-bezier(1, 0, 0, 1);
39
+ --ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.15, 0.86);
40
+ --ease-gleasing: cubic-bezier(0.4, 0, 0, 1);
41
+ --color-black: #000000;
42
+ --color-white: #ffffff;
43
+ --color-orange: #ff4d00;
44
+ --color-blue: #487cff;
45
+ --color-green: #00ff9b;
46
+ --color-violet: #f101a5;
47
+ --color-pink: #ff73a6;
48
+ --color-gray: #666666;
49
+
50
+ @variant desktop {
51
+ --device-width: 1440;
52
+ --device-height: 816;
53
+ --columns: 12;
54
+ --header-height: 98px;
55
+ }
56
+ }
57
+
58
+ @theme {
59
+ --breakpoint-*: initial;
60
+ --breakpoint-desktop-large: 1920px;
61
+ --breakpoint-desktop: 1440px;
62
+ --breakpoint-tablet-lg: 1024px;
63
+ --breakpoint-tablet: 768px;
64
+ --breakpoint-mobile: 640px;
65
+
66
+ --color-*: initial;
67
+ --color-primary: #ffffff;
68
+ --color-secondary: #000000;
69
+ --color-contrast: #ff4d00;
70
+ --color-black: #000000;
71
+ --color-white: #ffffff;
72
+ --color-orange: #ff4d00;
73
+ --color-blue: #487cff;
74
+ --color-green: #00ff9b;
75
+ --color-violet: #f101a5;
76
+ --color-pink: #ff73a6;
77
+ --color-gray: #666666;
78
+ --color-gray-50: #f5f5f5;
79
+ --color-gray-100: #e0e0e0;
80
+ --color-gray-200: #c2c2c2;
81
+ --color-gray-300: #a3a3a3;
82
+ --color-gray-400: #858585;
83
+ --color-gray-500: #666666;
84
+ --color-gray-600: #4d4d4d;
85
+ --color-gray-700: #333333;
86
+ --color-gray-800: #1a1a1a;
87
+
88
+ --spacing: 0.25rem;
89
+ --spacing-0: 0;
90
+ --spacing-safe: var(--safe);
91
+ --spacing-gap: var(--gap);
92
+ --spacing-header-height: var(--header-height);
93
+
94
+ --font-*: initial;
95
+ --font-mono: var(--geist-mono);
96
+
97
+ --ease-*: initial;
98
+ --ease-in-quad: var(--ease-in-quad);
99
+ --ease-in-cubic: var(--ease-in-cubic);
100
+ --ease-in-quart: var(--ease-in-quart);
101
+ --ease-in-quint: var(--ease-in-quint);
102
+ --ease-in-expo: var(--ease-in-expo);
103
+ --ease-in-circ: var(--ease-in-circ);
104
+ --ease-out-quad: var(--ease-out-quad);
105
+ --ease-out-cubic: var(--ease-out-cubic);
106
+ --ease-out-quart: var(--ease-out-quart);
107
+ --ease-out-quint: var(--ease-out-quint);
108
+ --ease-out-expo: var(--ease-out-expo);
109
+ --ease-out-circ: var(--ease-out-circ);
110
+ --ease-in-out-quad: var(--ease-in-out-quad);
111
+ --ease-in-out-cubic: var(--ease-in-out-cubic);
112
+ --ease-in-out-quart: var(--ease-in-out-quart);
113
+ --ease-in-out-quint: var(--ease-in-out-quint);
114
+ --ease-in-out-expo: var(--ease-in-out-expo);
115
+ --ease-in-out-circ: var(--ease-in-out-circ);
116
+ --ease-gleasing: var(--ease-gleasing);
117
+ }
118
+
119
+ [data-theme="light"] {
120
+ --color-primary: #ffffff;
121
+ --color-secondary: #000000;
122
+ --color-contrast: #ff4d00;
123
+ }
124
+
125
+ [data-theme="dark"] {
126
+ --color-primary: #000000;
127
+ --color-secondary: #ffffff;
128
+ --color-contrast: #ff4d00;
129
+ }
130
+
131
+ @utility test-mono {
132
+ font-family: var(--geist-mono);
133
+ font-size: 20px;
134
+ font-style: normal;
135
+ font-weight: 400;
136
+ letter-spacing: 0;
137
+ line-height: 90%;
138
+
139
+ @variant desktop {
140
+ font-size: 24px;
141
+ }
142
+ }
143
+
144
+ @utility desktop-only {
145
+ @media (--mobile-only) {
146
+ display: none !important;
147
+ }
148
+ }
149
+
150
+ @utility mobile-only {
151
+ @media (--tablet) {
152
+ display: none !important;
153
+ }
154
+ }
155
+
156
+ @utility b-grid {
157
+ column-gap: var(--gap);
158
+ display: grid;
159
+ grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
160
+ }
161
+
162
+ @utility b-layout-block {
163
+ margin-inline: auto;
164
+ width: calc(100% - 2 * var(--safe));
165
+ }
166
+
167
+ @utility b-layout-block-inner {
168
+ padding-inline: var(--safe);
169
+ width: 100%;
170
+ }
171
+
172
+ @utility b-layout-grid {
173
+ @apply b-layout-block b-grid;
174
+ }
175
+
176
+ @utility b-layout-grid-inner {
177
+ @apply b-layout-block-inner b-grid;
178
+ }
179
+
180
+ @custom-variant light (&:where([data-theme="light"], [data-theme="light"] *));
181
+ @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
182
+
1
183
  /***
2
184
  The new CSS reset - version 1.11.3 (last updated 25.08.2024)
3
185
  GitHub page: https://github.com/elad2412/the-new-css-reset
@@ -1,13 +1,8 @@
1
- import type {
2
- Article,
3
- BreadcrumbList,
4
- Organization,
5
- SearchAction,
6
- Thing,
7
- WebPage,
8
- WebSite,
9
- WithContext,
10
- } from "schema-dts";
1
+ type JsonLdValue = {
2
+ "@context": "https://schema.org";
3
+ "@type": string;
4
+ [key: string]: unknown;
5
+ };
11
6
 
12
7
  const APP_BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;
13
8
 
@@ -25,10 +20,10 @@ function resolveUrl(value?: string) {
25
20
 
26
21
  /* -------------------------------- Component ------------------------------- */
27
22
 
28
- export function JsonLd<T extends Thing>({
23
+ export function JsonLd<T extends JsonLdValue>({
29
24
  data,
30
25
  }: {
31
- data: WithContext<T>;
26
+ data: T;
32
27
  }) {
33
28
  return (
34
29
  <script
@@ -52,7 +47,7 @@ interface WebSiteJsonLdOptions {
52
47
 
53
48
  export function generateWebSiteJsonLd(
54
49
  options: WebSiteJsonLdOptions
55
- ): WithContext<WebSite> {
50
+ ): JsonLdValue {
56
51
  const { name, url, description, searchUrl } = options;
57
52
  const resolvedUrl = resolveUrl(url);
58
53
  const resolvedSearchUrl = resolveUrl(searchUrl);
@@ -68,7 +63,7 @@ export function generateWebSiteJsonLd(
68
63
  "@type": "SearchAction",
69
64
  target: resolvedSearchUrl,
70
65
  "query-input": "required name=search_term_string",
71
- } as SearchAction & { "query-input": string },
66
+ },
72
67
  }),
73
68
  };
74
69
  }
@@ -83,7 +78,7 @@ interface OrganizationJsonLdOptions {
83
78
 
84
79
  export function generateOrganizationJsonLd(
85
80
  options: OrganizationJsonLdOptions
86
- ): WithContext<Organization> {
81
+ ): JsonLdValue {
87
82
  const { name, url, logo, description, sameAs } = options;
88
83
  const resolvedUrl = resolveUrl(url);
89
84
  const resolvedLogo = resolveUrl(logo);
@@ -110,7 +105,7 @@ interface WebPageJsonLdOptions {
110
105
 
111
106
  export function generateWebPageJsonLd(
112
107
  options: WebPageJsonLdOptions
113
- ): WithContext<WebPage> {
108
+ ): JsonLdValue {
114
109
  const { title, url, description, image, datePublished, dateModified } =
115
110
  options;
116
111
  const resolvedUrl = resolveUrl(url);
@@ -141,7 +136,7 @@ interface ArticleJsonLdOptions {
141
136
 
142
137
  export function generateArticleJsonLd(
143
138
  options: ArticleJsonLdOptions
144
- ): WithContext<Article> {
139
+ ): JsonLdValue {
145
140
  const {
146
141
  title,
147
142
  url,
@@ -181,7 +176,7 @@ interface BreadcrumbItem {
181
176
 
182
177
  export function generateBreadcrumbJsonLd(
183
178
  items: BreadcrumbItem[]
184
- ): WithContext<BreadcrumbList> {
179
+ ): JsonLdValue {
185
180
  return {
186
181
  "@context": "https://schema.org",
187
182
  "@type": "BreadcrumbList",
@@ -0,0 +1,83 @@
1
+ export interface PortableTextMarkDefinition {
2
+ _key?: string;
3
+ _type?: string;
4
+ href?: string;
5
+ }
6
+
7
+ export interface PortableTextSpan {
8
+ _type?: string;
9
+ text?: string;
10
+ marks?: string[];
11
+ }
12
+
13
+ export interface PortableTextBlock {
14
+ _type?: string;
15
+ style?: string;
16
+ listItem?: "bullet" | "number";
17
+ level?: number;
18
+ children?: PortableTextSpan[];
19
+ markDefs?: PortableTextMarkDefinition[];
20
+ }
21
+
22
+ const headingStyles: Record<string, string> = {
23
+ h1: "#",
24
+ h2: "##",
25
+ h3: "###",
26
+ h4: "####",
27
+ h5: "#####",
28
+ h6: "######",
29
+ }
30
+
31
+ function applyMarks(
32
+ text: string,
33
+ marks: string[] | undefined,
34
+ markDefs: PortableTextMarkDefinition[]
35
+ ) {
36
+ return (marks ?? []).reduce((result, mark) => {
37
+ if (mark === "strong") return `**${result}**`
38
+ if (mark === "em") return `*${result}*`
39
+ if (mark === "code") return `\`${result}\``
40
+
41
+ const link = markDefs.find((definition) => definition._key === mark)
42
+ if (link?._type === "link" && link.href) {
43
+ return `[${result}](${link.href})`
44
+ }
45
+
46
+ return result
47
+ }, text)
48
+ }
49
+
50
+ function serializeBlock(block: PortableTextBlock) {
51
+ const text = (block.children ?? [])
52
+ .map((child) =>
53
+ applyMarks(child.text ?? "", child.marks, block.markDefs ?? [])
54
+ )
55
+ .join("")
56
+ .trim()
57
+
58
+ if (!text) return ""
59
+
60
+ if (block.listItem) {
61
+ const level = Math.max((block.level ?? 1) - 1, 0)
62
+ const indent = " ".repeat(level)
63
+ const marker = block.listItem === "number" ? "1." : "-"
64
+ return `${indent}${marker} ${text}`
65
+ }
66
+
67
+ if (block.style === "blockquote") {
68
+ return `> ${text}`
69
+ }
70
+
71
+ const headingPrefix = headingStyles[block.style ?? ""]
72
+ if (headingPrefix) {
73
+ return `${headingPrefix} ${text}`
74
+ }
75
+
76
+ return text
77
+ }
78
+
79
+ export function portableTextToMarkdown(
80
+ value: PortableTextBlock[] | null | undefined
81
+ ) {
82
+ return (value ?? []).map(serializeBlock).filter(Boolean).join("\n\n")
83
+ }
@@ -8,9 +8,9 @@
8
8
  "analyze": "cross-env ANALYZE=true bun run build",
9
9
  "analyze:experimental": "next experimental-analyze",
10
10
  "build": "next build",
11
- "dev": "bun ./lib/scripts/dev.ts",
12
- "dev:https": "bun ./lib/scripts/dev.ts --https",
13
- "dev:inspect": "bun ./lib/scripts/dev.ts --inspect",
11
+ "dev": "next dev",
12
+ "dev:https": "next dev --experimental-https",
13
+ "dev:inspect": "next dev --inspect",
14
14
  "format": "biome format --write .",
15
15
  "lighthouse": "bunx @unlighthouse/cli --site http://localhost:3000",
16
16
  "lint": "biome lint --max-diagnostics=200",
@@ -82,7 +82,7 @@
82
82
  ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^\"'`]*)(?:'|\"|`)"],
83
83
  ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
84
84
  ],
85
- "tailwindCSS.experimental.configFile": "./lib/styles/css/tailwind.css",
85
+ "tailwindCSS.experimental.configFile": "./lib/styles/global.css",
86
86
  "tailwindCSS.includeLanguages": {
87
87
  "typescriptreact": "html"
88
88
  },
@@ -34,17 +34,16 @@ lib/
34
34
  scripts/
35
35
  store/
36
36
  styles/
37
- index.css
38
- tokens.css
39
37
  global.css
40
- fonts.ts
41
38
  cn.ts
42
39
  utils/
40
+ metadata.ts
41
+ portable-text-to-markdown.ts
42
+ json-ld.ts
43
43
  ```
44
44
 
45
45
  ## Styling
46
46
 
47
- - Import `@/lib/styles/index.css` once in `app/layout.tsx`.
48
- - Edit `lib/styles/tokens.css` for theme variables, breakpoints, and custom Tailwind utilities.
49
- - Edit `lib/styles/global.css` for reset rules and app-wide global styles.
50
- - `lib/styles/fonts.ts` handles font variables.
47
+ - Import `@/lib/styles/global.css` once in `app/layout.tsx`.
48
+ - `lib/styles/global.css` includes Tailwind utilities, theme tokens, and app-wide global styles.
49
+ - `lib/styles/cn.ts` is the shared class merge helper.
@@ -1,10 +1,9 @@
1
1
  import type { Metadata, Viewport } from "next";
2
- import { Geist } from "next/font/google";
2
+ import { Geist, Geist_Mono } from "next/font/google";
3
3
  import { type PropsWithChildren, Suspense } from "react";
4
4
  import { Link } from "@/components/ui/link";
5
- import { fontsVariable } from "@/lib/styles/fonts";
6
5
  import AppData from "@/package.json";
7
- import "@/lib/styles/index.css";
6
+ import "@/lib/styles/global.css";
8
7
  import { cn } from "@/lib/styles/cn";
9
8
  import {
10
9
  JsonLd,
@@ -23,6 +22,20 @@ const geist = Geist({
23
22
  subsets: ["latin"],
24
23
  });
25
24
 
25
+ const mono = Geist_Mono({
26
+ subsets: ["latin"],
27
+ display: "swap",
28
+ variable: "--geist-mono",
29
+ fallback: [
30
+ "ui-monospace",
31
+ "SFMono-Regular",
32
+ "Consolas",
33
+ "Liberation Mono",
34
+ "Menlo",
35
+ "monospace",
36
+ ],
37
+ });
38
+
26
39
  export const metadata: Metadata = {
27
40
  alternates: {
28
41
  canonical: "/",
@@ -86,7 +99,7 @@ export default async function Layout({ children }: PropsWithChildren) {
86
99
  <html
87
100
  lang="en"
88
101
  dir="ltr"
89
- className={cn(fontsVariable, geist.className)}
102
+ className={cn(mono.variable, geist.className)}
90
103
  // NOTE: This is due to the data-theme attribute being set which causes hydration errors
91
104
  suppressHydrationWarning
92
105
  >
@@ -214,7 +214,7 @@
214
214
  }
215
215
  },
216
216
  {
217
- "includes": ["lib/styles/tokens.css"],
217
+ "includes": ["lib/styles/global.css"],
218
218
  "linter": {
219
219
  "rules": {
220
220
  "suspicious": {
@@ -0,0 +1 @@
1
+ declare module "*.css"