diff --git a/.agents/skills/fulldev/SKILL.md b/.agents/skills/fulldev/SKILL.md new file mode 100644 index 000000000..69aeca65a --- /dev/null +++ b/.agents/skills/fulldev/SKILL.md @@ -0,0 +1,189 @@ +--- +name: fulldev +description: Guides Fulldev client projects using Astro, Fulldev UI, content/schema/layout architecture, reusable components, blocks, theming, and shadcn-compatible Fulldev registry installs. Use when working in Fulldev client projects, installing or composing @fulldev components, shaping content-driven Astro pages, or deciding where project responsibilities belong. +--- + +# Fulldev + +Fulldev projects are content-driven Astro sites that use Fulldev UI components +and blocks through the shadcn-compatible `@fulldev` registry. + +This skill is for using Fulldev in client projects. If the current repository +has its own `AGENTS.md`, contributing guide, or project instructions, those +local instructions own repo-specific workflow. + +If you encounter problems with Fulldev UI, discover missing guidance, or see +reusable improvements while using this skill, ask the user whether the agent should +create a pull request for the Fulldev UI library so the improvement can be +shared back with future contributors and agents. Use the Fulldev UI +contributing guide for that workflow: +https://github.com/fulldotdev/ui/blob/main/CONTRIBUTING.md + +## Project Model + +Preferred page flow: + +```text +content frontmatter/body -> schema validation -> layout orchestration -> components/blocks +``` + +Content owns authored copy and semantic configuration. Schemas own contracts. +Layouts own page orchestration. Components and blocks own DOM, behavior, +accessibility, styling, and implementation details. + +Inspect the current project before enforcing conventions. Fulldev architecture +is the target for client projects, but do not silently migrate an existing +different architecture. + +## Core Rules + +- Routes stay thin and hand work to generic rendering or layouts. +- Shared base layouts stay shell-only. +- Page orchestration belongs in layouts. +- Content must not contain raw Astro components, imported icons, SVG/HTML, + Tailwind class strings, or DOM details. +- Content-owned icons are plain names rendered through a project icon component. +- Globals are for cross-page site data, not page-specific block data. +- Components and blocks receive data through props and slots. +- Reusable blocks stay schema-agnostic and do not import content collections, + page schemas, layouts, routes, or other private page architecture. + +## Fulldev UI Usage + +Install Fulldev UI through shadcn-compatible tooling. Do not invent a `fulldev` +CLI command unless the project actually provides one. + +Use the project package runner equivalent of: + +```bash +npx shadcn@latest add @fulldev/ +``` + +Prefer existing `@fulldev` components and blocks before creating local reusable +UI or complete page sections. Read installed source when behavior or API is +unclear. + +## Components + +Reusable UI components commonly live in `src/components/ui//`, +unless the project has a different established convention. + +For Astro component frontmatter: + +- Use `type Props`. +- Destructure `Astro.props` once near the top. +- Destructure `class` as `class: className`. +- Name pass-through props `props`. +- Merge classes with the project's class helper, commonly `cn(...)`. +- Keep content-specific data out of generic UI primitives. + +Local components are application code unless repo-specific instructions say +otherwise. + +## Blocks + +Blocks commonly live in `src/components/blocks`, unless the project has a +different established convention. + +Blocks are production-leaning compositions for content-driven pages. They should +receive project-specific data through props and slots while layouts map +schema-backed content into those props. + +Block conventions: + +- Expose `class?: string` and apply it to the root. +- Keep prop types plain and local. +- Use semantic prop names such as `title`, `description`, `buttons`, + `features`, `services`, `reviews`, `href`, and `icon`. +- Avoid generic collection names like `items`, `entries`, `cards`, or `actions` + unless the block is genuinely generic. +- Button data should not include size when size is a block design decision. +- Images, links, labels, CTAs, and content-owned icons that vary by project, + page, block instance, or locale should come through props. + +## Customization + +Customize theme variables and component variants before editing installed +component source. Use local wrappers or compositions when behavior is +project-specific. + +Prefer semantic CSS variables over one-off style overrides. Keep customization +at the lowest level that owns the decision: theme tokens for global look, +variants for component behavior, layouts for page orchestration, and local +wrappers for project-specific composition. + +## Validation + +Use the project's package manager and local instructions. Keep development +feedback fast: + +- Start or reuse the dev server when presentation, routing, or content changed. +- Read dev server logs occasionally. +- Format touched files when a change is settled. +- Do not run full checks or builds after every small edit. +- Run focused validation for contract changes and broader validation only when + requested or when the change is risky. + +## Workflows + +### Standard Change + +1. Identify the touched responsibility tier. +2. Inspect nearby implementation and naming/composition patterns. +3. Make the smallest coherent change that preserves project architecture. +4. Use the dev server and logs for feedback when presentation or routing is + affected. +5. Run only the relevant validation subset unless final validation is requested. + +### Add Fulldev UI to a Project + +1. Inspect whether the project already has shadcn-compatible configuration. +2. If needed, initialize shadcn-compatible component installation. +3. Ensure `@fulldev` is configured as a registry. +4. Install requested components or blocks with shadcn-compatible tooling. +5. Read installed files and adapt imports only when the project requires it. + +### New or Changed Page Type + +1. Update the layout schema. +2. Add it to the page schema union if the project uses one. +3. Create or update the layout. +4. Add or update content. +5. Keep route files thin. + +### Local Component or Block + +1. Check whether an existing `@fulldev` component or block covers the need. +2. Keep the API small, semantic, and content-first. +3. Keep content and schema concerns out of reusable components/blocks. +4. Treat the result as local application code unless repo-specific instructions + say otherwise. + +### Docs or Examples + +Treat docs as descriptions of the API, not the source of truth for the API. If +docs and implementation disagree, fix the implementation or local contract +first. + +## Progressive Disclosure + +When this skill package includes detailed rule files, load only the files +relevant to the current change: + +- `rules/source-ownership.md` for `src/content`, `src/schemas`, content schemas, + icons, and content/code boundaries. +- `rules/layouts.md` for `src/layouts`, generic layout renderers, base layouts, + and route boundaries. +- `rules/components.md` for reusable UI components and Astro component + conventions. +- `rules/blocks.md` for block prop naming, portability, and layout-to-block + mapping. +- `cli.md` for installing Fulldev UI through shadcn-compatible tooling. +- `customization.md` for theming, CSS variables, and component customization. +- `mcp.md` for using shadcn-compatible MCP tooling with the `@fulldev` + registry. +- `rules/validation.md` before finishing changes, to choose validation commands. +- `rules/anti-patterns.md` when reviewing architecture or investigating drift. + +The core guidance above must stand on its own because a new project may not yet +have any of these files. diff --git a/.agents/skills/fulldev/agents/openai.yaml b/.agents/skills/fulldev/agents/openai.yaml new file mode 100644 index 000000000..0e1355040 --- /dev/null +++ b/.agents/skills/fulldev/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Fulldev" + short_description: "Fulldev Astro architecture and UI guidance" + default_prompt: "Use $fulldev while working in a Fulldev client project." diff --git a/.agents/skills/fulldev/cli.md b/.agents/skills/fulldev/cli.md new file mode 100644 index 000000000..c2296243c --- /dev/null +++ b/.agents/skills/fulldev/cli.md @@ -0,0 +1,73 @@ +# Fulldev CLI Reference + +Fulldev UI uses the shadcn CLI and registry protocol. There is no assumed `fulldev` binary. Say "install the Fulldev component" or "install the Fulldev block", but run shadcn-compatible commands against the `@fulldev` registry. + +## Project Setup + +Configuration is read from `components.json`. + +Initialize shadcn-compatible component installation when the project does not have `components.json`: + +```bash +npx shadcn@latest init +``` + +Add the Fulldev registry: + +```json +{ + "registries": { + "@fulldev": "https://ui.full.dev/r/{name}.json" + } +} +``` + +Use the package runner already used by the project when possible. If the repo uses pnpm, prefer: + +```bash +pnpm dlx shadcn@latest add @fulldev/button +``` + +Otherwise use: + +```bash +npx shadcn@latest add @fulldev/button +``` + +## Common Commands + +Inspect project configuration: + +```bash +npx shadcn@latest info +``` + +Install Fulldev components or blocks: + +```bash +npx shadcn@latest add @fulldev/button +npx shadcn@latest add @fulldev/card @fulldev/section +``` + +Preview what an install would change: + +```bash +npx shadcn@latest add @fulldev/button --dry-run +npx shadcn@latest add @fulldev/button --diff +npx shadcn@latest add @fulldev/button --view +``` + +Search or inspect registry items: + +```bash +npx shadcn@latest search @fulldev -q "button" +npx shadcn@latest view @fulldev/button +``` + +## Rules + +- Do not invent Fulldev CLI flags or commands. +- Do not fetch registry files manually when the shadcn CLI can preview, diff, view, or install them. +- Before creating local UI or page sections, check whether an `@fulldev` component or block already exists. +- After installing a component or block, read the added files when behavior, imports, or API details matter. +- If a third-party registry item hardcodes aliases, adjust imports to the project's actual aliases. diff --git a/.agents/skills/fulldev/customization.md b/.agents/skills/fulldev/customization.md new file mode 100644 index 000000000..c173a6205 --- /dev/null +++ b/.agents/skills/fulldev/customization.md @@ -0,0 +1,55 @@ +# Fulldev Customization + +Fulldev UI follows the shadcn-style semantic token model. Prefer changing theme variables and composing installed components before editing component source. + +## Theming Order + +1. Change semantic CSS variables. +2. Use built-in component props or variants. +3. Compose local wrappers or project components. +4. Edit installed component source only when the desired behavior belongs to the component itself. + +## Semantic Tokens + +Use semantic utilities and CSS variables such as: + +- `bg-background` / `text-foreground` +- `bg-card` / `text-card-foreground` +- `bg-primary` / `text-primary-foreground` +- `bg-secondary` / `text-secondary-foreground` +- `text-muted-foreground` +- `border-border` +- `ring-ring` + +Avoid raw project colors in reusable components when a semantic token fits. + +## Tailwind and CSS Variables + +Use `npx shadcn@latest info` to find the project's Tailwind CSS file and Tailwind version. Edit the existing global CSS file; do not create a second theme entrypoint unless the project already has that convention. + +For Tailwind v4, register custom token mappings in `@theme inline` when needed. For Tailwind v3, use the project's Tailwind config. + +## Component Customization + +Prefer local composition for project-specific behavior: + +```astro +--- +import { Button } from "@/components/ui/button" + +type Props = { + href: string + label: string +} + +const { href, label } = Astro.props +--- + + +``` + +Edit installed component source when the change is a reusable behavior or API correction that should apply everywhere in the project. + +## Content Boundary + +Content may choose semantic values such as `tone`, `icon`, `label`, `href`, and `description`. Content should not choose Tailwind classes, DOM structure, imported icons, or raw SVG/HTML. diff --git a/.agents/skills/fulldev/mcp.md b/.agents/skills/fulldev/mcp.md new file mode 100644 index 000000000..7648ee5db --- /dev/null +++ b/.agents/skills/fulldev/mcp.md @@ -0,0 +1,28 @@ +# Fulldev MCP + +Fulldev registry work can use the shadcn MCP server when it is configured. Treat it as shadcn-compatible registry tooling for `@fulldev` items, not as a separate Fulldev MCP. + +## Use MCP For + +- Listing configured registries. +- Searching the `@fulldev` registry. +- Viewing item metadata and files. +- Getting install commands for Fulldev components. +- Finding examples when the registry exposes them. + +## Use CLI For + +Use the shadcn CLI when you need local project context: + +```bash +npx shadcn@latest info +``` + +The CLI is the source for project aliases, Tailwind version, framework, resolved paths, and installed component state. + +## Rules + +- If MCP and CLI disagree about local project configuration, trust the CLI. +- If MCP is unavailable, use the CLI workflow in `cli.md`. +- Do not assume an MCP server is configured in every client project. +- Do not use MCP as a reason to skip reading installed source files when making edits. diff --git a/.agents/skills/fulldev/rules/anti-patterns.md b/.agents/skills/fulldev/rules/anti-patterns.md new file mode 100644 index 000000000..c0f0483c5 --- /dev/null +++ b/.agents/skills/fulldev/rules/anti-patterns.md @@ -0,0 +1,15 @@ +# Anti-Patterns + +Avoid: + +- Adding page orchestration to routes, content files, `base.astro`, or reusable blocks. +- Treating `src/layouts` as docs-only plumbing. +- Using MDX imports as the default page composition model. +- Adding content fields without updating the matching schema. +- Moving UI implementation details, DOM structure, classes, raw SVG, or component imports into content. +- Hardcoding content-meaningful icons or entries inside reusable blocks. +- Importing `src/content`, globals, page schemas, routes, or docs helpers from reusable blocks/components. +- Adding page-type branching or fallback SEO shaping to `base.astro`. +- Creating local reusable UI before checking whether a Fulldev component already exists. +- Silently migrating a non-Fulldev architecture without surfacing the tradeoff. +- Patching examples to hide broken component behavior, missing exports, or schema drift. diff --git a/.agents/skills/fulldev/rules/blocks.md b/.agents/skills/fulldev/rules/blocks.md new file mode 100644 index 000000000..e3085d986 --- /dev/null +++ b/.agents/skills/fulldev/rules/blocks.md @@ -0,0 +1,118 @@ +# Block Rules + +Project blocks commonly live in `src/components/blocks` unless the repo has a different established convention. + +Blocks are production-leaning compositions for content-driven Astro sites. They receive project-specific data through props and slots, while layouts map schema-backed content into those props. + +## Portability + +Blocks should: + +- Receive project-specific data through props and slots. +- Stay schema-agnostic. +- Not import page schemas or content collection types. +- Not import from `src/content`, `src/layouts`, route files, or private page architecture. +- Not hardcode content-meaningful icons, entries, CTAs, links, labels, or images when they should vary by project, page, block instance, or locale. +- Not import docs-site assets, placeholder images, or other project-owned media. Images rendered by installable blocks should be passed in through props. +- Let layouts map schema-backed content into block props. + +It is fine to import fixed code-owned UX/control icons inside a block. Use the `Icon` component only when the icon name is content/config-owned data. + +Layouts importing reusable blocks and passing schema-backed content into them is the preferred orchestration pattern. In client projects, local blocks are application code unless repo-specific instructions say otherwise. + +## Block File Shape + +For block files: + +- Always expose `class?: string`. +- Destructure `class` as `class: className`. +- Apply the class to the outermost block/root component. +- Use `cn("", className)` when forwarding the root class, even when there are no base classes yet. +- Keep block prop types plain and inline. +- Do not import UI component prop types into blocks. +- Use semantic prop names that describe visible content. + +Example: + +```ts +import { cn } from "@/lib/utils" + +type Props = { + class?: string + title: string + description?: string + buttons?: { + label: string + href: string + icon?: string + variant?: "default" | "outline" | "secondary" | "ghost" + }[] + features: { + title: string + description: string + icon?: string + }[] +} + +const { class: className, title, description, buttons, features } = Astro.props +``` + +## Prop Naming + +Use: + +- `label` for buttons, links, nav items, tabs, menu items, form controls, and other interactive/control visible names. +- `title` for headings and named content entities. +- `description` for supporting copy. +- `icon` for content-owned icon names. +- `href` for link destinations. +- `buttons` for CTA/action button arrays. +- Domain-specific plural collection names such as `features`, `services`, `reviews`, `links`, `plans`, `articles`, `logos`, or `faqs`. + +Avoid generic block collection names like `items`, `entries`, `cards`, or `actions` unless the block is genuinely generic. + +Prop/data naming rules apply only to TypeScript props, content data, schema fields, and local variables that represent data. Never rename Tailwind classes, CSS selectors, `data-*` attributes, slot names, component names, file names, or existing style hooks because of a prop naming rule. + +Tailwind utility classes must remain valid Tailwind classes. For example, keep `items-center`, `items-start`, `items-end`, and `justify-between`; never rewrite them to domain terms such as `features-center`, `services-start`, or `contactItems-center`. + +## Buttons + +For block button rendering, let the block own button size and simple design defaults: + +```astro +{ + buttons?.length && ( +
+ {buttons.map(({ href, label, icon, ...button }, index) => ( + + ))} +
+ ) +} +``` + +Button data should not include `size`; size belongs to the block design. If `target` or `rel` behavior is needed, derive it from `href` in the component where that behavior matters. + +## Rendering and Mapping + +For conditional rendering: + +- Optional arrays: `{buttons?.length && (...)}` +- Optional presentational values: `{description && (...)}` +- Required arrays: map directly with `{features.map(...)}` +- Do not use `? (...) : null` when `&&` communicates the intent. + +For mapping: + +- Map arrays inline when rendering is direct. +- Derive named values in frontmatter when sorting, filtering, combining sources, computing active state, choosing previous/next, assigning meaningful page data, or converting schema content into block props. +- In layouts, deriving named block props is expected. +- In blocks, avoid over-preparing simple prop data. diff --git a/.agents/skills/fulldev/rules/components.md b/.agents/skills/fulldev/rules/components.md new file mode 100644 index 000000000..924fc9296 --- /dev/null +++ b/.agents/skills/fulldev/rules/components.md @@ -0,0 +1,85 @@ +# Component Rules + +Reusable UI components live in `src/components/ui//`. + +- Use kebab-case filenames throughout the repo. +- Keep one folder per component family. +- Expose the public API through an `index.ts` barrel. +- Keep helper files next to the component they support. +- Use the existing `@/*` import alias for `src/*`. +- Preserve nearby naming and composition patterns. + +Prefer existing `@fulldev` components before creating local reusable UI. For complete page sections, check existing `@fulldev` blocks first. Local components are application code unless repo-specific instructions say otherwise. + +## Astro Frontmatter + +Astro frontmatter should make the file's contract obvious: + +- Use `type Props`, not `interface Props`. +- Define `type Props` before reading `Astro.props`. +- Keep `Props` local to the component frontmatter. Do not `export type Props` from `.astro` files unless an external TypeScript module explicitly imports it. +- Let Astro infer prop types from `Props`; do not annotate the assignment or destructuring with `: Props`. +- Do not cast `Astro.props` with `as Props`. If Astro cannot associate a complex local `Props` type with the destructuring, prefer simplifying the type shape or using `satisfies Props`. +- Destructure `Astro.props` once near the top of the frontmatter. +- Derive local values after destructuring. + +Use this pattern: + +```ts +type Props = { + title: string + description?: string +} + +const { title, description } = Astro.props +``` + +Do not use this pattern: + +```ts +const props: Props = Astro.props +const { title }: Props = Astro.props +``` + +## UI Component Files + +For UI component files: + +- Type native attributes with Astro's `HTMLAttributes` or `Polymorphic` helpers. +- Destructure `class` as `class: className`. +- Name the remaining pass-through prop bag `props`. +- Merge classes with `cn(...)`. +- Spread `props` on the intended root/control element. +- Preserve required `data-slot` structure and behavior. + +Example: + +```ts +import type { HTMLAttributes } from "astro/types" + +import { cn } from "@/lib/utils" + +type Props = HTMLAttributes<"div"> & { + size?: "default" | "sm" +} + +const { class: className, size = "default", ...props } = Astro.props +``` + +## Fulldev Components + +Fulldev UI components are installed with shadcn-compatible tooling from the `@fulldev` registry. Use the `shadcn` skill or `cli.md` for CLI details when needed. + +- Install components before recreating them. +- Read installed source when behavior or API is unclear. +- Prefer built-in component props and composition before editing installed component source. +- Use local wrappers when project-specific behavior is needed. +- Keep content-specific data out of generic UI primitives. + +## Local Components + +When creating local project components: + +- Optimize for reusable, content-first Astro composition. +- Keep the public API small, portable, accessible, and consistent with nearby Fulldev components. +- Do not assume local components are part of any registry. diff --git a/.agents/skills/fulldev/rules/layouts.md b/.agents/skills/fulldev/rules/layouts.md new file mode 100644 index 000000000..17512e356 --- /dev/null +++ b/.agents/skills/fulldev/rules/layouts.md @@ -0,0 +1,71 @@ +# Layout Rules + +Routes stay thin. `src/pages/[...page].astro` should remain a content-to-renderer handoff. Do not put page orchestration, page-specific data shaping, SEO mapping, icon mapping, block selection, or layout branching in route files. + +## Layout Renderer + +`src/components/layout-renderer.astro` is the generic bridge from content to layout: + +- Fetch/render the content entry. +- Load the global content entry. +- Resolve the layout by `page.data.type`. +- Pass `global`, `page`, and `headings` to the layout. +- Render `` inside the selected layout. +- Keep the renderer generic and stable. + +## Layouts Own Orchestration + +Layouts live in `src/layouts` and are the only page orchestration layer. Page orchestration means choosing which blocks/components make up a page type, mapping validated content into their props, arranging page sections, coordinating page-specific data, and deciding where `` renders. + +Never put page orchestration in routes, content files, `base.astro`, or reusable blocks. + +## Layout Prop Shape + +For files in `src/layouts`, use the shared prop shape: + +```ts +type Props = { + global: GlobalSchema + page: LayoutSchema +} + +const { global, page } = Astro.props +``` + +Use the specific schema type for `page`, for example `HomeSchema` or `DocSchema`. + +Only include `headings` in a layout's `Props` when that layout uses headings. If included, `headings` must be required, not optional: + +```ts +type Props = { + global: GlobalSchema + page: DocSchema + headings: MarkdownHeading[] +} + +const { global, page, headings } = Astro.props +``` + +Do not define unused layout props. If a layout does not read `headings`, omit it from `Props`. + +Keep page-specific derived values in frontmatter with clear names. Pass explicit props into blocks/components. Do not use `const props = Astro.props` or keep referring to `props.page`. + +## Base Layout + +`src/layouts/base.astro` is the shared shell: + +- Keep it focused on document chrome, head integration, shared navigation, theme/body concerns, and the main shell. +- Pass only shared shell data such as `global`, `page`, and shell navigation options. +- Let `base.astro` forward `page.seo` to head components directly. +- Do not add page-specific SEO mapping, fallback SEO objects, layout-specific branching, or content reshaping in `base.astro`. + +## Adding Page Types + +To add a new page type: + +1. Create `src/schemas/layouts/.ts`. +2. Add it to the discriminated union in `src/schemas/page.ts`. +3. Create `src/layouts/.astro` using the shared prop shape. +4. Ensure `src/components/layout-renderer.astro` can resolve `src/layouts/.astro` from `type: ""`. +5. Add content under `src/content/pages` with `type: `. +6. Keep route files unchanged. diff --git a/.agents/skills/fulldev/rules/source-ownership.md b/.agents/skills/fulldev/rules/source-ownership.md new file mode 100644 index 000000000..893628982 --- /dev/null +++ b/.agents/skills/fulldev/rules/source-ownership.md @@ -0,0 +1,55 @@ +# Source Ownership Rules + +Use this flow for pages: + +```text +content frontmatter/body -> schema validation -> layout orchestration -> block/component props +``` + +## Content + +Content files own authored content and project-specific configuration: + +- Page content lives in `src/content/pages`. +- Global locale content lives in `src/content/globals`. +- Prefer `.md` files with frontmatter and body content. +- Use `.mdx` only when docs/live-code examples require imports or component usage. +- Body Markdown is authored rich content rendered by the layout with ``. +- Structured frontmatter drives schema-backed layout and block composition. +- Content may include schema-validated semantic configuration that changes by page, project, block instance, or locale. + +Content must not contain raw Astro components, imported icons, SVG/HTML, Tailwind class strings, or DOM details. + +## Schemas + +Schemas own the contract: + +- Schemas live in `src/schemas`. +- Layout schemas live in `src/schemas/layouts/.ts`. +- `src/content.config.ts` connects content collections to schemas. +- Page frontmatter uses `type` as the discriminant. +- Every page layout schema must be part of the union in `src/schemas/page.ts`. +- Validate object shape strictly. +- Keep open-ended ecosystem values, such as icon names, permissive when appropriate. + +## Code + +Astro layouts/components own rendering, behavior, DOM structure, imports, accessibility mechanics, styling, responsive behavior, animation, and data-slot internals. + +Content may pass semantic values such as `icon: "rocket"`, `tone: "success"`, or a CTA/link label when those values belong to the content instance. + +## Icons + +Treat icons as one example of the broader content/code boundary: + +- UX/control icons belong in code: chevrons, close icons, menu icons, search icons, disclosure arrows, loading indicators, carousel arrows, and form affordances. +- Content/meaning icons may come from content as plain icon names when the icon changes with the surrounding content, project, or locale. +- Render content-owned icons through `src/components/ui/icon` with ``. +- Import fixed code-owned icons directly from the static SVG packages, using local names with an `Icon` suffix such as `ArrowRightIcon`. +- Keep the current `Icon` contract: plain names are normalized, Lucide is preferred by default, and Simple Icons is used as a fallback mainly for brand/social icons. + +## Global Content + +Use `src/content/globals` for cross-page, locale-aware site data: navigation labels, footer groups, shared site metadata, and other global copy/configuration. + +Do not use globals as a dumping ground for page-specific block data. If content is only used by one page type or page instance, keep it in that page's content file. diff --git a/.agents/skills/fulldev/rules/validation.md b/.agents/skills/fulldev/rules/validation.md new file mode 100644 index 000000000..10c1ecc4e --- /dev/null +++ b/.agents/skills/fulldev/rules/validation.md @@ -0,0 +1,45 @@ +# Validation Rules + +Use the package manager configured by the project. Prefer `pnpm` when the project uses pnpm. + +Honor the Node version required by the project's `package.json`. + +## Development Loop + +Keep development feedback fast: + +- Start or reuse the dev server. +- Read dev server logs occasionally, especially after content, routing, layout, or component changes. +- Use browser/manual inspection when UI presentation changed. +- Do not run full checks or builds after every small edit. +- Do not repeatedly restart the dev server unless logs show it is stale or broken. + +## Formatting + +Format touched files when the change is settled, not after every micro-edit: + +```bash +pnpm exec prettier --write +``` + +Avoid repo-wide formatting unless the user asks for it or the task is explicitly cleanup-oriented. + +## Validation + +Each project owns its exact validation commands. Inspect `package.json`, project docs, and local agent instructions before choosing commands. + +For local validation, run the smallest relevant subset: + +1. If formatting changed, run `pnpm exec prettier --write `. +2. If the project has a typecheck or check command and the change affects contracts, run that command. +3. If final validation is requested or warranted, run the project's documented build/check sequence. + +For risky structural changes, run the smallest relevant subset instead of the whole validation suite. + +## Change Workflow + +1. Identify the area touched: content/schema/layout architecture, UI components, blocks, docs/content, styling, or tooling. +2. Keep content, schema, layout, component, block, and registry responsibilities separate. +3. For content/page/layout changes, update content, schema, and layout together. +4. Keep routes thin and `base.astro` shell-only. +5. Prefer existing patterns. If you must diverge, keep the exception local and explain why the normal architecture does not fit. diff --git a/.agents/skills/shadcn/SKILL.md b/.agents/skills/shadcn/SKILL.md new file mode 100644 index 000000000..d64d5e3ba --- /dev/null +++ b/.agents/skills/shadcn/SKILL.md @@ -0,0 +1,250 @@ +--- +name: shadcn +description: Manages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset". +user-invocable: false +allowed-tools: Bash(npx shadcn@latest *), Bash(pnpm dlx shadcn@latest *) +--- + +# shadcn/ui + +A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI. + +> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn@latest` or `pnpm dlx shadcn@latest` — based on the project's `packageManager`. Examples below use `npx shadcn@latest` but substitute the correct runner for the project. + +## Current Project Context + +```json +!`npx shadcn@latest info --json` +``` + +The JSON above contains the project config and installed components. Use `npx shadcn@latest docs ` to get documentation and example URLs for any component. + +## Principles + +1. **Use existing components first.** Use `npx shadcn@latest search` to check registries before writing custom UI. Check community registries too. +2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table. +3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc. +4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`. + +## Critical Rules + +These rules are **always enforced**. Each links to a file with Incorrect/Correct code pairs. + +### Styling & Tailwind → [styling.md](./rules/styling.md) + +- **`className` for layout, not styling.** Never override component colors or typography. +- **No `space-x-*` or `space-y-*`.** Use `flex` with `gap-*`. For vertical stacks, `flex flex-col gap-*`. +- **Use `size-*` when width and height are equal.** `size-10` not `w-10 h-10`. +- **Use `truncate` shorthand.** Not `overflow-hidden text-ellipsis whitespace-nowrap`. +- **No manual `dark:` color overrides.** Use semantic tokens (`bg-background`, `text-muted-foreground`). +- **Use `cn()` for conditional classes.** Don't write manual template literal ternaries. +- **No manual `z-index` on overlay components.** Dialog, Sheet, Popover, etc. handle their own stacking. + +### Forms & Inputs → [forms.md](./rules/forms.md) + +- **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout. +- **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never raw `Input`/`Textarea` inside `InputGroup`. +- **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.** +- **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` with manual active state. +- **`FieldSet` + `FieldLegend` for grouping related checkboxes/radios.** Don't use a `div` with a heading. +- **Field validation uses `data-invalid` + `aria-invalid`.** `data-invalid` on `Field`, `aria-invalid` on the control. For disabled: `data-disabled` on `Field`, `disabled` on the control. + +### Component Structure → [composition.md](./rules/composition.md) + +- **Items always inside their Group.** `SelectItem` → `SelectGroup`. `DropdownMenuItem` → `DropdownMenuGroup`. `CommandItem` → `CommandGroup`. +- **Use `asChild` (radix) or `render` (base) for custom triggers.** Check `base` field from `npx shadcn@latest info`. → [base-vs-radix.md](./rules/base-vs-radix.md) +- **Dialog, Sheet, and Drawer always need a Title.** `DialogTitle`, `SheetTitle`, `DrawerTitle` required for accessibility. Use `className="sr-only"` if visually hidden. +- **Use full Card composition.** `CardHeader`/`CardTitle`/`CardDescription`/`CardContent`/`CardFooter`. Don't dump everything in `CardContent`. +- **Button has no `isPending`/`isLoading`.** Compose with `Spinner` + `data-icon` + `disabled`. +- **`TabsTrigger` must be inside `TabsList`.** Never render triggers directly in `Tabs`. +- **`Avatar` always needs `AvatarFallback`.** For when the image fails to load. + +### Use Components, Not Custom Markup → [composition.md](./rules/composition.md) + +- **Use existing components before custom markup.** Check if a component exists before writing a styled `div`. +- **Callouts use `Alert`.** Don't build custom styled divs. +- **Empty states use `Empty`.** Don't build custom empty state markup. +- **Toast via `sonner`.** Use `toast()` from `sonner`. +- **Use `Separator`** instead of `
` or `
`. +- **Use `Skeleton`** for loading placeholders. No custom `animate-pulse` divs. +- **Use `Badge`** instead of custom styled spans. + +### Icons → [icons.md](./rules/icons.md) + +- **Icons in `Button` use `data-icon`.** `data-icon="inline-start"` or `data-icon="inline-end"` on the icon. +- **No sizing classes on icons inside components.** Components handle icon sizing via CSS. No `size-4` or `w-4 h-4`. +- **Pass icons as objects, not string keys.** `icon={CheckIcon}`, not a string lookup. + +### CLI + +- **Never decode or fetch preset codes manually.** Pass them directly to `npx shadcn@latest apply --preset ` for existing projects, or `npx shadcn@latest init --preset ` when initializing. + +## Key Patterns + +These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above. + +```tsx +// Form layout: FieldGroup + Field, not div + Label. + + + Email + + + + +// Validation: data-invalid on Field, aria-invalid on the control. + + Email + + Invalid email. + + +// Icons in buttons: data-icon, no sizing classes. + + +// Spacing: gap-*, not space-y-*. +
// correct +
// wrong + +// Equal dimensions: size-*, not w-* h-*. + // correct + // wrong + +// Status colors: Badge variants or semantic tokens, not raw colors. ++20.1% // correct ++20.1% // wrong +``` + +## Component Selection + +| Need | Use | +| -------------------------- | --------------------------------------------------------------------------------------------------- | +| Button/action | `Button` with appropriate variant | +| Form inputs | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` | +| Toggle between 2–5 options | `ToggleGroup` + `ToggleGroupItem` | +| Data display | `Table`, `Card`, `Badge`, `Avatar` | +| Navigation | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` | +| Overlays | `Dialog` (modal), `Sheet` (side panel), `Drawer` (bottom sheet), `AlertDialog` (confirmation) | +| Feedback | `sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` | +| Command palette | `Command` inside `Dialog` | +| Charts | `Chart` (wraps Recharts) | +| Layout | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` | +| Empty states | `Empty` | +| Menus | `DropdownMenu`, `ContextMenu`, `Menubar` | +| Tooltips/info | `Tooltip`, `HoverCard`, `Popover` | + +## Key Fields + +The injected project context contains these key fields: + +- **`aliases`** → use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode. +- **`isRSC`** → when `true`, components using `useState`, `useEffect`, event handlers, or browser APIs need `"use client"` at the top of the file. Always reference this field when advising on the directive. +- **`tailwindVersion`** → `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`. +- **`tailwindCssFile`** → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one. +- **`style`** → component visual treatment (e.g. `nova`, `vega`). +- **`base`** → primitive library (`radix` or `base`). Affects component APIs and available props. +- **`iconLibrary`** → determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`. +- **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc. +- **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA). +- **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`). + +See [cli.md — `info` command](./cli.md) for the full field reference. + +## Component Docs, Examples, and Usage + +Run `npx shadcn@latest docs ` to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content. + +```bash +npx shadcn@latest docs button dialog select +``` + +**When creating, fixing, debugging, or using a component, always run `npx shadcn@latest docs` and fetch the URLs first.** This ensures you're working with the correct API and usage patterns rather than guessing. + +## Workflow + +1. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh. +2. **Check installed components first** — before running `add`, always check the `components` list from project context or list the `resolvedPaths.ui` directory. Don't import components that haven't been added, and don't re-add ones already installed. +3. **Find components** — `npx shadcn@latest search`. +4. **Get docs and examples** — run `npx shadcn@latest docs ` to get URLs, then fetch them. Use `npx shadcn@latest view` to browse registry items you haven't installed. To preview changes to installed components, use `npx shadcn@latest add --diff`. +5. **Install or update** — `npx shadcn@latest add`. When updating existing components, use `--dry-run` and `--diff` to preview changes first (see [Updating Components](#updating-components) below). +6. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `npx shadcn@latest info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project. +7. **Review added components** — After adding a component or block from any registry, **always read the added files and verify they are correct**. Check for missing sub-components (e.g. `SelectItem` without `SelectGroup`), missing imports, incorrect composition, or violations of the [Critical Rules](#critical-rules). Also replace any icon imports with the project's `iconLibrary` from the project context (e.g. if the registry item uses `lucide-react` but the project uses `hugeicons`, swap the imports and icon names accordingly). Fix all issues before moving on. +8. **Registry must be explicit** — When the user asks to add a block or component, **do not guess the registry**. If no registry is specified (e.g. user says "add a login block" without specifying `@shadcn`, `@tailark`, etc.), ask which registry to use. Never default to a registry on behalf of the user. +9. **Switching presets** — Ask the user first: **overwrite**, **partial**, **merge**, or **skip**? + - **Overwrite**: `npx shadcn@latest apply --preset `. Overwrites detected components, fonts, and CSS variables. + - **Partial**: `npx shadcn@latest apply --preset --only theme,font`. Updates only the selected preset parts without reinstalling UI components. Supported values are `theme` and `font`; comma-separated combinations are allowed. `icon` is intentionally not supported, because icon changes may require full component reinstall and transforms. + - **Merge**: `npx shadcn@latest init --preset --force --no-reinstall`, then run `npx shadcn@latest info` to list installed components, then for each installed component use `--dry-run` and `--diff` to [smart merge](#updating-components) it individually. + - **Skip**: `npx shadcn@latest init --preset --force --no-reinstall`. Only updates config and CSS, leaves components as-is. + - **Important**: Always run preset commands inside the user's project directory. `apply` only works in an existing project with a `components.json` file. The CLI automatically preserves the current base (`base` vs `radix`) from `components.json`. If you must use a scratch/temp directory (e.g. for `--dry-run` comparisons), pass `--base ` explicitly — preset codes do not encode the base. + +## Updating Components + +When the user asks to update a component from upstream while keeping their local changes, use `--dry-run` and `--diff` to intelligently merge. **NEVER fetch raw files from GitHub manually — always use the CLI.** + +1. Run `npx shadcn@latest add --dry-run` to see all files that would be affected. +2. For each file, run `npx shadcn@latest add --diff ` to see what changed upstream vs local. +3. Decide per file based on the diff: + - No local changes → safe to overwrite. + - Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications. + - User says "just update everything" → use `--overwrite`, but confirm first. +4. **Never use `--overwrite` without the user's explicit approval.** + +## Quick Reference + +```bash +# Create a new project. +npx shadcn@latest init --name my-app --preset base-nova +npx shadcn@latest init --name my-app --preset a2r6bw --template vite + +# Create a monorepo project. +npx shadcn@latest init --name my-app --preset base-nova --monorepo +npx shadcn@latest init --name my-app --preset base-nova --template next --monorepo + +# Initialize existing project. +npx shadcn@latest init --preset base-nova +npx shadcn@latest init --defaults # shortcut: --template=next --preset=nova (base style implied) + +# Apply a preset to an existing project. +npx shadcn@latest apply --preset a2r6bw +npx shadcn@latest apply a2r6bw +npx shadcn@latest apply --preset a2r6bw --only theme +npx shadcn@latest apply --preset a2r6bw --only font +npx shadcn@latest apply --preset a2r6bw --only theme,font + +# Add components. +npx shadcn@latest add button card dialog +npx shadcn@latest add @magicui/shimmer-button +npx shadcn@latest add --all + +# Preview changes before adding/updating. +npx shadcn@latest add button --dry-run +npx shadcn@latest add button --diff button.tsx +npx shadcn@latest add @acme/form --view button.tsx + +# Search registries. +npx shadcn@latest search @shadcn -q "sidebar" +npx shadcn@latest search @tailark -q "stats" + +# Get component docs and example URLs. +npx shadcn@latest docs button dialog select + +# View registry item details (for items not yet installed). +npx shadcn@latest view @shadcn/button +``` + +**Named presets:** `nova`, `vega`, `maia`, `lyra`, `mira`, `luma` +**Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`) and `laravel` (not supported for monorepo) +**Preset codes:** Version-prefixed base62 strings (e.g. `a2r6bw` or `b0`), from [ui.shadcn.com](https://ui.shadcn.com). + +## Detailed References + +- [rules/forms.md](./rules/forms.md) — FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states +- [rules/composition.md](./rules/composition.md) — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading +- [rules/icons.md](./rules/icons.md) — data-icon, icon sizing, passing icons as objects +- [rules/styling.md](./rules/styling.md) — Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index +- [rules/base-vs-radix.md](./rules/base-vs-radix.md) — asChild vs render, Select, ToggleGroup, Slider, Accordion +- [cli.md](./cli.md) — Commands, flags, presets, templates +- [customization.md](./customization.md) — Theming, CSS variables, extending components diff --git a/.agents/skills/shadcn/agents/openai.yml b/.agents/skills/shadcn/agents/openai.yml new file mode 100644 index 000000000..ab636da86 --- /dev/null +++ b/.agents/skills/shadcn/agents/openai.yml @@ -0,0 +1,5 @@ +interface: + display_name: "shadcn/ui" + short_description: "Manages shadcn/ui components — adding, searching, fixing, debugging, styling, and composing UI." + icon_small: "./assets/shadcn-small.png" + icon_large: "./assets/shadcn.png" diff --git a/.agents/skills/shadcn/assets/shadcn-small.png b/.agents/skills/shadcn/assets/shadcn-small.png new file mode 100644 index 000000000..547154b97 Binary files /dev/null and b/.agents/skills/shadcn/assets/shadcn-small.png differ diff --git a/.agents/skills/shadcn/assets/shadcn.png b/.agents/skills/shadcn/assets/shadcn.png new file mode 100644 index 000000000..b7b6814ac Binary files /dev/null and b/.agents/skills/shadcn/assets/shadcn.png differ diff --git a/.agents/skills/shadcn/cli.md b/.agents/skills/shadcn/cli.md new file mode 100644 index 000000000..77fdb6ab3 --- /dev/null +++ b/.agents/skills/shadcn/cli.md @@ -0,0 +1,276 @@ +# shadcn CLI Reference + +Configuration is read from `components.json`. + +> **IMPORTANT:** Always run commands using the project's package runner: `npx shadcn@latest` or `pnpm dlx shadcn@latest`. Check `packageManager` from project context to choose the right one. Examples below use `npx shadcn@latest` but substitute the correct runner for the project. + +> **IMPORTANT:** Only use the flags documented below. Do not invent or guess flags — if a flag isn't listed here, it doesn't exist. The CLI auto-detects the package manager from the project's lockfile; there is no `--package-manager` flag. + +## Contents + +- Commands: init, apply, add (dry-run, smart merge), search, view, docs, info, build +- Templates: next, vite, start, react-router, astro +- Presets: named, code, URL formats and fields +- Switching presets + +--- + +## Commands + +### `init` — Initialize or create a project + +```bash +npx shadcn@latest init [components...] [options] +``` + +Initializes shadcn/ui in an existing project or creates a new project (when `--name` is provided). Optionally installs components in the same step. + +| Flag | Short | Description | Default | +| ----------------------- | ----- | --------------------------------------------------------- | ------- | +| `--template