diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..5ad5032 --- /dev/null +++ b/.env.template @@ -0,0 +1 @@ +CALENDAR_API_KEY= diff --git a/.prettierrc.mjs b/.prettierrc.mjs index f084910..a56ce69 100644 --- a/.prettierrc.mjs +++ b/.prettierrc.mjs @@ -4,6 +4,14 @@ const config = { tabWidth: 4, semi: true, singleQuote: true, + overrides: [ + { + files: '*.md', + options: { + tabWidth: 2, + }, + }, + ], }; export default config; diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..47f0f86 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,263 @@ +# AGENTS.md - Coding Agent Guidelines for VanPOP Website + +## Project Overview + +Static website for VanPOP (Vancouver) built with **Astro v5**, **TypeScript (strict)**, and **Tailwind CSS v4**. Deployed to Cloudflare Pages. Uses **pnpm** as the package manager. + +No client-side framework (React/Vue/Svelte) -- all components are `.astro` single-file components. Blog content is driven by Astro Content Collections using Markdown files with Zod-validated frontmatter. + +## Build / Lint / Test Commands + +| Command | Description | +| -------------- | ----------------------------------------------------- | +| `pnpm dev` | Start dev server (accessible on network via `--host`) | +| `pnpm start` | Start dev server (localhost only) | +| `pnpm build` | Type-check (`astro check`) then build static site | +| `pnpm preview` | Preview the production build locally | + +### Type Checking + +```sh +pnpm astro check +``` + +This is the primary code validation tool. It runs TypeScript checking for both `.ts` and `.astro` files. It is automatically run as part of `pnpm build`. + +### Linting + +- **No ESLint** is configured. Do not add ESLint rules or dependencies. +- **Markdown linting** is handled in CI via `markdownlint-cli2`. Config in `.markdownlint.json` disables line length limits (MD013), inline HTML (MD033), and duplicate headings (MD024). + +### Testing + +There is **no test framework** configured (no vitest, jest, playwright, etc.). There are no test files in the repository. Do not create test infrastructure unless explicitly asked. Validation is done via `astro check` and CI build verification. + +## Code Style + +### Formatting (Prettier) + +Configured in `.prettierrc.mjs`: + +- **Indentation**: 4 spaces (also in `.editorconfig`) +- **Semicolons**: Always (`semi: true`) +- **Quotes**: Single quotes (`singleQuote: true`) +- **Trailing commas**: ES5 style (`trailingComma: 'es5'`) + +### TypeScript + +- Extends `astro/tsconfigs/strict` with `strictNullChecks: true` +- No path aliases -- use relative imports (`../components/Foo.astro`) +- Use `import type` for type-only imports: + + ```ts + import type { CollectionEntry } from 'astro:content'; + ``` + +- **Avoid `as` type assertions.** They bypass the type checker and can hide bugs. Instead: + - Use type guards (`if ('key' in obj)`, `typeof x === 'string'`, etc.) + - Use `satisfies` when you want to validate a value matches a type without widening + - Narrow types with conditional checks rather than casting + - If a cast is truly unavoidable (e.g. working around a third-party library's incomplete types), add a comment explaining why + +### Imports + +Order imports as follows (no enforced linter rule, but follow existing convention): + +1. Astro built-ins (`astro:content`, `astro:transitions`) +2. Third-party packages (`@astrojs/rss`, etc.) +3. Local components (relative paths) +4. Types (using `import type`) + +Example: + +```ts +import { getCollection } from 'astro:content'; +import BaseHead from '../components/BaseHead.astro'; +import Header from '../components/Header.astro'; +import type { CollectionEntry } from 'astro:content'; +``` + +### Naming Conventions + +| Element | Convention | Example | +| ------------------ | --------------------- | ------------------------------------------- | +| Components | PascalCase `.astro` | `BlogPostsPreviewList.astro` | +| Layouts | PascalCase `.astro` | `BlogPost.astro` | +| Pages | kebab-case `.astro` | `get-involved.astro` | +| Blog posts | `YYYYMMDD-slug.md` | `20260213-finding-your-farm.md` | +| Exported constants | UPPER_SNAKE_CASE | `SITE_TITLE`, `INDEX_PAGE_BLOG_POSTS_LIMIT` | +| Variables | camelCase | `postsLimit`, `maxTitleLength` | +| CSS custom props | `--color-vp-*` prefix | `--color-vp-purple` | + +### Astro Component Structure + +Follow the standard Astro single-file component pattern: + +```astro +--- +// 1. Imports +import Footer from '../components/Footer.astro'; +import type { HTMLAttributes } from 'astro/types'; + +// 2. Props interface +interface Props { + title: string; + description?: string; +} + +// 3. Destructure props and component logic +const { title, description } = Astro.props; +--- + + +
+

{title}

+ +
+ + + +``` + +### Component Size & Refactoring + +Keep `.astro` components under **~400 lines**. When a component grows beyond that, refactor by extracting: + +- **Server-side logic** (data fetching, heavy computation) into `src/lib/*.ts` utility modules +- **Client-side helper functions** (pure functions, constants) into `src/scripts/*.ts` modules, imported by the component's ` diff --git a/src/components/EventCalendarNav.astro b/src/components/EventCalendarNav.astro new file mode 100644 index 0000000..ad2aaca --- /dev/null +++ b/src/components/EventCalendarNav.astro @@ -0,0 +1,36 @@ +--- +// Month navigation header for EventCalendar +--- + +
+ +

+ Loading... +

+ +
diff --git a/src/components/EventCardTemplate.astro b/src/components/EventCardTemplate.astro new file mode 100644 index 0000000..ea1686d --- /dev/null +++ b/src/components/EventCardTemplate.astro @@ -0,0 +1,31 @@ +--- +// HTML