bsmnt 0.2.11 → 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 (188) hide show
  1. package/dist/helpers/create/copy-template.d.ts +1 -1
  2. package/dist/helpers/create/copy-template.d.ts.map +1 -1
  3. package/dist/helpers/create/index.d.ts.map +1 -1
  4. package/dist/helpers/create/index.js +2 -1
  5. package/dist/helpers/create/index.js.map +1 -1
  6. package/dist/helpers/integrate/merge-config.d.ts.map +1 -1
  7. package/dist/helpers/integrate/merge-config.js +0 -2
  8. package/dist/helpers/integrate/merge-config.js.map +1 -1
  9. package/dist/helpers/integrate/sanity/config.d.ts.map +1 -1
  10. package/dist/helpers/integrate/sanity/config.js +2 -4
  11. package/dist/helpers/integrate/sanity/config.js.map +1 -1
  12. package/dist/index.js +84 -35
  13. package/dist/index.js.map +1 -1
  14. package/index.js +2 -2
  15. package/package.json +1 -1
  16. package/src/templates/next-default/.vscode/settings.json +1 -1
  17. package/src/templates/next-default/README.md +6 -7
  18. package/src/templates/next-default/app/layout.tsx +17 -4
  19. package/src/templates/next-default/biome.json +1 -1
  20. package/src/templates/next-default/css.d.ts +1 -0
  21. package/src/templates/next-default/lib/README.md +4 -8
  22. package/src/templates/next-default/lib/hooks/use-media.ts +3 -1
  23. package/src/templates/next-default/lib/styles/global.css +182 -0
  24. package/src/templates/next-default/lib/utils/json-ld.tsx +13 -18
  25. package/src/templates/next-default/lib/utils/portable-text-to-markdown.ts +83 -0
  26. package/src/templates/next-default/package.json +3 -3
  27. package/src/templates/next-experiments/.vscode/settings.json +1 -1
  28. package/src/templates/next-experiments/README.md +6 -7
  29. package/src/templates/next-experiments/app/layout.tsx +17 -4
  30. package/src/templates/next-experiments/biome.json +1 -1
  31. package/src/templates/next-experiments/css.d.ts +1 -0
  32. package/src/templates/next-experiments/lib/README.md +4 -8
  33. package/src/templates/next-experiments/lib/hooks/use-media.ts +3 -1
  34. package/src/templates/next-experiments/lib/styles/global.css +182 -0
  35. package/src/templates/next-experiments/lib/utils/json-ld.tsx +13 -18
  36. package/src/templates/next-experiments/lib/utils/portable-text-to-markdown.ts +83 -0
  37. package/src/templates/next-experiments/package.json +3 -3
  38. package/src/templates/next-pagebuilder/.env.example +11 -0
  39. package/src/templates/next-pagebuilder/README.md +23 -0
  40. package/src/templates/next-pagebuilder/_gitignore +67 -0
  41. package/src/templates/next-pagebuilder/app/(content)/[[...slug]]/page.tsx +68 -0
  42. package/src/templates/next-pagebuilder/app/(content)/layout.tsx +13 -0
  43. package/src/templates/next-pagebuilder/app/api/[[...slug]]/route.ts +100 -0
  44. package/src/templates/next-pagebuilder/app/api/draft-mode/disable/route.ts +7 -0
  45. package/src/templates/next-pagebuilder/app/api/draft-mode/enable/route.ts +20 -0
  46. package/src/templates/next-pagebuilder/app/api/revalidate/route.ts +121 -0
  47. package/src/templates/next-pagebuilder/app/favicon.ico +0 -0
  48. package/src/templates/next-pagebuilder/app/layout.tsx +80 -0
  49. package/src/templates/next-pagebuilder/app/robots.ts +15 -0
  50. package/src/templates/next-pagebuilder/app/sitemap.md/route.ts +124 -0
  51. package/src/templates/next-pagebuilder/app/sitemap.xml/route.ts +80 -0
  52. package/src/templates/next-pagebuilder/app/studio/[[...tool]]/page.tsx +8 -0
  53. package/src/templates/next-pagebuilder/biome.json +239 -0
  54. package/src/templates/next-pagebuilder/components/layout/footer/index.tsx +95 -0
  55. package/src/templates/next-pagebuilder/components/layout/header/components/cta-button.tsx +28 -0
  56. package/src/templates/next-pagebuilder/components/layout/header/components/mega-menu-panel.tsx +90 -0
  57. package/src/templates/next-pagebuilder/components/layout/header/components/nav-item-renderer.tsx +98 -0
  58. package/src/templates/next-pagebuilder/components/layout/header/components/nav-leaf-item.tsx +33 -0
  59. package/src/templates/next-pagebuilder/components/layout/header/components/types.ts +7 -0
  60. package/src/templates/next-pagebuilder/components/layout/header/header-client.tsx +110 -0
  61. package/src/templates/next-pagebuilder/components/layout/header/index.tsx +8 -0
  62. package/src/templates/next-pagebuilder/components/layout/json-ld/index.tsx +45 -0
  63. package/src/templates/next-pagebuilder/components/layout/wrapper/index.tsx +30 -0
  64. package/src/templates/next-pagebuilder/components/page-builder/components/article-content/index.tsx +83 -0
  65. package/src/templates/next-pagebuilder/components/page-builder/components/article-content/related-post-item.tsx +27 -0
  66. package/src/templates/next-pagebuilder/components/page-builder/components/description.tsx +17 -0
  67. package/src/templates/next-pagebuilder/components/page-builder/components/hero.tsx +17 -0
  68. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/content-card.tsx +66 -0
  69. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/content-grid.tsx +42 -0
  70. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/index.tsx +28 -0
  71. package/src/templates/next-pagebuilder/components/page-builder/components/post-collection/types.ts +16 -0
  72. package/src/templates/next-pagebuilder/components/page-builder/renderer.tsx +36 -0
  73. package/src/templates/next-pagebuilder/components/page-builder/types.ts +23 -0
  74. package/src/templates/next-pagebuilder/components/page-document/index.tsx +91 -0
  75. package/src/templates/next-pagebuilder/components/sanity/draft-mode-toggle.tsx +27 -0
  76. package/src/templates/next-pagebuilder/components/sanity/rich-text.tsx +87 -0
  77. package/src/templates/next-pagebuilder/components/sanity/visual-editing.tsx +27 -0
  78. package/src/templates/next-pagebuilder/components/ui/image/index.tsx +216 -0
  79. package/src/templates/next-pagebuilder/components/ui/link/index.tsx +152 -0
  80. package/src/templates/next-pagebuilder/components/ui/sanity-image/index.tsx +41 -0
  81. package/src/templates/next-pagebuilder/lib/integrations/check-integration.ts +5 -0
  82. package/src/templates/next-pagebuilder/lib/integrations/sanity/client.ts +27 -0
  83. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/disable-draft-mode.tsx +23 -0
  84. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/page-builder-input.tsx +36 -0
  85. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/page-category-input.tsx +50 -0
  86. package/src/templates/next-pagebuilder/lib/integrations/sanity/components/rich-text.tsx +84 -0
  87. package/src/templates/next-pagebuilder/lib/integrations/sanity/confirm-publish-action.ts +40 -0
  88. package/src/templates/next-pagebuilder/lib/integrations/sanity/env.ts +34 -0
  89. package/src/templates/next-pagebuilder/lib/integrations/sanity/fetchers/layout.ts +35 -0
  90. package/src/templates/next-pagebuilder/lib/integrations/sanity/icons.ts +58 -0
  91. package/src/templates/next-pagebuilder/lib/integrations/sanity/live/index.tsx +61 -0
  92. package/src/templates/next-pagebuilder/lib/integrations/sanity/markdown-proxy.config.ts +50 -0
  93. package/src/templates/next-pagebuilder/lib/integrations/sanity/page-builder-config.ts +132 -0
  94. package/src/templates/next-pagebuilder/lib/integrations/sanity/page-category.ts +28 -0
  95. package/src/templates/next-pagebuilder/lib/integrations/sanity/queries.ts +281 -0
  96. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.cli.ts +29 -0
  97. package/src/templates/next-pagebuilder/lib/integrations/sanity/sanity.config.ts +211 -0
  98. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/index.ts +4 -0
  99. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/blog-content.ts +89 -0
  100. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/description.ts +29 -0
  101. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/reusable/hero.ts +28 -0
  102. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/components/singleton/content-collection.ts +45 -0
  103. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/content/author.ts +70 -0
  104. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/content/blog-category.ts +55 -0
  105. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/index.ts +96 -0
  106. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/company-data.ts +62 -0
  107. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/footer.ts +79 -0
  108. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/layout/navbar.ts +74 -0
  109. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/link.ts +125 -0
  110. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/logo-field.ts +9 -0
  111. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/metadata.ts +68 -0
  112. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/nav-objects.ts +192 -0
  113. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page-builder.ts +39 -0
  114. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page-folder.ts +124 -0
  115. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/page.ts +232 -0
  116. package/src/templates/next-pagebuilder/lib/integrations/sanity/schemas/shared/richText.ts +63 -0
  117. package/src/templates/next-pagebuilder/lib/integrations/sanity/singletons.ts +44 -0
  118. package/src/templates/next-pagebuilder/lib/integrations/sanity/structure.ts +453 -0
  119. package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/image.ts +8 -0
  120. package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/link.ts +137 -0
  121. package/src/templates/next-pagebuilder/lib/integrations/sanity/utils/page-builder-markdown.ts +81 -0
  122. package/src/templates/next-pagebuilder/lib/scripts/sanity-typegen.ts +45 -0
  123. package/src/templates/next-pagebuilder/lib/styles/cn.ts +5 -0
  124. package/src/templates/next-pagebuilder/lib/styles/global.css +70 -0
  125. package/src/templates/next-pagebuilder/lib/utils/base-url.ts +17 -0
  126. package/src/templates/next-pagebuilder/lib/utils/format-date.ts +8 -0
  127. package/src/templates/next-pagebuilder/lib/utils/json-ld.tsx +213 -0
  128. package/src/templates/next-pagebuilder/lib/utils/metadata.ts +167 -0
  129. package/src/templates/next-pagebuilder/lib/utils/sitemap.ts +37 -0
  130. package/src/templates/next-pagebuilder/lib/utils/slug-tag.ts +6 -0
  131. package/src/templates/next-pagebuilder/next.config.ts +134 -0
  132. package/src/templates/next-pagebuilder/package.json +71 -0
  133. package/src/templates/next-pagebuilder/postcss.config.mjs +39 -0
  134. package/src/templates/next-pagebuilder/proxy.ts +81 -0
  135. package/src/templates/next-pagebuilder/svg.d.ts +5 -0
  136. package/src/templates/next-pagebuilder/tsconfig.json +38 -0
  137. package/src/templates/next-webgl/.vscode/settings.json +1 -1
  138. package/src/templates/next-webgl/README.md +6 -7
  139. package/src/templates/next-webgl/app/layout.tsx +17 -4
  140. package/src/templates/next-webgl/biome.json +1 -1
  141. package/src/templates/next-webgl/css.d.ts +1 -0
  142. package/src/templates/next-webgl/lib/README.md +4 -8
  143. package/src/templates/next-webgl/lib/hooks/use-media.ts +3 -1
  144. package/src/templates/next-webgl/lib/styles/global.css +182 -0
  145. package/src/templates/next-webgl/lib/utils/json-ld.tsx +13 -18
  146. package/src/templates/next-webgl/lib/utils/portable-text-to-markdown.ts +83 -0
  147. package/src/templates/next-webgl/package.json +3 -3
  148. package/src/helpers/integrate/sanity/files/lib/scripts/copy-sanity-mcp.ts +0 -23
  149. package/src/helpers/integrate/sanity/files/lib/scripts/generate-page.ts +0 -297
  150. package/src/templates/next-default/lib/scripts/dev.ts +0 -32
  151. package/src/templates/next-default/lib/styles/README.md +0 -13
  152. package/src/templates/next-default/lib/styles/fonts.ts +0 -20
  153. package/src/templates/next-default/lib/styles/index.css +0 -3
  154. package/src/templates/next-default/lib/styles/tokens.css +0 -179
  155. package/src/templates/next-default/lib/utils/README.md +0 -40
  156. package/src/templates/next-default/lib/utils/easings.ts +0 -240
  157. package/src/templates/next-default/lib/utils/fetch.ts +0 -84
  158. package/src/templates/next-default/lib/utils/global-css.d.ts +0 -1
  159. package/src/templates/next-default/lib/utils/math.ts +0 -236
  160. package/src/templates/next-default/lib/utils/strings.ts +0 -246
  161. package/src/templates/next-default/lib/utils/types.d.ts +0 -15
  162. package/src/templates/next-default/lib/utils/viewport.ts +0 -199
  163. package/src/templates/next-experiments/lib/scripts/dev.ts +0 -32
  164. package/src/templates/next-experiments/lib/styles/README.md +0 -13
  165. package/src/templates/next-experiments/lib/styles/fonts.ts +0 -20
  166. package/src/templates/next-experiments/lib/styles/index.css +0 -3
  167. package/src/templates/next-experiments/lib/styles/tokens.css +0 -179
  168. package/src/templates/next-experiments/lib/utils/README.md +0 -40
  169. package/src/templates/next-experiments/lib/utils/easings.ts +0 -240
  170. package/src/templates/next-experiments/lib/utils/fetch.ts +0 -84
  171. package/src/templates/next-experiments/lib/utils/global-css.d.ts +0 -1
  172. package/src/templates/next-experiments/lib/utils/math.ts +0 -236
  173. package/src/templates/next-experiments/lib/utils/strings.ts +0 -246
  174. package/src/templates/next-experiments/lib/utils/types.d.ts +0 -15
  175. package/src/templates/next-experiments/lib/utils/viewport.ts +0 -199
  176. package/src/templates/next-webgl/lib/scripts/dev.ts +0 -32
  177. package/src/templates/next-webgl/lib/styles/README.md +0 -13
  178. package/src/templates/next-webgl/lib/styles/fonts.ts +0 -20
  179. package/src/templates/next-webgl/lib/styles/index.css +0 -3
  180. package/src/templates/next-webgl/lib/styles/tokens.css +0 -179
  181. package/src/templates/next-webgl/lib/utils/README.md +0 -40
  182. package/src/templates/next-webgl/lib/utils/easings.ts +0 -240
  183. package/src/templates/next-webgl/lib/utils/fetch.ts +0 -84
  184. package/src/templates/next-webgl/lib/utils/global-css.d.ts +0 -1
  185. package/src/templates/next-webgl/lib/utils/math.ts +0 -236
  186. package/src/templates/next-webgl/lib/utils/strings.ts +0 -246
  187. package/src/templates/next-webgl/lib/utils/types.d.ts +0 -15
  188. package/src/templates/next-webgl/lib/utils/viewport.ts +0 -199
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "next-pagebuilder",
3
+ "description": "Basement Next.js starter template",
4
+ "version": "0.1.0",
5
+ "private": true,
6
+ "scripts": {
7
+ "analyze": "cross-env ANALYZE=true bun run build",
8
+ "analyze:experimental": "next experimental-analyze",
9
+ "build": "next build",
10
+ "dev": "next dev",
11
+ "format": "biome format --write .",
12
+ "generate": "bun ./lib/scripts/generate.ts",
13
+ "lighthouse": "bunx @unlighthouse/cli --site http://localhost:3000",
14
+ "lint": "biome lint --max-diagnostics=200",
15
+ "lint:fix": "biome lint --write --unsafe --max-diagnostics=200",
16
+ "start": "next start",
17
+ "test": "bun test",
18
+ "typecheck": "tsgo --noEmit",
19
+ "typecheck:compare": "bun run typecheck:tsc && bun run typecheck",
20
+ "typecheck:tsc": "tsc --noEmit --incremental false",
21
+ "sanity:extract": "cd lib/integrations/sanity && bun --env-file ../../../.env.local sanity schema extract",
22
+ "sanity:typegen": "bun ./lib/scripts/sanity-typegen.ts",
23
+ "predev": "bun run sanity:typegen",
24
+ "prebuild": "bun run sanity:typegen"
25
+ },
26
+ "dependencies": {
27
+ "@phosphor-icons/react": "^2.1.10",
28
+ "@portabletext/types": "^4.0.2",
29
+ "@sanity/asset-utils": "^2.3.0",
30
+ "@sanity/image-url": "^2.0.3",
31
+ "@sanity/table": "^2.0.1",
32
+ "@sanity/vision": "^5.17.1",
33
+ "@sanity/visual-editing": "^5.3.1",
34
+ "class-variance-authority": "^0.7.1",
35
+ "next": "16.2.3",
36
+ "next-sanity": "^12.1.4",
37
+ "react": "19.2.4",
38
+ "react-dom": "19.2.4",
39
+ "react-use": "^17.6.0",
40
+ "sanity": "^5.17.1",
41
+ "sanity-plugin-media": "^4.1.1",
42
+ "schema-dts": "^2.0.0",
43
+ "tailwind-merge": "^3.5.0",
44
+ "zod": "^4.3.6"
45
+ },
46
+ "devDependencies": {
47
+ "@biomejs/biome": "2.4.8",
48
+ "@clack/prompts": "^1.1.0",
49
+ "@csstools/postcss-global-data": "^4.0.0",
50
+ "@next/bundle-analyzer": "16.2.1",
51
+ "@svgr/webpack": "^8.1.0",
52
+ "@tailwindcss/postcss": "^4.2.2",
53
+ "@types/bun": "^1.3.11",
54
+ "@types/node": "^25.5.0",
55
+ "@types/react": "^19.2.14",
56
+ "@types/react-dom": "^19.2.3",
57
+ "@typescript/native-preview": "^7.0.0-dev.20260323.1",
58
+ "babel-plugin-react-compiler": "1.0.0",
59
+ "cross-env": "^10.1.0",
60
+ "postcss-functions": "^4.0.2",
61
+ "postcss-preset-env": "^11.2.0",
62
+ "tailwindcss": "^4.2.2",
63
+ "typescript": "^5.9.3"
64
+ },
65
+ "trustedDependencies": [
66
+ "@biomejs/biome",
67
+ "@tailwindcss/oxide",
68
+ "esbuild",
69
+ "sharp"
70
+ ]
71
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * PostCSS preset-env config
3
+ * @see Docs {@link https://github.com/csstools/postcss-plugins/blob/main/plugin-packs/postcss-preset-env/README.md#options}
4
+ * @see Features Flags {@link https://github.com/csstools/postcss-plugins/blob/main/plugin-packs/postcss-preset-env/FEATURES.md}
5
+ * @type {import('postcss-preset-env').pluginOptions}
6
+ */
7
+ const presetEnvConfig = {
8
+ autoprefixer: {
9
+ flexbox: "no-2009",
10
+ },
11
+ stage: 3,
12
+ features: {
13
+ "custom-properties": false,
14
+ "custom-media-queries": true,
15
+ "nesting-rules": true,
16
+ },
17
+ }
18
+
19
+ /**
20
+ * PostCSS global data config
21
+ * Makes sure the css module files have access to these context files
22
+ * @see {@link https://github.com/csstools/postcss-global-data?tab=readme-ov-file#options}
23
+ * @type {import('@csstools/postcss-global-data').pluginOptions}
24
+ */
25
+ const globalDataConfig = {
26
+ files: ["./lib/styles/global.css"],
27
+ }
28
+
29
+ const postcssConfig = {
30
+ // NOTE: Order is important
31
+ plugins: {
32
+ "@tailwindcss/postcss": {},
33
+ "@csstools/postcss-global-data": globalDataConfig,
34
+ // NOTE: This has to be last config
35
+ "postcss-preset-env": presetEnvConfig,
36
+ },
37
+ }
38
+
39
+ export default postcssConfig
@@ -0,0 +1,81 @@
1
+ import type { NextRequest } from "next/server"
2
+ import { NextResponse } from "next/server"
3
+ import {
4
+ acceptHeaderRoutes,
5
+ ignoredPaths,
6
+ mdExtensionRoutes,
7
+ } from "@/lib/integrations/sanity/markdown-proxy.config"
8
+
9
+ export function proxy(request: NextRequest) {
10
+ const { pathname } = request.nextUrl
11
+ const acceptHeader = request.headers.get("accept") || ""
12
+
13
+ if (ignoredPaths.some((p) => pathname.startsWith(p))) {
14
+ return NextResponse.next()
15
+ }
16
+
17
+ if (pathname === "/" && acceptHeader.includes("text/markdown")) {
18
+ const url = request.nextUrl.clone()
19
+ url.pathname = "/api/index.md"
20
+ return NextResponse.rewrite(url)
21
+ }
22
+
23
+ // 1. Rewrite .md extension URLs to API routes
24
+ // e.g. /about.md → /api/about.md
25
+ for (const route of mdExtensionRoutes) {
26
+ const match = route.regex.exec(pathname)
27
+ if (match) {
28
+ const slug = match[1]
29
+ const url = request.nextUrl.clone()
30
+ url.pathname = route.apiPath.replace("[slug]", slug!)
31
+ return NextResponse.rewrite(url)
32
+ }
33
+ }
34
+
35
+ // 2. Accept: text/markdown — rewrite to markdown API route
36
+ if (acceptHeader.includes("text/markdown")) {
37
+ for (const route of acceptHeaderRoutes) {
38
+ const match = route.regex.exec(pathname)
39
+ if (match) {
40
+ const slug = match[1]
41
+ const url = request.nextUrl.clone()
42
+ url.pathname = route.apiPath.replace("[slug]", slug!)
43
+ return NextResponse.rewrite(url)
44
+ }
45
+ }
46
+ }
47
+
48
+ // 3. Add Link header for markdown discoverability on HTML page requests
49
+ const response = NextResponse.next()
50
+
51
+ if (pathname === "/") {
52
+ response.headers.set(
53
+ "Link",
54
+ '</index.md>; rel="alternate"; type="text/markdown"'
55
+ )
56
+ response.headers.set("Vary", "Accept")
57
+ return response
58
+ }
59
+
60
+ for (const route of acceptHeaderRoutes) {
61
+ const match = route.regex.exec(pathname)
62
+ if (match) {
63
+ const slug = match[1]
64
+ const mdUrl = route.publicPath.replace("[slug]", slug!)
65
+ response.headers.set(
66
+ "Link",
67
+ `<${mdUrl}>; rel="alternate"; type="text/markdown"`
68
+ )
69
+ response.headers.set("Vary", "Accept")
70
+ break
71
+ }
72
+ }
73
+
74
+ return response
75
+ }
76
+
77
+ export const config = {
78
+ matcher: [
79
+ "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|sitemap.md|robots.txt).*)",
80
+ ],
81
+ }
@@ -0,0 +1,5 @@
1
+ declare module "*.svg" {
2
+ import type { FC, SVGProps } from "react"
3
+ const content: FC<SVGProps<SVGSVGElement>>
4
+ export default content
5
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "noImplicitOverride": true,
17
+ "exactOptionalPropertyTypes": true,
18
+ "useUnknownInCatchVariables": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+ "noImplicitReturns": true,
21
+ "noUncheckedSideEffectImports": true,
22
+ "noUnusedLocals": true,
23
+ "noUnusedParameters": true,
24
+ "noUncheckedIndexedAccess": true,
25
+ "plugins": [{ "name": "next" }],
26
+ "types": ["bun", "node"],
27
+ "paths": { "@/*": ["./*"] }
28
+ },
29
+ "include": [
30
+ "next-env.d.ts",
31
+ "**/*.ts",
32
+ "**/*.tsx",
33
+ ".next/types/**/*.ts",
34
+ ".next/dev/types/**/*.ts",
35
+ "**/*.mts"
36
+ ],
37
+ "exclude": ["node_modules"]
38
+ }
@@ -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
  },
@@ -35,17 +35,16 @@ lib/
35
35
  scripts/
36
36
  store/
37
37
  styles/
38
- index.css
39
- tokens.css
40
38
  global.css
41
- fonts.ts
42
39
  cn.ts
43
40
  utils/
41
+ metadata.ts
42
+ portable-text-to-markdown.ts
43
+ json-ld.ts
44
44
  ```
45
45
 
46
46
  ## Styling
47
47
 
48
- - Import `@/lib/styles/index.css` once in `app/layout.tsx`.
49
- - Edit `lib/styles/tokens.css` for theme variables, breakpoints, and custom Tailwind utilities.
50
- - Edit `lib/styles/global.css` for reset rules and app-wide global styles.
51
- - `lib/styles/fonts.ts` handles font variables.
48
+ - Import `@/lib/styles/global.css` once in `app/layout.tsx`.
49
+ - `lib/styles/global.css` includes Tailwind utilities, theme tokens, and app-wide global styles.
50
+ - `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",