From 038763fbdccc1ac2d2266d39ad74bd451bf99f95 Mon Sep 17 00:00:00 2001 From: prdHugo <48803115+HugoPerard@users.noreply.github.com> Date: Wed, 26 Aug 2026 04:02:32 -0700 Subject: [PATCH 01/46] feat(landing): add apps workspace, astro tsconfig, and tooling ignores --- .gitignore | 3 +++ .oxlintrc.json | 2 +- packages/typescript-config/astro.json | 13 +++++++++++++ pnpm-workspace.yaml | 1 + turbo.json | 1 + 5 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 packages/typescript-config/astro.json diff --git a/.gitignore b/.gitignore index 96fab4f..1249ff8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,9 @@ coverage # Vercel .vercel +# Astro +.astro + # Build Outputs .next/ out/ diff --git a/.oxlintrc.json b/.oxlintrc.json index 6eef9e4..7e4a6b5 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -18,5 +18,5 @@ "typescript/no-unnecessary-type-parameters": "off", "typescript/no-unsafe-type-assertion": "off" }, - "ignorePatterns": ["**/dist/**", "**/coverage/**"] + "ignorePatterns": ["**/dist/**", "**/coverage/**", "**/.astro/**"] } diff --git a/packages/typescript-config/astro.json b/packages/typescript-config/astro.json new file mode 100644 index 0000000..4bc754b --- /dev/null +++ b/packages/typescript-config/astro.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "allowJs": true, + "jsx": "react-jsx", + "noEmit": true, + "declaration": false, + "declarationMap": false + } +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dee51e9..0e5a073 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,3 @@ packages: - "packages/*" + - "apps/*" diff --git a/turbo.json b/turbo.json index 078c76f..9f25de0 100644 --- a/turbo.json +++ b/turbo.json @@ -14,6 +14,7 @@ "dependsOn": ["^check-types"] }, "dev": { + "dependsOn": ["^build"], "cache": false, "persistent": true }, From 96ec75ee7a6e9ac68072a89bbd3534b92c1aa0ab Mon Sep 17 00:00:00 2001 From: prdHugo <48803115+HugoPerard@users.noreply.github.com> Date: Wed, 26 Aug 2026 04:02:49 -0700 Subject: [PATCH 02/46] feat(landing): add Astro 6 app config, Tailwind 4 theme, and fonts --- apps/landing/astro.config.ts | 30 +++++++++++++++++++++ apps/landing/package.json | 29 ++++++++++++++++++++ apps/landing/public/favicon.svg | 4 +++ apps/landing/src/env.d.ts | 1 + apps/landing/src/styles/global.css | 43 ++++++++++++++++++++++++++++++ apps/landing/tsconfig.json | 10 +++++++ 6 files changed, 117 insertions(+) create mode 100644 apps/landing/astro.config.ts create mode 100644 apps/landing/package.json create mode 100644 apps/landing/public/favicon.svg create mode 100644 apps/landing/src/env.d.ts create mode 100644 apps/landing/src/styles/global.css create mode 100644 apps/landing/tsconfig.json diff --git a/apps/landing/astro.config.ts b/apps/landing/astro.config.ts new file mode 100644 index 0000000..675aa50 --- /dev/null +++ b/apps/landing/astro.config.ts @@ -0,0 +1,30 @@ +import react from "@astrojs/react"; +import tailwindcss from "@tailwindcss/vite"; +import { defineConfig, fontProviders } from "astro/config"; + +export default defineConfig({ + output: "static", + integrations: [react()], + vite: { + plugins: [tailwindcss()], + }, + fonts: [ + { + name: "IBM Plex Sans", + cssVariable: "--font-ibm-plex-sans", + provider: fontProviders.fontsource(), + weights: [400, 500, 600], + styles: ["normal"], + subsets: ["latin", "latin-ext"], + }, + { + name: "IBM Plex Mono", + cssVariable: "--font-ibm-plex-mono", + provider: fontProviders.fontsource(), + weights: [400, 500], + styles: ["normal"], + subsets: ["latin", "latin-ext"], + fallbacks: ["monospace"], + }, + ], +}); diff --git a/apps/landing/package.json b/apps/landing/package.json new file mode 100644 index 0000000..274d4fe --- /dev/null +++ b/apps/landing/package.json @@ -0,0 +1,29 @@ +{ + "name": "landing", + "private": true, + "type": "module", + "license": "MIT", + "scripts": { + "dev": "astro dev", + "build": "astro build", + "preview": "astro preview", + "check-types": "tsc --noEmit", + "lint": "oxlint .", + "format": "oxfmt" + }, + "dependencies": { + "@astrojs/react": "6.0.4", + "@bearstudio/ui-state": "workspace:*", + "astro": "6.4.8", + "react": "19.2.8", + "react-dom": "19.2.8" + }, + "devDependencies": { + "@bearstudio/typescript-config": "workspace:*", + "@tailwindcss/vite": "4.3.3", + "@types/react": "19.2.18", + "@types/react-dom": "19.2.5", + "tailwindcss": "4.3.3", + "typescript": "7.0.2" + } +} diff --git a/apps/landing/public/favicon.svg b/apps/landing/public/favicon.svg new file mode 100644 index 0000000..d2f32f1 --- /dev/null +++ b/apps/landing/public/favicon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/apps/landing/src/env.d.ts b/apps/landing/src/env.d.ts new file mode 100644 index 0000000..f964fe0 --- /dev/null +++ b/apps/landing/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/landing/src/styles/global.css b/apps/landing/src/styles/global.css new file mode 100644 index 0000000..7cd8cd0 --- /dev/null +++ b/apps/landing/src/styles/global.css @@ -0,0 +1,43 @@ +@import "tailwindcss"; + +@theme inline { + --font-sans: var(--font-ibm-plex-sans), ui-sans-serif, system-ui, + sans-serif; + --font-mono: var(--font-ibm-plex-mono), ui-monospace, monospace; + --color-paper: #f3eee4; + --color-paper-2: #e7dfd0; + --color-ink: #1c1915; + --color-ink-soft: #4f4a41; + --color-line: #d5ccba; + --color-accent: #b5521f; + --color-accent-ink: #fff7ee; + --color-code: #171512; + --color-code-muted: #9a9084; + --color-code-kw: #e08a55; + --color-code-str: #8fb58a; + --color-code-fn: #d4b56a; + --color-ok: #2f6f4e; + --color-err: #a33b2b; +} + +html { + scroll-behavior: smooth; +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } +} + +body { + font-family: var(--font-sans); + background: var(--color-paper); + color: var(--color-ink); +} + +code, +pre, +.font-mono { + font-family: var(--font-mono); +} diff --git a/apps/landing/tsconfig.json b/apps/landing/tsconfig.json new file mode 100644 index 0000000..ab13c5b --- /dev/null +++ b/apps/landing/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@bearstudio/typescript-config/astro.json", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "react", + "noEmit": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["dist", "node_modules", ".astro"] +} From 2ea21337b831e8177f8cc6177877750daf1e3de9 Mon Sep 17 00:00:00 2001 From: prdHugo <48803115+HugoPerard@users.noreply.github.com> Date: Wed, 26 Aug 2026 04:03:11 -0700 Subject: [PATCH 03/46] feat(landing): add layout, static product UI, and app README --- apps/landing/README.md | 35 ++++++++++ apps/landing/src/components/HeroCode.astro | 31 +++++++++ .../src/components/NestedTernary.astro | 14 ++++ apps/landing/src/layouts/Layout.astro | 65 +++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 apps/landing/README.md create mode 100644 apps/landing/src/components/HeroCode.astro create mode 100644 apps/landing/src/components/NestedTernary.astro create mode 100644 apps/landing/src/layouts/Layout.astro diff --git a/apps/landing/README.md b/apps/landing/README.md new file mode 100644 index 0000000..f097cf4 --- /dev/null +++ b/apps/landing/README.md @@ -0,0 +1,35 @@ +# landing + +Marketing site for `@bearstudio/ui-state`. Unpublished; no changeset. + +## Run + +From the repo root (Node 24, pnpm 10.34.5): + +```bash +pnpm install +pnpm --filter landing dev +``` + +Root `pnpm dev` / `pnpm build` / `pnpm check-types` / `pnpm lint` also +include this app via turbo. `dev` depends on `^build` so the library +dist exists before the Astro island imports it. + +## Stack + +- Astro 6 SSG + one React island (`client:visible`) +- Tailwind 4 via `@tailwindcss/vite` (not `@astrojs/tailwind`) +- Tokens in `@theme inline` +- `@bearstudio/ui-state` as `workspace:*` +- Fonts: Astro 6 Fonts API, Fontsource, latin + latin-ext, self-hosted + +## Typecheck split + +Library stays NodeNext (`react-library.json`). This app does **not** +extend `react-library.json`. It extends +`@bearstudio/typescript-config/astro.json` (`moduleResolution: Bundler`). + +`check-types` is `tsc --noEmit` on `src/**/*.ts(x)` (the island). +`astro check` is not the source of truth on TypeScript 7 (no compiler API). + +Lint: oxlint. Format: oxfmt. diff --git a/apps/landing/src/components/HeroCode.astro b/apps/landing/src/components/HeroCode.astro new file mode 100644 index 0000000..fe6829d --- /dev/null +++ b/apps/landing/src/components/HeroCode.astro @@ -0,0 +1,31 @@ +--- +// Static product UI — zero JS. Intended LCP: the match + exhaustive sample. +--- + +
+
+ + + +
+ book-screen.tsx +
+
+
import {"{"} getUiState {"}"} from "@bearstudio/ui-state";
+
+const ui = getUiState((set) => {"{"} 
+  if (bookQuery.status === "pending") return set("pending");
+  if (bookQuery.status === "error") return set("error");
+  return set("default", {"{"} book: bookQuery.data {"}"});
+{"}"});
+
+ui.match("pending", () => <>Loading...</>)
+  .match("error", () => <>Error</>)
+  .match("default", ({"{ "} book {"} "}) => <>{"{ "}book.title{"} "}</>)
+  .exhaustive();
+
diff --git a/apps/landing/src/components/NestedTernary.astro b/apps/landing/src/components/NestedTernary.astro new file mode 100644 index 0000000..dfb32c3 --- /dev/null +++ b/apps/landing/src/components/NestedTernary.astro @@ -0,0 +1,14 @@ +--- +// Static “before” sample. Braces escaped so Astro does not evaluate them. +--- +
return isLoading ? (
+  <Spinner />
+) : error ? (
+  <Error />
+) : data ? (
+  <Book book={"{ "}data{"} "} />
+) : (
+  <Empty />
+);
diff --git a/apps/landing/src/layouts/Layout.astro b/apps/landing/src/layouts/Layout.astro new file mode 100644 index 0000000..a2d81ea --- /dev/null +++ b/apps/landing/src/layouts/Layout.astro @@ -0,0 +1,65 @@ +--- +import { Font } from "astro:assets"; +import "../styles/global.css"; + +type Props = { + title: string; + description: string; +}; + +const { title, description } = Astro.props; +const canonical = "https://github.com/BearStudio/ui-state"; +const jsonLd = { + "@context": "https://schema.org", + "@graph": [ + { + "@type": "Organization", + name: "BearStudio", + url: "https://www.bearstudio.fr", + }, + { + "@type": "SoftwareApplication", + name: "@bearstudio/ui-state", + applicationCategory: "DeveloperApplication", + operatingSystem: "Web", + license: "https://opensource.org/licenses/MIT", + url: canonical, + }, + { + "@type": "WebPage", + name: title, + description, + url: canonical, + }, + ], +}; +--- + + + + + + + {title} + + + + + + + + + + +