- TypeScript 75.6%
- CSS 14.5%
- Shell 6.9%
- HTML 3%
|
Some checks failed
Build / build (push) Failing after 52s
Removes the Docker wrapper from build.sh in favor of running pnpm and composer natively. The CI workflow now delegates to build.sh --ci and sets minimumReleaseAge in pnpm config. |
||
|---|---|---|
| .forgejo/workflows | ||
| plugins | ||
| src | ||
| .gitignore | ||
| .rules | ||
| build.sh | ||
| components.json | ||
| index.html | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Preact Template
A minimal Preact project template with TypeScript, Tailwind CSS v4, and Vite 7.
Stack
- Framework: Preact 10 + TypeScript
- Build Tool: Vite 7
- Styling: Tailwind CSS v4 (via
@tailwindcss/vite) - Fonts: JetBrains Mono (bundled via @fontsource)
- Icons: Lucide (Preact-compatible)
- UI Components: Minimal shadcn-style components in
src/components/ui/
Architecture
src/
├── App.tsx # Route dispatcher (path-based routing via window.location.pathname)
├── main.tsx # Preact entry point with ErrorBoundary
├── ErrorFallback.tsx # Error boundary fallback UI
├── index.css # Single source of truth for all styles
├── pages/ # Page components (one file per route)
│ └── Home.tsx # Home page component
├── components/
│ └── ui/ # shadcn-style UI components (Button, Alert)
├── lib/ # Utility functions
└── assets/ # Images, favicon
Styling System
Single CSS file: src/index.css contains:
- Tailwind CSS imports
- Custom CSS variables for the theme (OKLCH color space)
- Custom
@keyframesanimations (fade-in) - Accessibility support (prefers-reduced-motion)
Custom color palette (OKLCH):
--background/--foreground: Base surface and text colors--primary: Brand primary color (indigo)--card: Card surface color--cyan,--magenta,--matrix-green: Extended accent colors
DO NOT create additional CSS files. All styling goes in index.css or inline Tailwind classes.
Build Configuration
Vite config (vite.config.ts):
- Preact plugin for JSX transformation
- Tailwind CSS v4 via
@tailwindcss/vite - Image optimization via
vite-plugin-image-optimizer(85% quality) - Terser minification (drop console, mangle toplevel, 2-pass)
- Lightning CSS for CSS minification
- Path alias:
@/→src/
TypeScript: --noCheck flag used in build script for faster builds
Build System
CRITICAL: All dependency management happens inside Docker containers via build.sh. Never run pnpm commands directly on the host for production builds.
./build.sh # Build project (output in dist/)
./build.sh install # Fresh install + audit + build
./build.sh clean # Remove node_modules, dist, caches
./build.sh update # Update dependencies to latest compatible versions
./build.sh audit # Run security audit
The build.sh script:
- Runs all pnpm commands inside ephemeral
node:latestDocker containers - Mounts current directory as
/appwith user permissions - Installs pnpm globally in container's temp directory
- Builds from
src/→ outputs todist/
Development
For quick iteration without Docker (not recommended for production builds):
pnpm dev # Dev server at http://localhost:5173
pnpm build # Build to dist/
pnpm preview # Preview production build
pnpm lint # ESLint check
Making Changes
- Edit source files in
src/ - Test with
pnpm devor./build.sh - The build output goes to
dist/
Dependency Management
To add/remove dependencies:
- Edit
package.json - Run
./build.sh installto reinstall and rebuild - Test the build works before committing
Conventions
Preact vs React
- Import from
preactandpreact/hooks, NOTreact - Use
react-error-boundaryfor error boundaries (Preact compatibility) - Button component uses
@radix-ui/react-slotwithasChildpattern for polymorphic rendering
Tailwind Configuration
- CSS variables: Defined in
:rootand@themeblocks inindex.css - Components config:
components.jsondefines shadcn paths/aliases
Adding UI Components
Follow shadcn-style patterns:
- Components go in
src/components/ui/ - Use
class-variance-authorityfor variant props - Use
tailwind-mergevia@/lib/utilsfor className merging - Export component with TypeScript interface
Adding Pages (Routing)
The app uses path-based routing via window.location.pathname in src/App.tsx — no router library needed.
- Create a new page component in
src/pages/(e.g.,src/pages/About.tsx) - Add a route condition in
src/App.tsx:if (path === "/about") return <About />; - Server config: Caddy must have
try_files {path} /index.htmlin the site block so unknown paths serve the SPA'sindex.html. Without this, direct navigation to routes returns 404.
Icon Usage
Icons via lucide-react. Import specific icons to avoid bundle bloat.
Image Optimization
SVG and raster images in src/assets/ are automatically optimized during build via vite-plugin-image-optimizer (uses Sharp for rasters, SVGO for vectors).
What NOT to Do
- Don't run pnpm commands directly on host for production builds (use
./build.sh) - Don't create additional CSS files (
index.cssis the single source of truth) - Don't duplicate color variables or animation definitions
- Don't add animation libraries (define custom keyframes in
index.cssinstead) - Don't add a
tailwind.config.js(Tailwind v4 is configured via CSS@themeblock) - Don't add a router library — use
window.location.pathnameinApp.tsxwith page components insrc/pages/ - Don't add generic documentation files that don't reflect actual codebase state