feat(blocks): stack-astro/react-vite/sveltekit/tailwind
This commit is contained in:
parent
2ba5754948
commit
c94646dd3c
4 changed files with 128 additions and 0 deletions
36
_blocks/stack-astro.md
Normal file
36
_blocks/stack-astro.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# STACK — Astro 6 (Content + Marketing + Islands)
|
||||
|
||||
Use for marketing sites, content-heavy sites, docs, and landing pages. Zero-JS by default; interactivity is opt-in per component via islands.
|
||||
|
||||
**When to pick:** the page is >70% static content (marketing, blog, docs, portfolio). For app-like surfaces (dashboards, editors, long session state) prefer `stack-nextjs` or `stack-react-vite`.
|
||||
|
||||
**Routing:** file-based (`src/pages/`). `.astro` components render to HTML at build time. Dynamic routes via `[slug].astro` + `getStaticPaths`.
|
||||
|
||||
**Islands:** any framework component (React / Svelte / Vue / Solid) renders via an integration and takes a `client:*` directive:
|
||||
|
||||
- `client:load` — hydrate immediately (interactive from first paint)
|
||||
- `client:idle` — hydrate when main thread idle
|
||||
- `client:visible` — hydrate when visible (default for below-fold widgets)
|
||||
- `client:media="(max-width: 768px)"` — hydrate only on matching viewport
|
||||
- `client:only="react"` — skip SSR entirely (client-only components)
|
||||
|
||||
No directive = zero JS shipped. Never add one "just in case".
|
||||
|
||||
**React integration:** `npx astro add react` → installs `@astrojs/react`. Then import and use `.tsx` components inside `.astro` with a `client:*` directive where interactivity is needed.
|
||||
|
||||
**Deploy adapter (Cloudflare default):** `npx astro add cloudflare` → installs `@astrojs/cloudflare`. In `astro.config.mjs` set `output: "server"` (for per-request SSR) or `"hybrid"` (pre-render by default, SSR where opted in). Static-only builds need no adapter — `astro build` emits `dist/`.
|
||||
|
||||
**Content collections:** `src/content/<collection>/*.md(x)` + `src/content/config.ts` (Zod schema). Type-safe queries via `getCollection(name)`. Use for blog posts, case studies, docs.
|
||||
|
||||
**View Transitions:** `import { ViewTransitions } from "astro:transitions"` — 2 lines in the base layout, zero JS overhead. Pairs well with the `motion-design` skill.
|
||||
|
||||
**Env vars:**
|
||||
- Build-time: `import.meta.env.FOO` (inlined). `PUBLIC_*` prefix is client-visible; everything else is build-host only.
|
||||
- Runtime (server/SSR): via adapter runtime (`context.locals.runtime.env` on Cloudflare Workers).
|
||||
- Secrets go in platform env (Cloudflare dashboard / `.dev.vars` locally). NEVER in `astro.config.mjs`.
|
||||
|
||||
**Images:** `<Image src={...} />` from `astro:assets` — automatic `srcset`, `sizes`, `width`/`height`, AVIF/WebP fallback. Pair with `web-assets` skill for pipeline details.
|
||||
|
||||
**Typical stack:** Astro 6 + TypeScript + Tailwind 4 (via `stack-tailwind`) + `@astrojs/react` for islands + `adapter-cloudflare` + Content Collections. Files > 200 LOC get split (Constructor Pattern).
|
||||
|
||||
**Forbidden:** `client:load` on static content, importing React at the top of `.astro` pages that don't render interactive components, secrets in `PUBLIC_*` vars, mixing two UI frameworks without a concrete reason (ships multiple hydration runtimes).
|
||||
26
_blocks/stack-react-vite.md
Normal file
26
_blocks/stack-react-vite.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# STACK — Vite + React 19 + TypeScript (SPA)
|
||||
|
||||
Use for single-page applications, internal dashboards, editors, design tools — surfaces where the page IS the app and SEO / zero-JS don't matter. For marketing use `stack-astro`. For full-stack React with Server Components use `stack-nextjs`.
|
||||
|
||||
**Scaffold:** `npm create vite@latest <app> -- --template react-ts`. Dev server via `vite`; production via `vite build` → `dist/` (static files).
|
||||
|
||||
**Routing:** `react-router-dom` v7 (data routers, `createBrowserRouter`). One file per route under `src/routes/`. For file-based routing prefer TanStack Router (first-class TS inference).
|
||||
|
||||
**Data:**
|
||||
- Server state → TanStack Query v5 (`useQuery` / `useMutation`). Never `useEffect + fetch`.
|
||||
- Client state → Zustand or `useState` — pick one per feature, don't layer Redux unless the team already uses it.
|
||||
- Form state → React Hook Form v7 + Zod resolver (single schema client + server).
|
||||
|
||||
**Rendering:** React 19's `useActionState`, `useOptimistic`, and the `use()` hook for promise unwrapping. `Suspense` + `ErrorBoundary` on every route boundary. No conditional rendering that hides suspense errors.
|
||||
|
||||
**Types first:** Props/interfaces declared BEFORE the component. Discriminated unions for variant props. `as const` for finite-set string unions. No `any` in new code — use `unknown` + type-guards.
|
||||
|
||||
**Env vars:** `import.meta.env.VITE_*` — anything NOT prefixed with `VITE_` is stripped at build time. Secrets → backend, never in `VITE_*` (ships to browser).
|
||||
|
||||
**Styling:** Tailwind 4 (via `stack-tailwind`) OR CSS Modules — never both in the same project. `className` + token classes; no inline `style={{}}` except for dynamic CSS custom properties.
|
||||
|
||||
**Testing:** Vitest + React Testing Library + Playwright for E2E. Tests co-located next to source (`Component.test.tsx`).
|
||||
|
||||
**Deploy target:** the SPA is a static bundle — Cloudflare Pages, Vercel, S3+CloudFront, or any static host. No adapter needed.
|
||||
|
||||
**Forbidden:** `create-react-app` (deprecated), `fetch` inside `useEffect` (use TanStack Query), `any` in new code, secret env vars without the `VITE_` prefix (shipped to client), mixing Redux + Zustand in the same feature, CSS-in-JS runtimes (ships extra KB — use Tailwind or CSS Modules).
|
||||
34
_blocks/stack-sveltekit.md
Normal file
34
_blocks/stack-sveltekit.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# STACK — SvelteKit (Svelte 5 Runes + TS)
|
||||
|
||||
Use for animation-heavy sites, mobile-first interactive surfaces, and apps where smallest-possible runtime matters. Svelte 5 compiles to minimal JS; Runes replace the legacy reactive-label syntax.
|
||||
|
||||
**Scaffold:** `npm create svelte@latest <app>` → choose "SvelteKit", TypeScript strict, ESLint + Prettier.
|
||||
|
||||
**Routing:** file-based (`src/routes/`). Each route is a folder containing `+page.svelte` (UI) + optionally `+page.server.ts` (server load / actions) / `+page.ts` (universal load) / `+layout.svelte`. Dynamic routes via `[slug]/+page.svelte`.
|
||||
|
||||
**Runes (Svelte 5):**
|
||||
- `$state(x)` — reactive value (replaces `let x = ...` + `$:` label)
|
||||
- `$derived(expr)` — computed (replaces `$:` derivations)
|
||||
- `$effect(() => {...})` — side effect (replaces `$:` statements with side effects)
|
||||
- `$props()` — component props (replaces `export let`)
|
||||
- `$bindable()` — two-way binding opt-in
|
||||
|
||||
No more legacy `export let` / `$: foo = bar` in new code. Runes are the canonical API from Svelte 5 onwards.
|
||||
|
||||
**Data flow:**
|
||||
- `+page.server.ts` `load({ fetch, params })` — runs on server only, DB/secrets OK.
|
||||
- `+page.ts` `load(...)` — runs both server (SSR) + client (navigation) — no secrets.
|
||||
- Form actions: `export const actions = { default: async ({ request }) => {...} }` in `+page.server.ts`. Use `<form method="POST">` + progressive enhancement — works without JS.
|
||||
|
||||
**Env vars:**
|
||||
- `$env/static/private` + `$env/dynamic/private` — server-only, secrets OK.
|
||||
- `$env/static/public` + `$env/dynamic/public` — must be prefixed `PUBLIC_`, ships to client.
|
||||
- SvelteKit refuses to build if a private env is imported into a client module — enforcement built in.
|
||||
|
||||
**Deploy adapter (Cloudflare default):** `npm i -D @sveltejs/adapter-cloudflare` and set it in `svelte.config.js`. Alternatives: `adapter-node`, `adapter-vercel`, `adapter-static`. Cloudflare adapter supports KV / R2 / D1 via `platform.env.*` inside load functions.
|
||||
|
||||
**Stores (legacy, still supported):** `writable`, `readable`, `derived` from `svelte/store`. Prefer `$state` in components; use stores only for cross-component shared state that truly needs it.
|
||||
|
||||
**Testing:** Vitest for unit + `@testing-library/svelte` for components + Playwright for E2E.
|
||||
|
||||
**Forbidden:** legacy `export let` + `$:` label syntax for NEW code (use Runes), `$env/static/private` imported into a client-reachable module, mixing runes + legacy reactivity in the same component, hardcoded secrets in `svelte.config.js` (ships to client bundle), adding React/Vue into a SvelteKit app without a very specific reason.
|
||||
32
_blocks/stack-tailwind.md
Normal file
32
_blocks/stack-tailwind.md
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# STACK — Tailwind CSS 4 (compositional add-on)
|
||||
|
||||
This is a **compositional** block — it does NOT stand alone. Layer on top of `stack-nextjs`, `stack-react-vite`, `stack-astro`, or `stack-sveltekit`. Any of those + this = the canonical 2026 "Tailwind project" shape.
|
||||
|
||||
**Version:** Tailwind 4.x — ships as a Vite / PostCSS / CLI plugin, NOT as a dependency you import into your framework code. Config lives in CSS via `@theme` (not `tailwind.config.ts` — that is v3).
|
||||
|
||||
**Minimal setup (v4):**
|
||||
```css
|
||||
/* src/styles/app.css */
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
--color-brand: oklch(0.6 0.2 250);
|
||||
--font-display: "Fraunces Variable", serif;
|
||||
--font-body: "Inter Variable", sans-serif;
|
||||
--radius-card: 0.75rem;
|
||||
}
|
||||
```
|
||||
|
||||
Any `--color-*`, `--font-*`, `--radius-*`, `--spacing-*`, `--breakpoint-*` declared in `@theme` auto-generates utilities (`bg-brand`, `font-display`, `rounded-card`, etc.).
|
||||
|
||||
**Design tokens are CSS custom properties**, not JS config. Same tokens reachable from runtime (`var(--color-brand)`) + Tailwind classes (`text-brand`). Single source of truth; no duplication.
|
||||
|
||||
**Dark mode:** `@custom-variant dark (&:where(.dark, .dark *))` (or `@media (prefers-color-scheme: dark)` for system-driven). Then `dark:bg-neutral-900` works as expected.
|
||||
|
||||
**Utilities forbidden in new code:** `@apply` in component CSS (makes purge harder, obscures which utilities render). Use the class attribute directly, or extract to a real component.
|
||||
|
||||
**Class composition:** use `clsx` or `tailwind-merge` (`cn()` helper pattern) for conditional classes. Never `className={"bg-red " + (active ? "opacity-100" : "opacity-0")}` — use `cn()`.
|
||||
|
||||
**Component libraries:** shadcn/ui (copy-paste, source-owned), Radix primitives, Headless UI — all compatible. Avoid UI kits that ship their own runtime CSS (MUI, Chakra) on top of Tailwind — the two design systems will fight.
|
||||
|
||||
**Forbidden:** `tailwind.config.js` for NEW v4 projects (use `@theme` in CSS), `@apply` beyond tiny one-offs, mixing Tailwind with MUI / Chakra / Bootstrap, hardcoded hex colors in `className` (`bg-[#ff0000]`) outside prototyping — those bypass the token system and drift.
|
||||
Loading…
Reference in a new issue