diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..830d14a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,173 @@ +# CLAUDE.md — AI Assistant Guide for `ferienhaus` + +## Project Overview + +**BarrierefRei Reisen** is a single-page React application for finding and comparing accessible vacation homes in Germany. The entire interface is in German. The app is frontend-only with no backend, API, or database — all data is static. + +**Stack:** React 19 · Vite 7 · Plain CSS · ESLint 9 · ES Modules + +--- + +## Development Commands + +```bash +npm run dev # Start dev server with hot module replacement (http://localhost:5173) +npm run build # Production build (outputs to dist/) +npm run preview # Preview production build locally +npm run lint # Run ESLint checks +``` + +There are **no tests** configured. To add tests, install Vitest or Jest. + +--- + +## Repository Structure + +``` +ferienhaus/ +├── index.html # HTML entry point, mounts #root +├── vite.config.js # Vite config with React plugin +├── eslint.config.js # ESLint flat config (v9 style) +├── package.json # Dependencies & scripts +├── public/ # Static assets served as-is +└── src/ + ├── main.jsx # Renders into #root + ├── App.jsx # Root component — state, layout, filtering logic + ├── App.css # All application styles (~814 lines) + ├── index.css # Global resets, CSS variables, base typography + ├── assets/ # Static assets imported by components + ├── components/ + │ ├── FilterPanel.jsx # Sidebar: price/guests/type/accessibility filters + │ ├── HausCard.jsx # Card for a single vacation home listing + │ └── CompareTable.jsx # Modal overlay comparing up to 3 selected homes + └── data/ + └── ferienhauser.js # Static data: ACCESSIBILITY_FEATURES + ferienhauser array +``` + +--- + +## Architecture & Data Flow + +### State (all in `App.jsx`) + +| State var | Type | Purpose | +|---------------|------------|-------------------------------------------------| +| `filter` | object | Current filter: `{features[], maxPreis, minPersonen, typ}` | +| `sortBy` | string | `"bewertung"` \| `"preis-asc"` \| `"preis-desc"` \| `"merkmale"` | +| `compareIds` | number[] | IDs of homes selected for comparison (max 3) | +| `showCompare` | boolean | Whether the comparison modal is visible | +| `sidebarOpen` | boolean | Mobile sidebar toggle | + +Filtering and sorting are performed with `useMemo` in `App.jsx` — no external state library. + +### Data Shape + +Each vacation home object in `ferienhauser.js`: +```js +{ + id: number, + name: string, + region: string, + bundesland: string, // German federal state + typ: "Haus" | "Chalet" | "Bungalow" | "Villa" | "Cottage" | "Apartment", + personen: number, // max guest capacity + schlafzimmer: number, // bedroom count + preisProNacht: number, // price per night in EUR + bewertung: number, // star rating (1–5) + anzahlBewertungen: number, // number of reviews + bild: string, // emoji used as image placeholder + beschreibung: string, // German description + accessibility: string[], // keys from ACCESSIBILITY_FEATURES + adresse: string, +} +``` + +Accessibility feature keys (defined in `ACCESSIBILITY_FEATURES`): +- **mobility:** `rollstuhlgerecht`, `rampe`, `aufzug`, `breiteSchieren`, `erdgeschoss` +- **bathroom:** `bodengleicheDusche`, `haltegriffe` +- **kitchen:** `behindertengerechteKueche` +- **outdoor:** `parkplatz`, `pool`, `strandnah` +- **sensory:** `sehbehinderung`, `hoerbehinderung` +- **general:** `haustiere` + +--- + +## Key Conventions + +### Language +All UI text, labels, and data are in **German**. Keep new UI text in German. + +### JavaScript / JSX +- ES Modules (`"type": "module"` in package.json) — always use `import`/`export` +- React function components with hooks only — no class components +- No TypeScript (type declaration packages are present but not used) +- `useMemo` for expensive derived state; `useState` for local UI state +- ESLint flat config (v9): avoid unused imports and variables + +### CSS +- All styles in `App.css` (component styles) and `index.css` (global resets) +- CSS custom properties defined in `:root` in `index.css`: + - Colors: `--primary`, `--primary-dark`, `--primary-light`, `--accent`, `--danger`, gray scale + - Utilities: `--radius`, `--shadow-sm`, `--shadow-md`, `--shadow-lg` +- Responsive breakpoints: `@media (max-width: 900px)` and `@media (max-width: 600px)` +- No CSS preprocessor, no CSS Modules, no CSS-in-JS +- Follow existing BEM-like class naming: `app-header`, `card-grid`, `filter-panel`, etc. + +### Component Props + +**``** +- `filter`: current filter object +- `onFilterChange`: setter from `useState` + +**``** +- `haus`: single vacation home object +- `isSelected`: whether this home is in the comparison list +- `onToggleCompare(id)`: callback to add/remove from comparison +- `compareCount`: current comparison list length (to enforce 3-item max) + +**``** +- `hauser`: array of vacation home objects (max 3) +- `onRemove(id)`: removes a home from comparison (closes modal if last one removed) +- `onClose()`: closes the modal without removing homes + +--- + +## Filter Defaults + +```js +const DEFAULT_FILTER = { features: [], maxPreis: 400, minPersonen: 1, typ: "Alle" }; +``` + +The "reset filters" button in `FilterPanel` and the empty-state button both reset to this value. + +--- + +## Adding New Data + +To add more vacation homes, append to the `ferienhauser` array in `src/data/ferienhauser.js`. Each entry must have a unique numeric `id`. The `accessibility` array should contain only keys present in `ACCESSIBILITY_FEATURES`. + +To add a new accessibility feature, add it to the `ACCESSIBILITY_FEATURES` object with `label`, `icon` (emoji), and `category` (`"mobility"` | `"bathroom"` | `"kitchen"` | `"outdoor"` | `"sensory"` | `"general"`). The `FilterPanel` groups and renders features by category automatically. + +--- + +## What Is NOT Present (Yet) + +- No tests (no Vitest, Jest, or Testing Library) +- No TypeScript (packages installed but unused) +- No backend or API calls +- No environment variables / `.env` files +- No CI/CD pipeline +- No routing (single-page, no React Router) +- No state management library (no Redux, Zustand, etc.) +- No Prettier or other formatter — only ESLint + +--- + +## ESLint Rules of Note + +```js +// Unused vars are errors, EXCEPT uppercase/underscore-prefixed names +"no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]" }] +``` + +Run `npm run lint` before committing. Lint errors will block the build in CI if one is added.