From 5b537ca344ea2318782ba217f2d8d9580e7fff4e Mon Sep 17 00:00:00 2001 From: cc Date: Sun, 8 Nov 2026 17:11:40 +0100 Subject: [PATCH 1/2] Add poesis-saf-agentic-harness and poesis-saf-agentic-organization (pre-release 1.0.0-alpha.3) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/plugin/marketplace.json | 66 +- CODEOWNERS | 4 +- CODE_OF_CONDUCT.md | 148 +- CONTRIBUTING.md | 58 +- LICENSE | 42 +- README.md | 72 +- SECURITY.md | 62 +- SUPPORT.md | 26 +- plugins/spark/README.md | 66 +- .../spark/skills/spark-app-template/SKILL.md | 980 ++++----- .../references/color-palettes.md | 1038 ++++----- .../references/component-patterns.md | 1954 ++++++++--------- .../references/design-system.md | 1182 +++++----- .../references/performance-checklist.md | 1256 +++++------ .../references/prd-template.md | 604 ++--- .../references/radix-migration-guide.md | 558 ++--- .../references/typography-pairings.md | 950 ++++---- .../stacks/complex-application.md | 1792 +++++++-------- .../stacks/content-showcase.md | 904 ++++---- .../stacks/data-dashboard.md | 890 ++++---- .../stacks/default-webapp.md | 854 +++---- 21 files changed, 6785 insertions(+), 6721 deletions(-) diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index 13e38cc..00204f7 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -434,6 +434,70 @@ "xpp" ], "license": "MIT" + }, + { + "name": "poesis-saf-agentic-harness", + "source": { + "source": "github", + "repo": "poesis-cloud/saf-agentic-harness", + "ref": "plugin-v1.0.0-alpha.3" + }, + "description": "Deterministic governance - regulation - supervision - coordination of agentic organization: workflow orchestration; step, model, skill, instruction resolution; artifact transaction and versioning; logging; agent authorization. (Pre-release / preview, v1.0.0-alpha.3; install via: marketplace add poesis-cloud/saf-marketplace#preview.)", + "version": "1.0.0-alpha.3", + "author": { + "name": "Poesis SAS", + "email": "clement.cazaud@poesis.cloud" + }, + "homepage": "https://docs.poesis.cloud/saf/", + "repository": "https://github.com/poesis-cloud/saf-agentic-harness", + "keywords": [ + "harness", + "organization", + "governance", + "regulation", + "supervision", + "coordination", + "orchestration", + "workflow", + "agent", + "skill", + "instruction", + "artifact", + "template" + ], + "license": "Apache-2.0" + }, + { + "name": "poesis-saf-agentic-organization", + "source": { + "source": "github", + "repo": "poesis-cloud/saf-agentic-organization", + "ref": "plugin-v1.0.0-alpha.3" + }, + "description": "A governed - regulated - supervised - coordinated SAFe-shaped agentic organization: portfolio, program and team orchestrators with a specialist bench. (Pre-release / preview, v1.0.0-alpha.3; install via: marketplace add poesis-cloud/saf-marketplace#preview.)", + "version": "1.0.0-alpha.3", + "author": { + "name": "Poesis SAS", + "email": "clement.cazaud@poesis.cloud" + }, + "homepage": "https://docs.poesis.cloud/saf/", + "repository": "https://github.com/poesis-cloud/saf-agentic-organization", + "keywords": [ + "harness", + "organization", + "governance", + "regulation", + "supervision", + "coordination", + "orchestration", + "workflow", + "agent", + "skill", + "instruction", + "artifact", + "template" + ], + "license": "Apache-2.0" } ] -} +} diff --git a/CODEOWNERS b/CODEOWNERS index 9c7c8b4..a2ebbc0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,2 @@ -# This repository is maintained by: -* @copilot-agent-runtime +# This repository is maintained by: +* @copilot-agent-runtime diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 6dc4b12..5a6e927 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,74 +1,74 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -nationality, personal appearance, race, religion, or sexual identity and -orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or -advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at . All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e85861d..b2a53f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,29 +1,29 @@ -## Contributing - -[fork]: https://github.com/github/copilot-plugins/fork -[pr]: https://github.com/github/copilot-plugins/compare - -Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. - -Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE.txt). - -Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. - -## Submitting a pull request - -1. [Fork][fork] and clone the repository -1. Create a new branch: `git checkout -b my-branch-name` -1. Make your change, add tests, and make sure the tests and linter still pass -1. Push to your fork and [submit a pull request][pr] -1. Pat yourself on the back and wait for your pull request to be reviewed and merged. - -Here are a few things you can do that will increase the likelihood of your pull request being accepted: - -- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. -- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). - -## Resources - -- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) -- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) -- [GitHub Help](https://help.github.com) +## Contributing + +[fork]: https://github.com/github/copilot-plugins/fork +[pr]: https://github.com/github/copilot-plugins/compare + +Hi there! We're thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. + +Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE.txt). + +Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. + +## Submitting a pull request + +1. [Fork][fork] and clone the repository +1. Create a new branch: `git checkout -b my-branch-name` +1. Make your change, add tests, and make sure the tests and linter still pass +1. Push to your fork and [submit a pull request][pr] +1. Pat yourself on the back and wait for your pull request to be reviewed and merged. + +Here are a few things you can do that will increase the likelihood of your pull request being accepted: + +- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests. +- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). + +## Resources + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/) +- [GitHub Help](https://help.github.com) diff --git a/LICENSE b/LICENSE index 28a50fa..a567c58 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright GitHub, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright GitHub, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index bab19f9..5f394ae 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,36 @@ -# copilot-plugins - -The official GitHub Copilot plugins collection ✨ - -Extend the power of GitHub Copilot with MCP servers, skills, hooks, and other extensibility tools — all in one place. - -## 🔌 What's Inside - -- **Skills** — Reusable prompts and workflows for common tasks -- **MCP Servers** — Model Context Protocol servers that give Copilot new capabilities *(coming soon)* -- **Hooks** — Custom integrations and event-driven automations -- **Extensibility Tools** — Building blocks for creating your own plugins *(coming soon)* - -## 🌐 External Plugins - -This marketplace also references plugins hosted in other repositories: - -- **[Advanced Security](https://github.com/github/copilot-advanced-security-plugin)** — Access to GitHub Advanced Security capabilities such as dependency scanning and secret scanning. - -- **[Azure DevOps Copilot Plugin](https://github.com/microsoft/azure-devops-copilot-plugin)** — Bring Azure DevOps work-item, repository, and pull-request workflows into GitHub Copilot. - -- **[Microsoft Skills for Fabric](https://github.com/microsoft/skills-for-fabric)** — `fabric-skills`, `powerbi-authoring`. Skills and agents for Microsoft Fabric (Lakehouse, Warehouse, Power BI, Eventhouse, Eventstream, Dataflows, Spark). - -- **[Microsoft C++ Language Server](https://github.com/microsoft/cpp-language-server)** — Navigate and interact with your C++ code. - -- **[Microsoft Dataverse](https://github.com/microsoft/Dataverse-skills)** — `dataverse`. Build and manage Dataverse solutions: record CRUD and bulk data, queries, schema and metadata, administration, security, and solution lifecycle through MCP, CLI, and SDK workflows. - -- **[Power Platform Skills](https://github.com/microsoft/power-platform-skills)** — `power-pages`, `model-apps`, `mcp-apps`, `canvas-apps`, `code-apps-preview`, `mobile-app`, `power-automate`. Plugins for Power Platform development (Power Pages sites, model-driven and canvas apps, code apps, MCP App widgets, mobile apps, and Power Automate cloud flows). - -## 🤝 Contributing - -We'd love your contributions! Please read our [Contributing Guide](CONTRIBUTING.md) for details on how to submit pull requests. - -## 📄 License - -This project is licensed under the [MIT License](LICENSE). +# copilot-plugins + +The official GitHub Copilot plugins collection ✨ + +Extend the power of GitHub Copilot with MCP servers, skills, hooks, and other extensibility tools — all in one place. + +## 🔌 What's Inside + +- **Skills** — Reusable prompts and workflows for common tasks +- **MCP Servers** — Model Context Protocol servers that give Copilot new capabilities *(coming soon)* +- **Hooks** — Custom integrations and event-driven automations +- **Extensibility Tools** — Building blocks for creating your own plugins *(coming soon)* + +## 🌐 External Plugins + +This marketplace also references plugins hosted in other repositories: + +- **[Advanced Security](https://github.com/github/copilot-advanced-security-plugin)** — Access to GitHub Advanced Security capabilities such as dependency scanning and secret scanning. + +- **[Azure DevOps Copilot Plugin](https://github.com/microsoft/azure-devops-copilot-plugin)** — Bring Azure DevOps work-item, repository, and pull-request workflows into GitHub Copilot. + +- **[Microsoft Skills for Fabric](https://github.com/microsoft/skills-for-fabric)** — `fabric-skills`, `powerbi-authoring`. Skills and agents for Microsoft Fabric (Lakehouse, Warehouse, Power BI, Eventhouse, Eventstream, Dataflows, Spark). + +- **[Microsoft C++ Language Server](https://github.com/microsoft/cpp-language-server)** — Navigate and interact with your C++ code. + +- **[Microsoft Dataverse](https://github.com/microsoft/Dataverse-skills)** — `dataverse`. Build and manage Dataverse solutions: record CRUD and bulk data, queries, schema and metadata, administration, security, and solution lifecycle through MCP, CLI, and SDK workflows. + +- **[Power Platform Skills](https://github.com/microsoft/power-platform-skills)** — `power-pages`, `model-apps`, `mcp-apps`, `canvas-apps`, `code-apps-preview`, `mobile-app`, `power-automate`. Plugins for Power Platform development (Power Pages sites, model-driven and canvas apps, code apps, MCP App widgets, mobile apps, and Power Automate cloud flows). + +## 🤝 Contributing + +We'd love your contributions! Please read our [Contributing Guide](CONTRIBUTING.md) for details on how to submit pull requests. + +## 📄 License + +This project is licensed under the [MIT License](LICENSE). diff --git a/SECURITY.md b/SECURITY.md index 67a9cbf..85c26ed 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,31 +1,31 @@ -Thanks for helping make GitHub safe for everyone. - -# Security - -GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). - -Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. - -## Reporting Security Issues - -If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. - -**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** - -Instead, please send an email to opensource-security[@]github.com. - -Please include as much of the information listed below as you can to help us better understand and resolve the issue: - - * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) - * Full paths of source file(s) related to the manifestation of the issue - * The location of the affected source code (tag/branch/commit or direct URL) - * Any special configuration required to reproduce the issue - * Step-by-step instructions to reproduce the issue - * Proof-of-concept or exploit code (if possible) - * Impact of the issue, including how an attacker might exploit the issue - -This information will help us triage your report more quickly. - -## Policy - -See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) +Thanks for helping make GitHub safe for everyone. + +# Security + +GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). + +Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation. + +## Reporting Security Issues + +If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. + +**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Instead, please send an email to opensource-security[@]github.com. + +Please include as much of the information listed below as you can to help us better understand and resolve the issue: + + * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Policy + +See [GitHub's Safe Harbor Policy](https://docs.github.com/en/site-policy/security-policies/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) diff --git a/SUPPORT.md b/SUPPORT.md index c2586d4..83967b1 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,13 +1,13 @@ -# Support - -## How to file issues and get help - -This project uses GitHub issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue. - -For help or questions about using this project, please file an issue in the repository. - -- **copilot-plugins** is under active development and maintained by GitHub staff **AND THE COMMUNITY**. We will do our best to respond to support, feature requests, and community questions in a timely manner. - -## GitHub Support Policy - -Support for this project is limited to the resources listed above. +# Support + +## How to file issues and get help + +This project uses GitHub issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue. + +For help or questions about using this project, please file an issue in the repository. + +- **copilot-plugins** is under active development and maintained by GitHub staff **AND THE COMMUNITY**. We will do our best to respond to support, feature requests, and community questions in a timely manner. + +## GitHub Support Policy + +Support for this project is limited to the resources listed above. diff --git a/plugins/spark/README.md b/plugins/spark/README.md index ce9581d..1f3e277 100644 --- a/plugins/spark/README.md +++ b/plugins/spark/README.md @@ -1,33 +1,33 @@ -# Spark - -Comprehensive guidance for building modern web applications with opinionated defaults for tech stack, design system, and code standards. - -## What it does - -Spark helps you quickly bootstrap high-quality web applications by providing: - -- Pre-vetted technology stack choices with multiple complexity-based variations -- An opinionated design philosophy and system -- Step-by-step setup workflows -- Design and performance optimization guidance - -## Skills - -### `spark-app-template` - -Activated when a user wants to create a new web application, dashboard, or interactive interface. Provides guidance on: - -- **Tech stack** — Vite, React 19+, TypeScript, Tailwind CSS v4+, shadcn/ui, TanStack Router & Query -- **Design system** — Typography pairings, OKLCH color palettes, spatial composition, micro-interactions -- **Stack variations** — Pre-configured stacks tailored to app complexity (default web app, content showcase, data dashboard, complex application) -- **Performance** — Core Web Vitals targets, React Compiler setup, optimization checklists -- **Component patterns** — Common shadcn compositions and usage patterns - -## Stack variations - -| Stack | Use case | -| --- | --- | -| **Default Web App** | General-purpose tools, utilities, simple CRUD, MVPs, prototypes | -| **Content Showcase** | Marketing sites, portfolios, blogs, documentation | -| **Data Dashboard** | Analytics dashboards, admin panels, BI tools, monitoring | -| **Complex Application** | SaaS platforms, enterprise tools, multi-view apps | +# Spark + +Comprehensive guidance for building modern web applications with opinionated defaults for tech stack, design system, and code standards. + +## What it does + +Spark helps you quickly bootstrap high-quality web applications by providing: + +- Pre-vetted technology stack choices with multiple complexity-based variations +- An opinionated design philosophy and system +- Step-by-step setup workflows +- Design and performance optimization guidance + +## Skills + +### `spark-app-template` + +Activated when a user wants to create a new web application, dashboard, or interactive interface. Provides guidance on: + +- **Tech stack** — Vite, React 19+, TypeScript, Tailwind CSS v4+, shadcn/ui, TanStack Router & Query +- **Design system** — Typography pairings, OKLCH color palettes, spatial composition, micro-interactions +- **Stack variations** — Pre-configured stacks tailored to app complexity (default web app, content showcase, data dashboard, complex application) +- **Performance** — Core Web Vitals targets, React Compiler setup, optimization checklists +- **Component patterns** — Common shadcn compositions and usage patterns + +## Stack variations + +| Stack | Use case | +| --- | --- | +| **Default Web App** | General-purpose tools, utilities, simple CRUD, MVPs, prototypes | +| **Content Showcase** | Marketing sites, portfolios, blogs, documentation | +| **Data Dashboard** | Analytics dashboards, admin panels, BI tools, monitoring | +| **Complex Application** | SaaS platforms, enterprise tools, multi-view apps | diff --git a/plugins/spark/skills/spark-app-template/SKILL.md b/plugins/spark/skills/spark-app-template/SKILL.md index ddfba1c..7d4adb0 100644 --- a/plugins/spark/skills/spark-app-template/SKILL.md +++ b/plugins/spark/skills/spark-app-template/SKILL.md @@ -1,490 +1,490 @@ ---- -name: spark-app-template -description: Comprehensive guidance for building web apps with opinionated defaults for tech stack, design system, and code standards. Use when user wants to create a new web application, dashboard, or interactive interface. Provides tech choices, styling guidance, project structure, and design philosophy to get users up and running quickly with a fully functional, beautiful web app. ---- - -# Spark App Template - -## Purpose - -Spark App Template provides defaults and guidance for building web applications. When a user asks to build a web app, this skill provides the technical foundation and design direction to create functional applications. - -## When to Use This Skill - -Activate Spark App Template when the user: -- Wants to build a new web application from scratch -- Asks "what stack should I use?" -- Needs guidance on design, styling, or tech choices -- Wants to start a dashboard, interactive tool, data app, or content site -- Requests help choosing between frameworks, libraries, or approaches - -## Quick Start Workflow - -**CRITICAL**: Follow this exact order to avoid configuration errors: - -1. **Create project**: `pnpm create vite@latest my-app --template react-ts` -2. **Install base dependencies**: `pnpm install` -3. **Configure TypeScript path aliases** (tsconfig.json AND tsconfig.app.json - see Step 1 below) -4. **Install Tailwind and tooling**: `pnpm add -D tailwindcss @tailwindcss/vite @biomejs/biome` -5. **Configure vite.config.ts**: Add Tailwind plugin and path aliases -6. **Initialize shadcn**: `pnpm dlx shadcn@latest init` (will now succeed with proper aliases) -7. **Install required shadcn components**: `pnpm dlx shadcn add button card avatar ...` (BEFORE writing components) -8. **Install additional packages**: TanStack Router, Query, Zustand, etc. -9. **Write custom components** (NOW safe to import from `@/components/ui/*`) -10. **Configure routing and state management** -11. **Implement features** - -**Steps 3, 6, and 7 must happen in this exact order** to avoid TypeScript errors and failed shadcn installations. - -## Complexity Levels - -Understanding complexity helps choose the right stack variation and design approach: - -1. **Micro Tool** (single-purpose) - - Examples: Calculator, converter, color picker, timer - - Stack: `stacks/default-webapp.md` - - Focus: Simple, focused UI with minimal state - -2. **Content Showcase** (information-focused) - - Examples: Landing page, portfolio, blog, documentation - - Stack: `stacks/content-showcase.md` - - Focus: Typography, reading experience, visual hierarchy - -3. **Light Application** (multiple features with basic state) - - Examples: Todo list, meal planner, expense tracker - - Stack: `stacks/default-webapp.md` - - Focus: Feature clarity, data persistence, user flows - -4. **Complex Application** (advanced functionality, multiple views) - - Examples: CRM, analytics dashboard, project management tool - - Stack: `stacks/complex-application.md` or `stacks/data-dashboard.md` - - Focus: Navigation, state management, performance optimization - -## Core Tech Stack (Shared Foundation) - -All Spark App Template applications use this foundation: - -### Build & Development -- **Build Tool**: Vite (latest stable) -- **Framework**: React 19+ (leverages new compiler, hooks, and features) -- **Language**: TypeScript -- **Package Manager**: pnpm -- **Linting**: Biome (ESLint fallback for complex plugins) - -### Routing & Data -- **Routing**: TanStack Router (file-based, type-safe) -- **Data Fetching**: TanStack Query -- **Forms**: react-hook-form + Zod validation - -### Styling & UI -- **Styling**: Tailwind CSS v4+ (modern @import syntax) -- **Components**: shadcn/ui (New York style, 45+ components) -- **Icons**: Lucide React (1000+ icons) -- **Color System**: Radix Colors (OKLCH format) -- **Theme**: next-themes (single theme default, dark mode optional) - -### Utilities & Enhancement -- **Animation**: Motion (formerly framer-motion) -- **Notifications**: Sonner -- **Utilities**: CVA (or Tailwind Variants) + clsx + tailwind-merge -- **Error Handling**: react-error-boundary - -## Stack Variations - -All variations share the core foundation above. These templates add specific packages and design guidance: - -### Default Web App (`stacks/default-webapp.md`) -- **Use for**: Most applications, general-purpose tools -- **Additive packages**: None -- **Design focus**: Clean, modern, functional - -### Data Dashboard (`stacks/data-dashboard.md`) -- **Use for**: Analytics, admin panels, data visualization -- **Additive packages**: Recharts (charts), date-fns (date handling) -- **Design focus**: Data density, hierarchical information, scanning patterns - -### Content Showcase (`stacks/content-showcase.md`) -- **Use for**: Marketing sites, portfolios, blogs, documentation -- **Additive packages**: marked (markdown parsing) -- **Design focus**: Typography scale, reading experience, whitespace - -### Complex Application (`stacks/complex-application.md`) -- **Use for**: Multi-view apps, SaaS platforms, enterprise tools -- **Additive packages**: Zustand (state management), date-fns -- **Design focus**: Navigation patterns, state architecture, performance - -## React 19+ Features - -Enable these modern React capabilities: - -### React Compiler -- **Status**: Available in React 19+ -- **Benefits**: Auto-memoization, significantly faster initial loads and interactions -- **Setup**: Compatible with React 17+, configure via compiler config - -### useActionState Hook -- **Use for**: Form handling, async actions, loading states -- **Benefits**: Simplified state management, built-in async handling -- **Pattern**: Consolidates form state, pending state, and error handling - -### useOptimistic Hook -- **Use for**: Instant UI updates before server confirmation -- **Benefits**: Improved perceived performance, better UX -- **Pattern**: Optimistic updates with automatic rollback on failure - -### Server Components -- **Status**: Stable in React 19+ (framework mode only) -- **Frameworks**: Next.js, TanStack Start -- **Note**: For Vite + React SPA apps, use client-side rendering - -## Project Structure Template - -``` -my-app/ -├── index.html -├── package.json -├── tsconfig.json -├── vite.config.ts -├── tailwind.config.js -├── biome.json -├── src/ -│ ├── main.tsx # App entry point -│ ├── App.tsx # Root component -│ ├── index.css # Global styles + theme -│ ├── components/ -│ │ ├── ui/ # shadcn components (don't edit) -│ │ └── ... # Custom components -│ ├── hooks/ -│ │ └── use-mobile.tsx -│ ├── lib/ -│ │ ├── utils.ts # cn() utility -│ │ └── data.ts # Data schemas (if needed) -│ └── routes/ # TanStack Router routes -│ └── __root.tsx -└── public/ # Static assets -``` - -## Design Philosophy - -Beautiful web applications transcend mere functionality - they evoke emotion and form memorable experiences. Follow these principles: - -### Core Principles -1. **Simplicity Through Reduction**: Remove until reaching the simplest effective solution -2. **Material Honesty**: Digital materials have unique properties; embrace them -3. **Obsessive Detail**: Excellence emerges from hundreds of thoughtful decisions -4. **Coherent Design Language**: Every element should feel like part of a unified system -5. **Distinctive Visual Identity**: Create memorable aesthetics, not generic patterns - -### Critical Requirements -- **Use OKLCH color format** (mandatory for 2026) -- **Avoid overused fonts**: Inter, Roboto, Arial, Space Grotesk -- **Choose distinctive typography**: See `references/typography-pairings.md` -- **Validate color contrast**: WCAG AA (4.5:1 normal, 3:1 large text) -- **Single theme by default**: No dark mode unless explicitly requested -- **Variable fonts**: Use single variable font files for performance - -See `references/design-system.md` for comprehensive design guidance. - -## Performance Targets (Core Web Vitals) - -Optimize for these metrics: -- **INP** (Interaction to Next Paint): < 200ms -- **LCP** (Largest Contentful Paint): < 2.5s -- **CLS** (Cumulative Layout Shift): < 0.1 - -Tools to achieve targets: -- React Compiler for automatic memoization -- Vite code-splitting and lazy loading -- Image optimization (WebP, AVIF, lazy loading) -- Font optimization (variable fonts, font-display: swap) - -See `references/performance-checklist.md` for detailed optimization strategies. - -## References - -Access detailed guidance in the `references/` directory: - -1. **design-system.md** - Comprehensive design philosophy, spatial composition, backgrounds, micro-interactions -2. **typography-pairings.md** - Distinctive font combinations with personality guidance -3. **color-palettes.md** - Pre-curated OKLCH palettes with WCAG validation -4. **component-patterns.md** - Common shadcn compositions and usage patterns -5. **performance-checklist.md** - Web Vitals optimization, React Compiler setup -6. **prd-template.md** - Simplified planning framework for new apps -7. **radix-migration-guide.md** - Base UI migration path for Radix concerns - -## Implementation Workflow - -### Step 1: Initialize Project - -**CRITICAL**: Configure path aliases BEFORE running `shadcn init` to avoid validation errors. - -```bash -# Create Vite project -pnpm create vite@latest my-app --template react-ts -# Note: Working directory is now my-app/ - no need to cd - -# Install dependencies -pnpm install - -# Add Tailwind CSS and tooling -pnpm add -D tailwindcss@latest @tailwindcss/vite -pnpm add -D @biomejs/biome -pnpm add -D @tanstack/router-plugin -``` - -**Configure TypeScript Path Aliases** (Required for shadcn): - -Update `tsconfig.json`*: -```json -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ], - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} -``` - -Update `tsconfig.app.json`*: -```json -{ - "compilerOptions": { - // ... existing options ... - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } -} -``` - -Update `vite.config.ts`*: -```typescript -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' -import { TanStackRouterVite } from '@tanstack/router-plugin/vite' -import path from 'path' - -export default defineConfig({ - plugins: [ - TanStackRouterVite(), - react(), - tailwindcss(), - ], - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, -}) -``` - -_* Configuration samples based on Vite + React + TypeScript template structure_ - -**Now shadcn init will succeed**: - -```bash -# Initialize shadcn (path aliases now configured) -pnpm dlx shadcn@latest init - -# CRITICAL: Install shadcn components BEFORE writing custom components -# Identify which components you need first -pnpm dlx shadcn@latest add button card input form dialog avatar badge separator - -# Add TanStack packages -pnpm add @tanstack/react-router @tanstack/react-query - -# Add utilities -pnpm add lucide-react motion sonner react-hook-form zod @hookform/resolvers -pnpm add clsx tailwind-merge class-variance-authority -pnpm add react-error-boundary next-themes -``` - -### Step 2: Configure Project - -See stack templates in `stacks/` for specific configuration examples. - -### Step 3: Create PRD (Optional but Recommended) - -Use `references/prd-template.md` to plan: -- Purpose and mission -- Complexity level -- Essential features -- Design direction -- Color and typography choices - -### Step 4: Install shadcn Components FIRST - -**CRITICAL: Component Installation Order** - -ALWAYS install shadcn components BEFORE writing custom components that import them. This prevents TypeScript errors and failed builds. - -❌ **WRONG ORDER** (causes errors): -```bash -# 1. Write PersonDetail.tsx that imports '@/components/ui/card' -# 2. Run pnpm dlx shadcn add card -# 3. Fix TypeScript errors 'Cannot find module @/components/ui/card' -``` - -✅ **CORRECT ORDER**: -```bash -# 1. Plan which shadcn components you need -# Example: Card, Avatar, Badge, Separator, Button - -# 2. Install ALL required shadcn components FIRST -pnpm dlx shadcn@latest add card avatar badge separator button - -# 3. Verify installation -ls src/components/ui/ # Should show: card.tsx, avatar.tsx, badge.tsx, etc. - -# 4. NOW write PersonDetail.tsx that imports from '@/components/ui/*' -# TypeScript will have proper types and components will exist -``` - -**Planning Checklist**: -1. List all UI components needed for your app -2. Identify which are shadcn components (Card, Button, etc.) -3. Run single `shadcn add` command with all components -4. Verify they exist in `src/components/ui/` -5. Write your custom components that import them - -### Step 5: Implement with Best Practices - -- Follow shadcn component patterns -- Use OKLCH colors in `:root` CSS variables -- Implement responsive design (mobile-first) -- Add error boundaries -- Optimize images and fonts -- Test Core Web Vitals - -## Common Patterns - -### Theme Configuration (index.css) - -```css -@import 'tailwindcss'; - -:root { - /* OKLCH colors - mandatory format */ - --background: oklch(0.97 0.01 75); - --foreground: oklch(0.25 0.02 55); - --primary: oklch(0.52 0.14 155); - --accent: oklch(0.72 0.13 55); - - /* Add more theme variables */ - --radius: 0.75rem; -} - -@theme { - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-primary: var(--primary); - --color-accent: var(--accent); - - /* Radius system */ - --radius-sm: calc(var(--radius) * 0.5); - --radius-md: var(--radius); - --radius-lg: calc(var(--radius) * 1.5); -} -``` - -_Note: Uses Tailwind CSS v4+ @import syntax. For v3, use @tailwind directives instead._ - -### Form Handling - -```tsx -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { z } from 'zod'; - -const schema = z.object({ - email: z.string().email(), - password: z.string().min(8) -}); - -function LoginForm() { - const form = useForm({ - resolver: zodResolver(schema), - defaultValues: { email: '', password: '' } - }); - - async function onSubmit(data: z.infer) { - // Handle form submission - } - - return
...
; -} -``` - -### Data Fetching - -```tsx -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; - -function UserList() { - const queryClient = useQueryClient(); - - const { data, isLoading } = useQuery({ - queryKey: ['users'], - queryFn: fetchUsers - }); - - const createUser = useMutation({ - mutationFn: createUserAPI, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['users'] }); - } - }); - - if (isLoading) return ; - return ; -} -``` - -## Troubleshooting - -### Radix UI Maintenance Concerns - -Radix UI is receiving fewer updates. For new projects or migration concerns: -- See `references/radix-migration-guide.md` for Base UI migration path -- shadcn/ui now supports Base UI as an alternative -- React Aria is another excellent option (Adobe-backed, superior accessibility) - -### Performance Issues - -If app feels slow: -1. Enable React Compiler for automatic memoization -2. Check Core Web Vitals in Chrome DevTools -3. Use `references/performance-checklist.md` -4. Consider code-splitting with TanStack Router's lazy loading - -### Build Tool Alternatives - -Newer Vite versions with Rolldown bundler may offer faster builds when stable. Monitor for stable releases. - -## System Requirements - -- **Node.js**: 18+ (or current LTS version) -- **Package Manager**: pnpm recommended for performance -- **OS**: macOS, Linux, or Windows with WSL2 - -## Next Steps - -After scaffolding: -1. Review the stack template for your complexity level -2. Consult design references for styling -3. Create a PRD to plan features and design -4. Implement following best practices -5. Optimize for Core Web Vitals -6. Deploy to production (Vercel, Netlify, etc.) - ---- - -**Remember**: The goal is functional and performant web applications. Start simple, iterate based on user needs, and prioritize user experience over technical complexity. +--- +name: spark-app-template +description: Comprehensive guidance for building web apps with opinionated defaults for tech stack, design system, and code standards. Use when user wants to create a new web application, dashboard, or interactive interface. Provides tech choices, styling guidance, project structure, and design philosophy to get users up and running quickly with a fully functional, beautiful web app. +--- + +# Spark App Template + +## Purpose + +Spark App Template provides defaults and guidance for building web applications. When a user asks to build a web app, this skill provides the technical foundation and design direction to create functional applications. + +## When to Use This Skill + +Activate Spark App Template when the user: +- Wants to build a new web application from scratch +- Asks "what stack should I use?" +- Needs guidance on design, styling, or tech choices +- Wants to start a dashboard, interactive tool, data app, or content site +- Requests help choosing between frameworks, libraries, or approaches + +## Quick Start Workflow + +**CRITICAL**: Follow this exact order to avoid configuration errors: + +1. **Create project**: `pnpm create vite@latest my-app --template react-ts` +2. **Install base dependencies**: `pnpm install` +3. **Configure TypeScript path aliases** (tsconfig.json AND tsconfig.app.json - see Step 1 below) +4. **Install Tailwind and tooling**: `pnpm add -D tailwindcss @tailwindcss/vite @biomejs/biome` +5. **Configure vite.config.ts**: Add Tailwind plugin and path aliases +6. **Initialize shadcn**: `pnpm dlx shadcn@latest init` (will now succeed with proper aliases) +7. **Install required shadcn components**: `pnpm dlx shadcn add button card avatar ...` (BEFORE writing components) +8. **Install additional packages**: TanStack Router, Query, Zustand, etc. +9. **Write custom components** (NOW safe to import from `@/components/ui/*`) +10. **Configure routing and state management** +11. **Implement features** + +**Steps 3, 6, and 7 must happen in this exact order** to avoid TypeScript errors and failed shadcn installations. + +## Complexity Levels + +Understanding complexity helps choose the right stack variation and design approach: + +1. **Micro Tool** (single-purpose) + - Examples: Calculator, converter, color picker, timer + - Stack: `stacks/default-webapp.md` + - Focus: Simple, focused UI with minimal state + +2. **Content Showcase** (information-focused) + - Examples: Landing page, portfolio, blog, documentation + - Stack: `stacks/content-showcase.md` + - Focus: Typography, reading experience, visual hierarchy + +3. **Light Application** (multiple features with basic state) + - Examples: Todo list, meal planner, expense tracker + - Stack: `stacks/default-webapp.md` + - Focus: Feature clarity, data persistence, user flows + +4. **Complex Application** (advanced functionality, multiple views) + - Examples: CRM, analytics dashboard, project management tool + - Stack: `stacks/complex-application.md` or `stacks/data-dashboard.md` + - Focus: Navigation, state management, performance optimization + +## Core Tech Stack (Shared Foundation) + +All Spark App Template applications use this foundation: + +### Build & Development +- **Build Tool**: Vite (latest stable) +- **Framework**: React 19+ (leverages new compiler, hooks, and features) +- **Language**: TypeScript +- **Package Manager**: pnpm +- **Linting**: Biome (ESLint fallback for complex plugins) + +### Routing & Data +- **Routing**: TanStack Router (file-based, type-safe) +- **Data Fetching**: TanStack Query +- **Forms**: react-hook-form + Zod validation + +### Styling & UI +- **Styling**: Tailwind CSS v4+ (modern @import syntax) +- **Components**: shadcn/ui (New York style, 45+ components) +- **Icons**: Lucide React (1000+ icons) +- **Color System**: Radix Colors (OKLCH format) +- **Theme**: next-themes (single theme default, dark mode optional) + +### Utilities & Enhancement +- **Animation**: Motion (formerly framer-motion) +- **Notifications**: Sonner +- **Utilities**: CVA (or Tailwind Variants) + clsx + tailwind-merge +- **Error Handling**: react-error-boundary + +## Stack Variations + +All variations share the core foundation above. These templates add specific packages and design guidance: + +### Default Web App (`stacks/default-webapp.md`) +- **Use for**: Most applications, general-purpose tools +- **Additive packages**: None +- **Design focus**: Clean, modern, functional + +### Data Dashboard (`stacks/data-dashboard.md`) +- **Use for**: Analytics, admin panels, data visualization +- **Additive packages**: Recharts (charts), date-fns (date handling) +- **Design focus**: Data density, hierarchical information, scanning patterns + +### Content Showcase (`stacks/content-showcase.md`) +- **Use for**: Marketing sites, portfolios, blogs, documentation +- **Additive packages**: marked (markdown parsing) +- **Design focus**: Typography scale, reading experience, whitespace + +### Complex Application (`stacks/complex-application.md`) +- **Use for**: Multi-view apps, SaaS platforms, enterprise tools +- **Additive packages**: Zustand (state management), date-fns +- **Design focus**: Navigation patterns, state architecture, performance + +## React 19+ Features + +Enable these modern React capabilities: + +### React Compiler +- **Status**: Available in React 19+ +- **Benefits**: Auto-memoization, significantly faster initial loads and interactions +- **Setup**: Compatible with React 17+, configure via compiler config + +### useActionState Hook +- **Use for**: Form handling, async actions, loading states +- **Benefits**: Simplified state management, built-in async handling +- **Pattern**: Consolidates form state, pending state, and error handling + +### useOptimistic Hook +- **Use for**: Instant UI updates before server confirmation +- **Benefits**: Improved perceived performance, better UX +- **Pattern**: Optimistic updates with automatic rollback on failure + +### Server Components +- **Status**: Stable in React 19+ (framework mode only) +- **Frameworks**: Next.js, TanStack Start +- **Note**: For Vite + React SPA apps, use client-side rendering + +## Project Structure Template + +``` +my-app/ +├── index.html +├── package.json +├── tsconfig.json +├── vite.config.ts +├── tailwind.config.js +├── biome.json +├── src/ +│ ├── main.tsx # App entry point +│ ├── App.tsx # Root component +│ ├── index.css # Global styles + theme +│ ├── components/ +│ │ ├── ui/ # shadcn components (don't edit) +│ │ └── ... # Custom components +│ ├── hooks/ +│ │ └── use-mobile.tsx +│ ├── lib/ +│ │ ├── utils.ts # cn() utility +│ │ └── data.ts # Data schemas (if needed) +│ └── routes/ # TanStack Router routes +│ └── __root.tsx +└── public/ # Static assets +``` + +## Design Philosophy + +Beautiful web applications transcend mere functionality - they evoke emotion and form memorable experiences. Follow these principles: + +### Core Principles +1. **Simplicity Through Reduction**: Remove until reaching the simplest effective solution +2. **Material Honesty**: Digital materials have unique properties; embrace them +3. **Obsessive Detail**: Excellence emerges from hundreds of thoughtful decisions +4. **Coherent Design Language**: Every element should feel like part of a unified system +5. **Distinctive Visual Identity**: Create memorable aesthetics, not generic patterns + +### Critical Requirements +- **Use OKLCH color format** (mandatory for 2026) +- **Avoid overused fonts**: Inter, Roboto, Arial, Space Grotesk +- **Choose distinctive typography**: See `references/typography-pairings.md` +- **Validate color contrast**: WCAG AA (4.5:1 normal, 3:1 large text) +- **Single theme by default**: No dark mode unless explicitly requested +- **Variable fonts**: Use single variable font files for performance + +See `references/design-system.md` for comprehensive design guidance. + +## Performance Targets (Core Web Vitals) + +Optimize for these metrics: +- **INP** (Interaction to Next Paint): < 200ms +- **LCP** (Largest Contentful Paint): < 2.5s +- **CLS** (Cumulative Layout Shift): < 0.1 + +Tools to achieve targets: +- React Compiler for automatic memoization +- Vite code-splitting and lazy loading +- Image optimization (WebP, AVIF, lazy loading) +- Font optimization (variable fonts, font-display: swap) + +See `references/performance-checklist.md` for detailed optimization strategies. + +## References + +Access detailed guidance in the `references/` directory: + +1. **design-system.md** - Comprehensive design philosophy, spatial composition, backgrounds, micro-interactions +2. **typography-pairings.md** - Distinctive font combinations with personality guidance +3. **color-palettes.md** - Pre-curated OKLCH palettes with WCAG validation +4. **component-patterns.md** - Common shadcn compositions and usage patterns +5. **performance-checklist.md** - Web Vitals optimization, React Compiler setup +6. **prd-template.md** - Simplified planning framework for new apps +7. **radix-migration-guide.md** - Base UI migration path for Radix concerns + +## Implementation Workflow + +### Step 1: Initialize Project + +**CRITICAL**: Configure path aliases BEFORE running `shadcn init` to avoid validation errors. + +```bash +# Create Vite project +pnpm create vite@latest my-app --template react-ts +# Note: Working directory is now my-app/ - no need to cd + +# Install dependencies +pnpm install + +# Add Tailwind CSS and tooling +pnpm add -D tailwindcss@latest @tailwindcss/vite +pnpm add -D @biomejs/biome +pnpm add -D @tanstack/router-plugin +``` + +**Configure TypeScript Path Aliases** (Required for shadcn): + +Update `tsconfig.json`*: +```json +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} +``` + +Update `tsconfig.app.json`*: +```json +{ + "compilerOptions": { + // ... existing options ... + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} +``` + +Update `vite.config.ts`*: +```typescript +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' +import { TanStackRouterVite } from '@tanstack/router-plugin/vite' +import path from 'path' + +export default defineConfig({ + plugins: [ + TanStackRouterVite(), + react(), + tailwindcss(), + ], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, +}) +``` + +_* Configuration samples based on Vite + React + TypeScript template structure_ + +**Now shadcn init will succeed**: + +```bash +# Initialize shadcn (path aliases now configured) +pnpm dlx shadcn@latest init + +# CRITICAL: Install shadcn components BEFORE writing custom components +# Identify which components you need first +pnpm dlx shadcn@latest add button card input form dialog avatar badge separator + +# Add TanStack packages +pnpm add @tanstack/react-router @tanstack/react-query + +# Add utilities +pnpm add lucide-react motion sonner react-hook-form zod @hookform/resolvers +pnpm add clsx tailwind-merge class-variance-authority +pnpm add react-error-boundary next-themes +``` + +### Step 2: Configure Project + +See stack templates in `stacks/` for specific configuration examples. + +### Step 3: Create PRD (Optional but Recommended) + +Use `references/prd-template.md` to plan: +- Purpose and mission +- Complexity level +- Essential features +- Design direction +- Color and typography choices + +### Step 4: Install shadcn Components FIRST + +**CRITICAL: Component Installation Order** + +ALWAYS install shadcn components BEFORE writing custom components that import them. This prevents TypeScript errors and failed builds. + +❌ **WRONG ORDER** (causes errors): +```bash +# 1. Write PersonDetail.tsx that imports '@/components/ui/card' +# 2. Run pnpm dlx shadcn add card +# 3. Fix TypeScript errors 'Cannot find module @/components/ui/card' +``` + +✅ **CORRECT ORDER**: +```bash +# 1. Plan which shadcn components you need +# Example: Card, Avatar, Badge, Separator, Button + +# 2. Install ALL required shadcn components FIRST +pnpm dlx shadcn@latest add card avatar badge separator button + +# 3. Verify installation +ls src/components/ui/ # Should show: card.tsx, avatar.tsx, badge.tsx, etc. + +# 4. NOW write PersonDetail.tsx that imports from '@/components/ui/*' +# TypeScript will have proper types and components will exist +``` + +**Planning Checklist**: +1. List all UI components needed for your app +2. Identify which are shadcn components (Card, Button, etc.) +3. Run single `shadcn add` command with all components +4. Verify they exist in `src/components/ui/` +5. Write your custom components that import them + +### Step 5: Implement with Best Practices + +- Follow shadcn component patterns +- Use OKLCH colors in `:root` CSS variables +- Implement responsive design (mobile-first) +- Add error boundaries +- Optimize images and fonts +- Test Core Web Vitals + +## Common Patterns + +### Theme Configuration (index.css) + +```css +@import 'tailwindcss'; + +:root { + /* OKLCH colors - mandatory format */ + --background: oklch(0.97 0.01 75); + --foreground: oklch(0.25 0.02 55); + --primary: oklch(0.52 0.14 155); + --accent: oklch(0.72 0.13 55); + + /* Add more theme variables */ + --radius: 0.75rem; +} + +@theme { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-primary: var(--primary); + --color-accent: var(--accent); + + /* Radius system */ + --radius-sm: calc(var(--radius) * 0.5); + --radius-md: var(--radius); + --radius-lg: calc(var(--radius) * 1.5); +} +``` + +_Note: Uses Tailwind CSS v4+ @import syntax. For v3, use @tailwind directives instead._ + +### Form Handling + +```tsx +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; + +const schema = z.object({ + email: z.string().email(), + password: z.string().min(8) +}); + +function LoginForm() { + const form = useForm({ + resolver: zodResolver(schema), + defaultValues: { email: '', password: '' } + }); + + async function onSubmit(data: z.infer) { + // Handle form submission + } + + return
...
; +} +``` + +### Data Fetching + +```tsx +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; + +function UserList() { + const queryClient = useQueryClient(); + + const { data, isLoading } = useQuery({ + queryKey: ['users'], + queryFn: fetchUsers + }); + + const createUser = useMutation({ + mutationFn: createUserAPI, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['users'] }); + } + }); + + if (isLoading) return ; + return ; +} +``` + +## Troubleshooting + +### Radix UI Maintenance Concerns + +Radix UI is receiving fewer updates. For new projects or migration concerns: +- See `references/radix-migration-guide.md` for Base UI migration path +- shadcn/ui now supports Base UI as an alternative +- React Aria is another excellent option (Adobe-backed, superior accessibility) + +### Performance Issues + +If app feels slow: +1. Enable React Compiler for automatic memoization +2. Check Core Web Vitals in Chrome DevTools +3. Use `references/performance-checklist.md` +4. Consider code-splitting with TanStack Router's lazy loading + +### Build Tool Alternatives + +Newer Vite versions with Rolldown bundler may offer faster builds when stable. Monitor for stable releases. + +## System Requirements + +- **Node.js**: 18+ (or current LTS version) +- **Package Manager**: pnpm recommended for performance +- **OS**: macOS, Linux, or Windows with WSL2 + +## Next Steps + +After scaffolding: +1. Review the stack template for your complexity level +2. Consult design references for styling +3. Create a PRD to plan features and design +4. Implement following best practices +5. Optimize for Core Web Vitals +6. Deploy to production (Vercel, Netlify, etc.) + +--- + +**Remember**: The goal is functional and performant web applications. Start simple, iterate based on user needs, and prioritize user experience over technical complexity. diff --git a/plugins/spark/skills/spark-app-template/references/color-palettes.md b/plugins/spark/skills/spark-app-template/references/color-palettes.md index 2f69afb..b5bd926 100644 --- a/plugins/spark/skills/spark-app-template/references/color-palettes.md +++ b/plugins/spark/skills/spark-app-template/references/color-palettes.md @@ -1,519 +1,519 @@ -# Color Palettes - Spark App Template - -## OKLCH: The Color Format for 2026 - -OKLCH (Oklab Lightness Chroma Hue) is a perceptually uniform color space. Unlike RGB or HSL, equal numerical changes produce equal perceived differences. - -**Why OKLCH?** -- ✅ Perceptually uniform (50% lightness looks halfway between black and white) -- ✅ Predictable color manipulation -- ✅ Better gamut coverage (more vibrant colors possible) -- ✅ Native browser support (all modern browsers) -- ✅ Easier to maintain consistent contrast - -**OKLCH Format**: -```css -color: oklch(L C H / A); -/* L = Lightness (0-1, where 0.5 is truly middle gray) - C = Chroma (0-0.4, color intensity/saturation) - H = Hue (0-360 degrees) - A = Alpha (0-1, optional) */ -``` - -**Example**: -```css ---primary: oklch(0.55 0.15 265); -/* 55% lightness, medium chroma, blue-purple hue */ -``` - -## Color Palette Structure - -Every Spark App Template app should define these semantic color tokens: - -```css -:root { - /* Base colors */ - --background: oklch(...); - --foreground: oklch(...); - - /* Component backgrounds */ - --card: oklch(...); - --card-foreground: oklch(...); - --popover: oklch(...); - --popover-foreground: oklch(...); - - /* Action colors */ - --primary: oklch(...); - --primary-foreground: oklch(...); - --secondary: oklch(...); - --secondary-foreground: oklch(...); - --accent: oklch(...); - --accent-foreground: oklch(...); - --destructive: oklch(...); - --destructive-foreground: oklch(...); - - /* Supporting colors */ - --muted: oklch(...); - --muted-foreground: oklch(...); - --border: oklch(...); - --input: oklch(...); - --ring: oklch(...); - - /* Optional: Status colors */ - --success: oklch(...); - --warning: oklch(...); - --error: oklch(...); - --info: oklch(...); -} -``` - -## Pre-Curated Palettes - -### Palette 1: Professional Blue (Default) - -Modern, trustworthy, professional. Think Stripe, Linear, Vercel. - -```css -:root { - --background: oklch(0.98 0.01 240); - --foreground: oklch(0.20 0.02 240); - - --card: oklch(1 0 0); - --card-foreground: oklch(0.20 0.02 240); - - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.20 0.02 240); - - --primary: oklch(0.45 0.15 265); /* Deep blue */ - --primary-foreground: oklch(0.99 0 0); - - --secondary: oklch(0.94 0.02 240); - --secondary-foreground: oklch(0.30 0.02 240); - - --accent: oklch(0.68 0.16 240); /* Bright blue */ - --accent-foreground: oklch(0.20 0.02 240); - - --destructive: oklch(0.55 0.20 25); /* Red */ - --destructive-foreground: oklch(0.98 0 0); - - --muted: oklch(0.95 0.01 240); - --muted-foreground: oklch(0.48 0.02 240); - - --border: oklch(0.88 0.02 240); - --input: oklch(0.90 0.01 240); - --ring: oklch(0.45 0.15 265); - - /* Status colors */ - --success: oklch(0.60 0.14 145); /* Green */ - --warning: oklch(0.70 0.16 85); /* Yellow */ - --error: oklch(0.55 0.20 25); /* Red */ - --info: oklch(0.60 0.12 240); /* Blue */ - - --radius: 0.5rem; -} -``` - -**Contrast Checks**: -- Background → Foreground: 12.8:1 ✅ -- Primary → Primary Foreground: 8.2:1 ✅ -- Accent → Accent Foreground: 5.1:1 ✅ - ---- - -### Palette 2: Warm & Inviting - -Organic, friendly, approachable. Think Notion, Figma. - -```css -:root { - --background: oklch(0.98 0.005 85); /* Warm off-white */ - --foreground: oklch(0.22 0.01 75); - - --card: oklch(1 0 0); - --card-foreground: oklch(0.22 0.01 75); - - --primary: oklch(0.50 0.12 35); /* Warm orange-red */ - --primary-foreground: oklch(0.99 0 0); - - --secondary: oklch(0.94 0.02 85); - --secondary-foreground: oklch(0.30 0.01 75); - - --accent: oklch(0.70 0.14 55); /* Warm orange */ - --accent-foreground: oklch(0.22 0.01 75); - - --destructive: oklch(0.52 0.22 30); - --destructive-foreground: oklch(0.98 0 0); - - --muted: oklch(0.96 0.01 85); - --muted-foreground: oklch(0.50 0.01 75); - - --border: oklch(0.88 0.02 85); - --input: oklch(0.92 0.01 85); - --ring: oklch(0.50 0.12 35); - - --success: oklch(0.58 0.15 145); - --warning: oklch(0.75 0.14 85); - --error: oklch(0.52 0.22 30); - --info: oklch(0.58 0.12 240); - - --radius: 0.75rem; /* Larger radius for friendly feel */ -} -``` - ---- - -### Palette 3: Dark Mode Elegant - -Sophisticated dark theme with purple accents. - -```css -:root { - --background: oklch(0.15 0.01 265); /* Deep blue-black */ - --foreground: oklch(0.95 0.01 265); - - --card: oklch(0.18 0.01 265); - --card-foreground: oklch(0.95 0.01 265); - - --popover: oklch(0.18 0.01 265); - --popover-foreground: oklch(0.95 0.01 265); - - --primary: oklch(0.70 0.20 300); /* Bright purple */ - --primary-foreground: oklch(0.15 0.01 265); - - --secondary: oklch(0.22 0.02 265); - --secondary-foreground: oklch(0.85 0.01 265); - - --accent: oklch(0.65 0.25 330); /* Pink-purple */ - --accent-foreground: oklch(0.95 0.01 265); - - --destructive: oklch(0.60 0.24 25); - --destructive-foreground: oklch(0.95 0.01 265); - - --muted: oklch(0.22 0.02 265); - --muted-foreground: oklch(0.60 0.01 265); - - --border: oklch(0.25 0.02 265); - --input: oklch(0.22 0.02 265); - --ring: oklch(0.70 0.20 300); - - --success: oklch(0.65 0.16 145); - --warning: oklch(0.72 0.16 85); - --error: oklch(0.60 0.24 25); - --info: oklch(0.65 0.14 240); - - --radius: 0.5rem; -} -``` - ---- - -### Palette 4: Vibrant & Bold - -High energy, attention-grabbing. Think gaming, creative tools. - -```css -:root { - --background: oklch(0.98 0.01 265); - --foreground: oklch(0.15 0.02 265); - - --card: oklch(1 0 0); - --card-foreground: oklch(0.15 0.02 265); - - --primary: oklch(0.55 0.28 310); /* Hot magenta */ - --primary-foreground: oklch(0.99 0 0); - - --secondary: oklch(0.92 0.03 265); - --secondary-foreground: oklch(0.25 0.02 265); - - --accent: oklch(0.65 0.26 180); /* Cyan */ - --accent-foreground: oklch(0.15 0.02 265); - - --destructive: oklch(0.58 0.26 25); - --destructive-foreground: oklch(0.98 0 0); - - --muted: oklch(0.94 0.02 265); - --muted-foreground: oklch(0.50 0.02 265); - - --border: oklch(0.86 0.03 265); - --input: oklch(0.90 0.02 265); - --ring: oklch(0.55 0.28 310); - - --success: oklch(0.62 0.20 145); - --warning: oklch(0.72 0.18 85); - --error: oklch(0.58 0.26 25); - --info: oklch(0.62 0.16 240); - - --radius: 0.25rem; /* Sharp corners for edgy feel */ -} -``` - ---- - -### Palette 5: Minimalist Monochrome - -Pure focus, maximum clarity. Think Apple, minimalist tools. - -```css -:root { - --background: oklch(1 0 0); /* Pure white */ - --foreground: oklch(0.10 0 0); /* Near black */ - - --card: oklch(0.98 0 0); - --card-foreground: oklch(0.10 0 0); - - --popover: oklch(0.98 0 0); - --popover-foreground: oklch(0.10 0 0); - - --primary: oklch(0.10 0 0); /* Black */ - --primary-foreground: oklch(1 0 0); - - --secondary: oklch(0.94 0 0); - --secondary-foreground: oklch(0.20 0 0); - - --accent: oklch(0.40 0 0); /* Dark gray */ - --accent-foreground: oklch(1 0 0); - - --destructive: oklch(0.30 0 0); - --destructive-foreground: oklch(1 0 0); - - --muted: oklch(0.96 0 0); - --muted-foreground: oklch(0.50 0 0); - - --border: oklch(0.90 0 0); - --input: oklch(0.94 0 0); - --ring: oklch(0.10 0 0); - - --success: oklch(0.50 0 0); - --warning: oklch(0.50 0 0); - --error: oklch(0.30 0 0); - --info: oklch(0.50 0 0); - - --radius: 0rem; /* No rounded corners */ -} -``` - ---- - -### Palette 6: Nature-Inspired Green - -Calm, growth-focused, eco-friendly. Think sustainability, health. - -```css -:root { - --background: oklch(0.98 0.01 145); - --foreground: oklch(0.20 0.02 145); - - --card: oklch(1 0 0); - --card-foreground: oklch(0.20 0.02 145); - - --primary: oklch(0.48 0.14 155); /* Forest green */ - --primary-foreground: oklch(0.99 0 0); - - --secondary: oklch(0.94 0.02 145); - --secondary-foreground: oklch(0.28 0.02 145); - - --accent: oklch(0.65 0.16 135); /* Bright green */ - --accent-foreground: oklch(0.20 0.02 145); - - --destructive: oklch(0.55 0.20 25); - --destructive-foreground: oklch(0.98 0 0); - - --muted: oklch(0.96 0.01 145); - --muted-foreground: oklch(0.50 0.02 145); - - --border: oklch(0.88 0.02 145); - --input: oklch(0.92 0.01 145); - --ring: oklch(0.48 0.14 155); - - --success: oklch(0.62 0.16 145); - --warning: oklch(0.72 0.14 85); - --error: oklch(0.55 0.20 25); - --info: oklch(0.60 0.12 240); - - --radius: 1rem; /* Very rounded for organic feel */ -} -``` - ---- - -## WCAG Contrast Guidelines - -**Required Ratios**: -- **Normal text (< 18px)**: 4.5:1 (AA) or 7:1 (AAA) -- **Large text (≥ 18px or ≥ 14px bold)**: 3:1 (AA) or 4.5:1 (AAA) -- **UI components**: 3:1 minimum - -**Testing Your Colors**: -```css -/* Example: Check if primary text on background passes */ -background: oklch(0.98 0.01 240); /* Light */ -foreground: oklch(0.20 0.02 240); /* Dark */ -/* Contrast ratio: ~13:1 (Passes AAA for all text) ✅ */ -``` - -**Tools**: -- OKLCH Contrast Checker: oklch.com -- Who Can Use: whocanuse.com -- WebAIM Contrast Checker: webaim.org/resources/contrastchecker - -## Validating Your Palette - -Before using any palette, verify these pairings: - -```markdown -✅ Background → Foreground -✅ Card → Card Foreground -✅ Primary → Primary Foreground -✅ Secondary → Secondary Foreground -✅ Accent → Accent Foreground -✅ Muted Background → Muted Foreground -✅ Success/Warning/Error → Background -``` - -## Creating Custom Palettes - -### Step 1: Choose Your Hue - -```css -/* Blue family: 240-270 */ ---hue: 265; - -/* Red family: 0-30 */ ---hue: 25; - -/* Green family: 130-160 */ ---hue: 145; - -/* Purple family: 280-320 */ ---hue: 300; - -/* Orange family: 40-70 */ ---hue: 55; -``` - -### Step 2: Define Lightness Scale - -```css -/* Light theme scale */ ---l-100: 0.98; /* Lightest (backgrounds) */ ---l-200: 0.94; ---l-300: 0.88; ---l-400: 0.80; ---l-500: 0.60; /* Middle */ ---l-600: 0.45; /* Primary actions */ ---l-700: 0.30; ---l-800: 0.20; /* Darkest (text) */ -``` - -### Step 3: Set Chroma (Saturation) - -```css -/* Low chroma = subtle, professional */ ---c-low: 0.05; - -/* Medium chroma = balanced */ ---c-medium: 0.12; - -/* High chroma = vibrant */ ---c-high: 0.20; -``` - -### Step 4: Build Your Palette - -```css -:root { - --background: oklch(0.98 0.01 var(--hue)); - --foreground: oklch(0.20 0.02 var(--hue)); - --primary: oklch(0.45 0.15 var(--hue)); - --accent: oklch(0.68 0.16 var(--hue)); - /* Continue for all tokens */ -} -``` - -## Color Manipulation - -### Lighten/Darken - -```css -/* Original */ ---color: oklch(0.50 0.15 265); - -/* Lighter (increase L) */ ---color-light: oklch(0.70 0.15 265); - -/* Darker (decrease L) */ ---color-dark: oklch(0.30 0.15 265); -``` - -### More/Less Saturated - -```css -/* Original */ ---color: oklch(0.50 0.15 265); - -/* More saturated (increase C) */ ---color-vibrant: oklch(0.50 0.25 265); - -/* Less saturated (decrease C) */ ---color-muted: oklch(0.50 0.05 265); -``` - -### Shift Hue - -```css -/* Original blue */ ---color: oklch(0.50 0.15 265); - -/* Shift to purple */ ---color-purple: oklch(0.50 0.15 300); - -/* Shift to cyan */ ---color-cyan: oklch(0.50 0.15 200); -``` - -### Using color-mix() - -```css -/* Mix two colors */ -.mixed { - background: color-mix(in oklch, var(--primary) 70%, var(--accent) 30%); -} - -/* Lighten with white */ -.lightened { - background: color-mix(in oklch, var(--primary) 80%, white 20%); -} - -/* Darken with black */ -.darkened { - background: color-mix(in oklch, var(--primary) 80%, black 20%); -} -``` - -## Implementing Dark Mode (Optional) - -Only implement dark mode if explicitly requested. Single theme is preferred. - -```css -@media (prefers-color-scheme: dark) { - :root { - --background: oklch(0.15 0.01 265); - --foreground: oklch(0.95 0.01 265); - /* Invert lightness scale */ - } -} -``` - -Or use `next-themes` for manual toggle: - -```tsx -import { ThemeProvider } from 'next-themes'; - - - - -``` - ---- - -**Remember**: Color is emotional. Choose palettes that align with your brand personality, validate contrast for accessibility, and test with real users to ensure your colors communicate effectively. +# Color Palettes - Spark App Template + +## OKLCH: The Color Format for 2026 + +OKLCH (Oklab Lightness Chroma Hue) is a perceptually uniform color space. Unlike RGB or HSL, equal numerical changes produce equal perceived differences. + +**Why OKLCH?** +- ✅ Perceptually uniform (50% lightness looks halfway between black and white) +- ✅ Predictable color manipulation +- ✅ Better gamut coverage (more vibrant colors possible) +- ✅ Native browser support (all modern browsers) +- ✅ Easier to maintain consistent contrast + +**OKLCH Format**: +```css +color: oklch(L C H / A); +/* L = Lightness (0-1, where 0.5 is truly middle gray) + C = Chroma (0-0.4, color intensity/saturation) + H = Hue (0-360 degrees) + A = Alpha (0-1, optional) */ +``` + +**Example**: +```css +--primary: oklch(0.55 0.15 265); +/* 55% lightness, medium chroma, blue-purple hue */ +``` + +## Color Palette Structure + +Every Spark App Template app should define these semantic color tokens: + +```css +:root { + /* Base colors */ + --background: oklch(...); + --foreground: oklch(...); + + /* Component backgrounds */ + --card: oklch(...); + --card-foreground: oklch(...); + --popover: oklch(...); + --popover-foreground: oklch(...); + + /* Action colors */ + --primary: oklch(...); + --primary-foreground: oklch(...); + --secondary: oklch(...); + --secondary-foreground: oklch(...); + --accent: oklch(...); + --accent-foreground: oklch(...); + --destructive: oklch(...); + --destructive-foreground: oklch(...); + + /* Supporting colors */ + --muted: oklch(...); + --muted-foreground: oklch(...); + --border: oklch(...); + --input: oklch(...); + --ring: oklch(...); + + /* Optional: Status colors */ + --success: oklch(...); + --warning: oklch(...); + --error: oklch(...); + --info: oklch(...); +} +``` + +## Pre-Curated Palettes + +### Palette 1: Professional Blue (Default) + +Modern, trustworthy, professional. Think Stripe, Linear, Vercel. + +```css +:root { + --background: oklch(0.98 0.01 240); + --foreground: oklch(0.20 0.02 240); + + --card: oklch(1 0 0); + --card-foreground: oklch(0.20 0.02 240); + + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.20 0.02 240); + + --primary: oklch(0.45 0.15 265); /* Deep blue */ + --primary-foreground: oklch(0.99 0 0); + + --secondary: oklch(0.94 0.02 240); + --secondary-foreground: oklch(0.30 0.02 240); + + --accent: oklch(0.68 0.16 240); /* Bright blue */ + --accent-foreground: oklch(0.20 0.02 240); + + --destructive: oklch(0.55 0.20 25); /* Red */ + --destructive-foreground: oklch(0.98 0 0); + + --muted: oklch(0.95 0.01 240); + --muted-foreground: oklch(0.48 0.02 240); + + --border: oklch(0.88 0.02 240); + --input: oklch(0.90 0.01 240); + --ring: oklch(0.45 0.15 265); + + /* Status colors */ + --success: oklch(0.60 0.14 145); /* Green */ + --warning: oklch(0.70 0.16 85); /* Yellow */ + --error: oklch(0.55 0.20 25); /* Red */ + --info: oklch(0.60 0.12 240); /* Blue */ + + --radius: 0.5rem; +} +``` + +**Contrast Checks**: +- Background → Foreground: 12.8:1 ✅ +- Primary → Primary Foreground: 8.2:1 ✅ +- Accent → Accent Foreground: 5.1:1 ✅ + +--- + +### Palette 2: Warm & Inviting + +Organic, friendly, approachable. Think Notion, Figma. + +```css +:root { + --background: oklch(0.98 0.005 85); /* Warm off-white */ + --foreground: oklch(0.22 0.01 75); + + --card: oklch(1 0 0); + --card-foreground: oklch(0.22 0.01 75); + + --primary: oklch(0.50 0.12 35); /* Warm orange-red */ + --primary-foreground: oklch(0.99 0 0); + + --secondary: oklch(0.94 0.02 85); + --secondary-foreground: oklch(0.30 0.01 75); + + --accent: oklch(0.70 0.14 55); /* Warm orange */ + --accent-foreground: oklch(0.22 0.01 75); + + --destructive: oklch(0.52 0.22 30); + --destructive-foreground: oklch(0.98 0 0); + + --muted: oklch(0.96 0.01 85); + --muted-foreground: oklch(0.50 0.01 75); + + --border: oklch(0.88 0.02 85); + --input: oklch(0.92 0.01 85); + --ring: oklch(0.50 0.12 35); + + --success: oklch(0.58 0.15 145); + --warning: oklch(0.75 0.14 85); + --error: oklch(0.52 0.22 30); + --info: oklch(0.58 0.12 240); + + --radius: 0.75rem; /* Larger radius for friendly feel */ +} +``` + +--- + +### Palette 3: Dark Mode Elegant + +Sophisticated dark theme with purple accents. + +```css +:root { + --background: oklch(0.15 0.01 265); /* Deep blue-black */ + --foreground: oklch(0.95 0.01 265); + + --card: oklch(0.18 0.01 265); + --card-foreground: oklch(0.95 0.01 265); + + --popover: oklch(0.18 0.01 265); + --popover-foreground: oklch(0.95 0.01 265); + + --primary: oklch(0.70 0.20 300); /* Bright purple */ + --primary-foreground: oklch(0.15 0.01 265); + + --secondary: oklch(0.22 0.02 265); + --secondary-foreground: oklch(0.85 0.01 265); + + --accent: oklch(0.65 0.25 330); /* Pink-purple */ + --accent-foreground: oklch(0.95 0.01 265); + + --destructive: oklch(0.60 0.24 25); + --destructive-foreground: oklch(0.95 0.01 265); + + --muted: oklch(0.22 0.02 265); + --muted-foreground: oklch(0.60 0.01 265); + + --border: oklch(0.25 0.02 265); + --input: oklch(0.22 0.02 265); + --ring: oklch(0.70 0.20 300); + + --success: oklch(0.65 0.16 145); + --warning: oklch(0.72 0.16 85); + --error: oklch(0.60 0.24 25); + --info: oklch(0.65 0.14 240); + + --radius: 0.5rem; +} +``` + +--- + +### Palette 4: Vibrant & Bold + +High energy, attention-grabbing. Think gaming, creative tools. + +```css +:root { + --background: oklch(0.98 0.01 265); + --foreground: oklch(0.15 0.02 265); + + --card: oklch(1 0 0); + --card-foreground: oklch(0.15 0.02 265); + + --primary: oklch(0.55 0.28 310); /* Hot magenta */ + --primary-foreground: oklch(0.99 0 0); + + --secondary: oklch(0.92 0.03 265); + --secondary-foreground: oklch(0.25 0.02 265); + + --accent: oklch(0.65 0.26 180); /* Cyan */ + --accent-foreground: oklch(0.15 0.02 265); + + --destructive: oklch(0.58 0.26 25); + --destructive-foreground: oklch(0.98 0 0); + + --muted: oklch(0.94 0.02 265); + --muted-foreground: oklch(0.50 0.02 265); + + --border: oklch(0.86 0.03 265); + --input: oklch(0.90 0.02 265); + --ring: oklch(0.55 0.28 310); + + --success: oklch(0.62 0.20 145); + --warning: oklch(0.72 0.18 85); + --error: oklch(0.58 0.26 25); + --info: oklch(0.62 0.16 240); + + --radius: 0.25rem; /* Sharp corners for edgy feel */ +} +``` + +--- + +### Palette 5: Minimalist Monochrome + +Pure focus, maximum clarity. Think Apple, minimalist tools. + +```css +:root { + --background: oklch(1 0 0); /* Pure white */ + --foreground: oklch(0.10 0 0); /* Near black */ + + --card: oklch(0.98 0 0); + --card-foreground: oklch(0.10 0 0); + + --popover: oklch(0.98 0 0); + --popover-foreground: oklch(0.10 0 0); + + --primary: oklch(0.10 0 0); /* Black */ + --primary-foreground: oklch(1 0 0); + + --secondary: oklch(0.94 0 0); + --secondary-foreground: oklch(0.20 0 0); + + --accent: oklch(0.40 0 0); /* Dark gray */ + --accent-foreground: oklch(1 0 0); + + --destructive: oklch(0.30 0 0); + --destructive-foreground: oklch(1 0 0); + + --muted: oklch(0.96 0 0); + --muted-foreground: oklch(0.50 0 0); + + --border: oklch(0.90 0 0); + --input: oklch(0.94 0 0); + --ring: oklch(0.10 0 0); + + --success: oklch(0.50 0 0); + --warning: oklch(0.50 0 0); + --error: oklch(0.30 0 0); + --info: oklch(0.50 0 0); + + --radius: 0rem; /* No rounded corners */ +} +``` + +--- + +### Palette 6: Nature-Inspired Green + +Calm, growth-focused, eco-friendly. Think sustainability, health. + +```css +:root { + --background: oklch(0.98 0.01 145); + --foreground: oklch(0.20 0.02 145); + + --card: oklch(1 0 0); + --card-foreground: oklch(0.20 0.02 145); + + --primary: oklch(0.48 0.14 155); /* Forest green */ + --primary-foreground: oklch(0.99 0 0); + + --secondary: oklch(0.94 0.02 145); + --secondary-foreground: oklch(0.28 0.02 145); + + --accent: oklch(0.65 0.16 135); /* Bright green */ + --accent-foreground: oklch(0.20 0.02 145); + + --destructive: oklch(0.55 0.20 25); + --destructive-foreground: oklch(0.98 0 0); + + --muted: oklch(0.96 0.01 145); + --muted-foreground: oklch(0.50 0.02 145); + + --border: oklch(0.88 0.02 145); + --input: oklch(0.92 0.01 145); + --ring: oklch(0.48 0.14 155); + + --success: oklch(0.62 0.16 145); + --warning: oklch(0.72 0.14 85); + --error: oklch(0.55 0.20 25); + --info: oklch(0.60 0.12 240); + + --radius: 1rem; /* Very rounded for organic feel */ +} +``` + +--- + +## WCAG Contrast Guidelines + +**Required Ratios**: +- **Normal text (< 18px)**: 4.5:1 (AA) or 7:1 (AAA) +- **Large text (≥ 18px or ≥ 14px bold)**: 3:1 (AA) or 4.5:1 (AAA) +- **UI components**: 3:1 minimum + +**Testing Your Colors**: +```css +/* Example: Check if primary text on background passes */ +background: oklch(0.98 0.01 240); /* Light */ +foreground: oklch(0.20 0.02 240); /* Dark */ +/* Contrast ratio: ~13:1 (Passes AAA for all text) ✅ */ +``` + +**Tools**: +- OKLCH Contrast Checker: oklch.com +- Who Can Use: whocanuse.com +- WebAIM Contrast Checker: webaim.org/resources/contrastchecker + +## Validating Your Palette + +Before using any palette, verify these pairings: + +```markdown +✅ Background → Foreground +✅ Card → Card Foreground +✅ Primary → Primary Foreground +✅ Secondary → Secondary Foreground +✅ Accent → Accent Foreground +✅ Muted Background → Muted Foreground +✅ Success/Warning/Error → Background +``` + +## Creating Custom Palettes + +### Step 1: Choose Your Hue + +```css +/* Blue family: 240-270 */ +--hue: 265; + +/* Red family: 0-30 */ +--hue: 25; + +/* Green family: 130-160 */ +--hue: 145; + +/* Purple family: 280-320 */ +--hue: 300; + +/* Orange family: 40-70 */ +--hue: 55; +``` + +### Step 2: Define Lightness Scale + +```css +/* Light theme scale */ +--l-100: 0.98; /* Lightest (backgrounds) */ +--l-200: 0.94; +--l-300: 0.88; +--l-400: 0.80; +--l-500: 0.60; /* Middle */ +--l-600: 0.45; /* Primary actions */ +--l-700: 0.30; +--l-800: 0.20; /* Darkest (text) */ +``` + +### Step 3: Set Chroma (Saturation) + +```css +/* Low chroma = subtle, professional */ +--c-low: 0.05; + +/* Medium chroma = balanced */ +--c-medium: 0.12; + +/* High chroma = vibrant */ +--c-high: 0.20; +``` + +### Step 4: Build Your Palette + +```css +:root { + --background: oklch(0.98 0.01 var(--hue)); + --foreground: oklch(0.20 0.02 var(--hue)); + --primary: oklch(0.45 0.15 var(--hue)); + --accent: oklch(0.68 0.16 var(--hue)); + /* Continue for all tokens */ +} +``` + +## Color Manipulation + +### Lighten/Darken + +```css +/* Original */ +--color: oklch(0.50 0.15 265); + +/* Lighter (increase L) */ +--color-light: oklch(0.70 0.15 265); + +/* Darker (decrease L) */ +--color-dark: oklch(0.30 0.15 265); +``` + +### More/Less Saturated + +```css +/* Original */ +--color: oklch(0.50 0.15 265); + +/* More saturated (increase C) */ +--color-vibrant: oklch(0.50 0.25 265); + +/* Less saturated (decrease C) */ +--color-muted: oklch(0.50 0.05 265); +``` + +### Shift Hue + +```css +/* Original blue */ +--color: oklch(0.50 0.15 265); + +/* Shift to purple */ +--color-purple: oklch(0.50 0.15 300); + +/* Shift to cyan */ +--color-cyan: oklch(0.50 0.15 200); +``` + +### Using color-mix() + +```css +/* Mix two colors */ +.mixed { + background: color-mix(in oklch, var(--primary) 70%, var(--accent) 30%); +} + +/* Lighten with white */ +.lightened { + background: color-mix(in oklch, var(--primary) 80%, white 20%); +} + +/* Darken with black */ +.darkened { + background: color-mix(in oklch, var(--primary) 80%, black 20%); +} +``` + +## Implementing Dark Mode (Optional) + +Only implement dark mode if explicitly requested. Single theme is preferred. + +```css +@media (prefers-color-scheme: dark) { + :root { + --background: oklch(0.15 0.01 265); + --foreground: oklch(0.95 0.01 265); + /* Invert lightness scale */ + } +} +``` + +Or use `next-themes` for manual toggle: + +```tsx +import { ThemeProvider } from 'next-themes'; + + + + +``` + +--- + +**Remember**: Color is emotional. Choose palettes that align with your brand personality, validate contrast for accessibility, and test with real users to ensure your colors communicate effectively. diff --git a/plugins/spark/skills/spark-app-template/references/component-patterns.md b/plugins/spark/skills/spark-app-template/references/component-patterns.md index 6578ecd..203fc31 100644 --- a/plugins/spark/skills/spark-app-template/references/component-patterns.md +++ b/plugins/spark/skills/spark-app-template/references/component-patterns.md @@ -1,977 +1,977 @@ -# Component Patterns - Spark App Template - -## shadcn/ui Component Usage Guide - -This guide covers common patterns and best practices for using shadcn/ui components in Spark App Template applications. - -## Core Principles - -1. **Copy, Don't Import**: shadcn components are copied into your project, giving you full ownership -2. **Customize Freely**: Edit components in `src/components/ui/` to match your needs -3. **Compose, Don't Duplicate**: Build complex components by composing primitives -4. **Maintain Consistency**: Follow established patterns across your app - -## Common Patterns - -### Forms with Validation - -The canonical pattern for forms combines Form + react-hook-form + Zod: - -```tsx -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { z } from 'zod'; -import { Button } from '@/components/ui/button'; -import { - Form, - FormControl, - FormDescription, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@/components/ui/form'; -import { Input } from '@/components/ui/input'; - -const formSchema = z.object({ - username: z.string().min(2, 'Username must be at least 2 characters'), - email: z.string().email('Invalid email address'), -}); - -export function ProfileForm() { - const form = useForm>({ - resolver: zodResolver(formSchema), - defaultValues: { - username: '', - email: '', - }, - }); - - function onSubmit(values: z.infer) { - console.log(values); - } - - return ( -
- - ( - - Username - - - - - This is your public display name. - - - - )} - /> - - ( - - Email - - - - - - )} - /> - - - - - ); -} -``` - -### Dialogs & Modals - -Standard pattern for modal dialogs: - -```tsx -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '@/components/ui/dialog'; -import { Button } from '@/components/ui/button'; - -export function DeleteConfirmDialog() { - return ( - - - - - - - Are you sure? - - This action cannot be undone. This will permanently delete your - account and remove your data from our servers. - - - - - - - - - ); -} -``` - -### Cards with Actions - -Pattern for content cards with interactive elements: - -```tsx -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; - -interface ProjectCardProps { - title: string; - description: string; - status: 'active' | 'archived'; - onEdit: () => void; - onDelete: () => void; -} - -export function ProjectCard({ - title, - description, - status, - onEdit, - onDelete, -}: ProjectCardProps) { - return ( - - -
- {title} - - {status} - -
- {description} -
- - - - -
- ); -} -``` - -### Data Tables - -Pattern for displaying tabular data: - -```tsx -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/ui/table'; -import { Badge } from '@/components/ui/badge'; -import { Button } from '@/components/ui/button'; -import { MoreHorizontal } from 'lucide-react'; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; - -interface User { - id: string; - name: string; - email: string; - role: string; - status: 'active' | 'inactive'; -} - -export function UserTable({ users }: { users: User[] }) { - return ( - - - - Name - Email - Role - Status - - - - - {users.map((user) => ( - - {user.name} - {user.email} - {user.role} - - - {user.status} - - - - - - - - - Edit - Delete - - - - - ))} - -
- ); -} -``` - -### Select Dropdowns - -Pattern for select/dropdown inputs: - -```tsx -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; - -export function StatusSelect() { - return ( - - ); -} -``` - -With react-hook-form: - -```tsx - ( - - Status - - - - )} -/> -``` - -### Toast Notifications - -Using Sonner for toast notifications: - -```tsx -import { toast } from 'sonner'; -import { Button } from '@/components/ui/button'; - -export function ToastExample() { - return ( -
- - - - -
- ); -} -``` - -### Tabs for Content Organization - -```tsx -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; -import { Card, CardContent } from '@/components/ui/card'; - -export function SettingsTabs() { - return ( - - - General - Security - Notifications - - - - - General settings content - - - - - - - Security settings content - - - - - ); -} -``` - -### Accordion for FAQ / Expandable Content - -```tsx -import { - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, -} from '@/components/ui/accordion'; - -export function FAQ() { - return ( - - - How do I get started? - - Getting started is easy! Simply sign up for an account and follow - our onboarding guide. - - - - What payment methods do you accept? - - We accept all major credit cards, PayPal, and bank transfers. - - - - ); -} -``` - -### Command Palette (⌘K) - -```tsx -import { useEffect, useState } from 'react'; -import { useNavigate } from '@tanstack/react-router'; -import { - CommandDialog, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator, -} from '@/components/ui/command'; - -export function CommandPalette() { - const [open, setOpen] = useState(false); - const navigate = useNavigate(); - - useEffect(() => { - const down = (e: KeyboardEvent) => { - if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { - e.preventDefault(); - setOpen((open) => !open); - } - }; - document.addEventListener('keydown', down); - return () => document.removeEventListener('keydown', down); - }, []); - - return ( - - - - No results found. - - navigate({ to: '/dashboard' })}> - Dashboard - - navigate({ to: '/settings' })}> - Settings - - - - - Create New Project - Invite Team Member - - - - ); -} -``` - -### Sheet (Drawer) for Mobile Navigation - -```tsx -import { Menu } from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, - SheetTrigger, -} from '@/components/ui/sheet'; - -export function MobileNav() { - return ( - - - - - - - Navigation - - Navigate to different sections of the app - - - - - - ); -} -``` - -### Popovers for Contextual Content - -```tsx -import { Button } from '@/components/ui/button'; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from '@/components/ui/popover'; -import { Calendar } from '@/components/ui/calendar'; - -export function DatePickerPopover() { - const [date, setDate] = useState(); - - return ( - - - - - - - - - ); -} -``` - -### Alert / Alert Dialog for Important Messages - -**Alert** (non-blocking): -```tsx -import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; -import { InfoIcon } from 'lucide-react'; - -export function InfoAlert() { - return ( - - - Heads up! - - You can add components to your app using the CLI. - - - ); -} -``` - -**AlertDialog** (blocking confirmation): -```tsx -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, -} from '@/components/ui/alert-dialog'; -import { Button } from '@/components/ui/button'; - -export function DeleteAlert() { - return ( - - - - - - - Are you absolutely sure? - - This action cannot be undone. This will permanently delete your - account and remove your data from our servers. - - - - Cancel - Continue - - - - ); -} -``` - -## Composition Patterns - -### Combining Components - -Build complex UIs by composing primitives: - -```tsx -// Filter panel combining multiple components -export function FilterPanel() { - return ( - - - Filters - - -
- - -
- -
- - - - - - - - - -
- - - -
- - -
-
-
- ); -} -``` - -## Card Layout Patterns - -### Understanding Card Spacing - -shadcn Card components come with default spacing optimized for content cards but may need adjustment when used as structural containers. - -**Default Card structure:** -- `CardHeader`: Uses `p-6` padding (1.5rem/24px on all sides) -- `CardContent`: Uses `p-6 pt-0` padding (removes top padding to prevent double spacing with CardHeader) -- Card wrapper: May include `py-6` and `gap-6` in some versions - -**Key principle:** "Keep card content focused - cards work best when covering one topic" ([source](https://medium.com/@rivainasution/shadcn-ui-react-series-part-6-card-the-container-i-use-everywhere-without-thinking-a6f9dd711d18)) - -### When to Override Card Defaults - -shadcn explicitly supports overriding defaults via className props ([Card docs](https://ui.shadcn.com/docs/components/card)). Here's when to use each pattern: - -**Content Cards (Keep defaults):** -Use default spacing when Card represents discrete content: - -```tsx -// ✅ Good - Content card benefits from default spacing - - - Project Updates - Latest changes to your project - - -

Each card should cover one focused topic

-
-
-``` - -**Layout Cards (Override with p-0):** -Remove spacing when Card serves as a structural container: - -```tsx -// ✅ Good - Layout card with full control over spacing - -
-

Panel Header

-
-
- {/* Panel content with independent spacing */} -
-
-``` - -**Partial Overrides:** -When you need asymmetric spacing control: - -```tsx -// ✅ Good - Remove top padding only, preserve bottom - - - {/* Controlled top spacing, natural bottom spacing */} - - -``` - -### Full-Height Card Layouts - -For Cards that need to fill available vertical space: - -```tsx -// Pattern: flex-col on Card, flex-1 on content area - -
-

Fixed Header

-
-
- {/* Scrollable content fills remaining space */} -
-
- -
-
-``` - -**Why this works:** Setting `flex: 1` on the content area allows it to "grow and take all available space" while pushing footers to the bottom ([CSS-Tricks](https://css-tricks.com/boxes-fill-height-dont-squish/)). - -### Cards with ScrollArea - -ScrollArea requires careful padding coordination: - -```tsx -// ✅ Correct pattern - padding inside ScrollArea - - - Scrollable Content - - - - {/* Padding applied here, not on CardContent */} -
- {items.map(item =>
{item.content}
)} -
-
-
-
-``` - -**Key points:** -- Always set explicit height on ScrollArea (e.g., `h-[400px]`) -- Place padding inside ScrollArea, not on parent CardContent -- This prevents double scrollbars and layout issues ([Medium - ScrollArea](https://medium.com/@rivainasution/shadcn-ui-react-series-part-9-scroll-area-controlled-scrolling-without-layout-hacks-4263c6f899f4)) - -### Overflow-Hidden Considerations - -The `overflow-hidden` class is commonly needed for layout cards but intentionally not default: - -```tsx -// When to use overflow-hidden: - {/* Clips content to rounded corners */} - {/* Image respects border-radius */} - ... - -``` - -There's ongoing discussion about making this default, but it remains optional to support both `overflow: hidden` and `overflow: scroll` use cases ([GitHub #2885](https://github.com/shadcn-ui/ui/issues/2885)). - -### Split Panel Pattern - -Common pattern for side-by-side cards in dashboard layouts: - -```tsx -
- -
-

Left Panel

-
-
- {/* Scrollable left content */} -
-
- - -
-

Right Panel

-
-
- {/* Scrollable right content */} -
-
-
-``` - -### Nested Cards Pattern - -Outer layout card with inner content cards: - -```tsx - - {/* Outer: Layout card with no default spacing */} -
-

Main Panel

-
- -
-
- {/* Inner: Content cards keep default spacing */} - - - Section A - - - Content benefits from Card's natural padding - - - - - - Section B - - - Another content card with default spacing - - -
-
-
-``` - -### Card Spacing Decision Tree - -Ask yourself these questions when using Cards: - -1. **Is this a content card or layout card?** - - Content: Represents discrete information → Keep defaults - - Layout: Structural container → Override with `p-0 gap-0` - -2. **Does the Card need to fill available height?** - - Yes → Use `flex flex-col` on Card, `flex-1` on content area - - Add `overflow-auto` on content area if scrolling needed - -3. **Are there nested Cards?** - - Outer Card: Override spacing (`p-0 gap-0`) for layout control - - Inner Cards: Keep defaults for proper content spacing - -4. **Using ScrollArea inside Card?** - - CardContent needs `p-0` - - Move padding into ScrollArea - - Set explicit height on ScrollArea - -5. **Need clipped corners for images?** - - Add `overflow-hidden` to Card wrapper - -## Best Practices - -### 1. Use Variants - -```tsx - - - - -``` - -### 2. Consistent Sizing - -```tsx - - - - -``` - -### 3. Accessible Labels - -```tsx - - -``` - -### 4. Loading States - -```tsx - -``` - -### 5. Empty States - -```tsx -{items.length === 0 ? ( -
- -

No projects found

-

- Get started by creating a new project. -

- -
-) : ( - -)} -``` - -## Common Mistakes to Avoid - -❌ **Don't** nest interactive elements: -```tsx - -``` - -✅ **Do** use asChild: -```tsx - -``` - -❌ **Don't** ignore form validation feedback: -```tsx - {/* Missing FormMessage */} -``` - -✅ **Do** show validation errors: -```tsx - - - - - {/* Shows errors */} - -``` - -❌ **Don't** use inline styles for theming: -```tsx - + + + ); +} +``` + +### Dialogs & Modals + +Standard pattern for modal dialogs: + +```tsx +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; + +export function DeleteConfirmDialog() { + return ( + + + + + + + Are you sure? + + This action cannot be undone. This will permanently delete your + account and remove your data from our servers. + + + + + + + + + ); +} +``` + +### Cards with Actions + +Pattern for content cards with interactive elements: + +```tsx +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from '@/components/ui/card'; +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; + +interface ProjectCardProps { + title: string; + description: string; + status: 'active' | 'archived'; + onEdit: () => void; + onDelete: () => void; +} + +export function ProjectCard({ + title, + description, + status, + onEdit, + onDelete, +}: ProjectCardProps) { + return ( + + +
+ {title} + + {status} + +
+ {description} +
+ + + + +
+ ); +} +``` + +### Data Tables + +Pattern for displaying tabular data: + +```tsx +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { MoreHorizontal } from 'lucide-react'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; + +interface User { + id: string; + name: string; + email: string; + role: string; + status: 'active' | 'inactive'; +} + +export function UserTable({ users }: { users: User[] }) { + return ( + + + + Name + Email + Role + Status + + + + + {users.map((user) => ( + + {user.name} + {user.email} + {user.role} + + + {user.status} + + + + + + + + + Edit + Delete + + + + + ))} + +
+ ); +} +``` + +### Select Dropdowns + +Pattern for select/dropdown inputs: + +```tsx +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; + +export function StatusSelect() { + return ( + + ); +} +``` + +With react-hook-form: + +```tsx + ( + + Status + + + + )} +/> +``` + +### Toast Notifications + +Using Sonner for toast notifications: + +```tsx +import { toast } from 'sonner'; +import { Button } from '@/components/ui/button'; + +export function ToastExample() { + return ( +
+ + + + +
+ ); +} +``` + +### Tabs for Content Organization + +```tsx +import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; +import { Card, CardContent } from '@/components/ui/card'; + +export function SettingsTabs() { + return ( + + + General + Security + Notifications + + + + + General settings content + + + + + + + Security settings content + + + + + ); +} +``` + +### Accordion for FAQ / Expandable Content + +```tsx +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from '@/components/ui/accordion'; + +export function FAQ() { + return ( + + + How do I get started? + + Getting started is easy! Simply sign up for an account and follow + our onboarding guide. + + + + What payment methods do you accept? + + We accept all major credit cards, PayPal, and bank transfers. + + + + ); +} +``` + +### Command Palette (⌘K) + +```tsx +import { useEffect, useState } from 'react'; +import { useNavigate } from '@tanstack/react-router'; +import { + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from '@/components/ui/command'; + +export function CommandPalette() { + const [open, setOpen] = useState(false); + const navigate = useNavigate(); + + useEffect(() => { + const down = (e: KeyboardEvent) => { + if (e.key === 'k' && (e.metaKey || e.ctrlKey)) { + e.preventDefault(); + setOpen((open) => !open); + } + }; + document.addEventListener('keydown', down); + return () => document.removeEventListener('keydown', down); + }, []); + + return ( + + + + No results found. + + navigate({ to: '/dashboard' })}> + Dashboard + + navigate({ to: '/settings' })}> + Settings + + + + + Create New Project + Invite Team Member + + + + ); +} +``` + +### Sheet (Drawer) for Mobile Navigation + +```tsx +import { Menu } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from '@/components/ui/sheet'; + +export function MobileNav() { + return ( + + + + + + + Navigation + + Navigate to different sections of the app + + + + + + ); +} +``` + +### Popovers for Contextual Content + +```tsx +import { Button } from '@/components/ui/button'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/popover'; +import { Calendar } from '@/components/ui/calendar'; + +export function DatePickerPopover() { + const [date, setDate] = useState(); + + return ( + + + + + + + + + ); +} +``` + +### Alert / Alert Dialog for Important Messages + +**Alert** (non-blocking): +```tsx +import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; +import { InfoIcon } from 'lucide-react'; + +export function InfoAlert() { + return ( + + + Heads up! + + You can add components to your app using the CLI. + + + ); +} +``` + +**AlertDialog** (blocking confirmation): +```tsx +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@/components/ui/alert-dialog'; +import { Button } from '@/components/ui/button'; + +export function DeleteAlert() { + return ( + + + + + + + Are you absolutely sure? + + This action cannot be undone. This will permanently delete your + account and remove your data from our servers. + + + + Cancel + Continue + + + + ); +} +``` + +## Composition Patterns + +### Combining Components + +Build complex UIs by composing primitives: + +```tsx +// Filter panel combining multiple components +export function FilterPanel() { + return ( + + + Filters + + +
+ + +
+ +
+ + + + + + + + + +
+ + + +
+ + +
+
+
+ ); +} +``` + +## Card Layout Patterns + +### Understanding Card Spacing + +shadcn Card components come with default spacing optimized for content cards but may need adjustment when used as structural containers. + +**Default Card structure:** +- `CardHeader`: Uses `p-6` padding (1.5rem/24px on all sides) +- `CardContent`: Uses `p-6 pt-0` padding (removes top padding to prevent double spacing with CardHeader) +- Card wrapper: May include `py-6` and `gap-6` in some versions + +**Key principle:** "Keep card content focused - cards work best when covering one topic" ([source](https://medium.com/@rivainasution/shadcn-ui-react-series-part-6-card-the-container-i-use-everywhere-without-thinking-a6f9dd711d18)) + +### When to Override Card Defaults + +shadcn explicitly supports overriding defaults via className props ([Card docs](https://ui.shadcn.com/docs/components/card)). Here's when to use each pattern: + +**Content Cards (Keep defaults):** +Use default spacing when Card represents discrete content: + +```tsx +// ✅ Good - Content card benefits from default spacing + + + Project Updates + Latest changes to your project + + +

Each card should cover one focused topic

+
+
+``` + +**Layout Cards (Override with p-0):** +Remove spacing when Card serves as a structural container: + +```tsx +// ✅ Good - Layout card with full control over spacing + +
+

Panel Header

+
+
+ {/* Panel content with independent spacing */} +
+
+``` + +**Partial Overrides:** +When you need asymmetric spacing control: + +```tsx +// ✅ Good - Remove top padding only, preserve bottom + + + {/* Controlled top spacing, natural bottom spacing */} + + +``` + +### Full-Height Card Layouts + +For Cards that need to fill available vertical space: + +```tsx +// Pattern: flex-col on Card, flex-1 on content area + +
+

Fixed Header

+
+
+ {/* Scrollable content fills remaining space */} +
+
+ +
+
+``` + +**Why this works:** Setting `flex: 1` on the content area allows it to "grow and take all available space" while pushing footers to the bottom ([CSS-Tricks](https://css-tricks.com/boxes-fill-height-dont-squish/)). + +### Cards with ScrollArea + +ScrollArea requires careful padding coordination: + +```tsx +// ✅ Correct pattern - padding inside ScrollArea + + + Scrollable Content + + + + {/* Padding applied here, not on CardContent */} +
+ {items.map(item =>
{item.content}
)} +
+
+
+
+``` + +**Key points:** +- Always set explicit height on ScrollArea (e.g., `h-[400px]`) +- Place padding inside ScrollArea, not on parent CardContent +- This prevents double scrollbars and layout issues ([Medium - ScrollArea](https://medium.com/@rivainasution/shadcn-ui-react-series-part-9-scroll-area-controlled-scrolling-without-layout-hacks-4263c6f899f4)) + +### Overflow-Hidden Considerations + +The `overflow-hidden` class is commonly needed for layout cards but intentionally not default: + +```tsx +// When to use overflow-hidden: + {/* Clips content to rounded corners */} + {/* Image respects border-radius */} + ... + +``` + +There's ongoing discussion about making this default, but it remains optional to support both `overflow: hidden` and `overflow: scroll` use cases ([GitHub #2885](https://github.com/shadcn-ui/ui/issues/2885)). + +### Split Panel Pattern + +Common pattern for side-by-side cards in dashboard layouts: + +```tsx +
+ +
+

Left Panel

+
+
+ {/* Scrollable left content */} +
+
+ + +
+

Right Panel

+
+
+ {/* Scrollable right content */} +
+
+
+``` + +### Nested Cards Pattern + +Outer layout card with inner content cards: + +```tsx + + {/* Outer: Layout card with no default spacing */} +
+

Main Panel

+
+ +
+
+ {/* Inner: Content cards keep default spacing */} + + + Section A + + + Content benefits from Card's natural padding + + + + + + Section B + + + Another content card with default spacing + + +
+
+
+``` + +### Card Spacing Decision Tree + +Ask yourself these questions when using Cards: + +1. **Is this a content card or layout card?** + - Content: Represents discrete information → Keep defaults + - Layout: Structural container → Override with `p-0 gap-0` + +2. **Does the Card need to fill available height?** + - Yes → Use `flex flex-col` on Card, `flex-1` on content area + - Add `overflow-auto` on content area if scrolling needed + +3. **Are there nested Cards?** + - Outer Card: Override spacing (`p-0 gap-0`) for layout control + - Inner Cards: Keep defaults for proper content spacing + +4. **Using ScrollArea inside Card?** + - CardContent needs `p-0` + - Move padding into ScrollArea + - Set explicit height on ScrollArea + +5. **Need clipped corners for images?** + - Add `overflow-hidden` to Card wrapper + +## Best Practices + +### 1. Use Variants + +```tsx + + + + +``` + +### 2. Consistent Sizing + +```tsx + + + + +``` + +### 3. Accessible Labels + +```tsx + + +``` + +### 4. Loading States + +```tsx + +``` + +### 5. Empty States + +```tsx +{items.length === 0 ? ( +
+ +

No projects found

+

+ Get started by creating a new project. +

+ +
+) : ( + +)} +``` + +## Common Mistakes to Avoid + +❌ **Don't** nest interactive elements: +```tsx + +``` + +✅ **Do** use asChild: +```tsx + +``` + +❌ **Don't** ignore form validation feedback: +```tsx + {/* Missing FormMessage */} +``` + +✅ **Do** show validation errors: +```tsx + + + + + {/* Shows errors */} + +``` + +❌ **Don't** use inline styles for theming: +```tsx + - -// ✅ Good: Memoized function (if React Compiler not enabled) -const handleClickItem = useCallback(() => { - handleClick(item.id); -}, [item.id]); - - - -// ✅ Best: With React Compiler, write naturally - -// Compiler auto-memoizes this -``` - -## Network Optimization - -### API Request Batching - -```tsx -// Batch multiple queries -const results = useQueries({ - queries: [ - { queryKey: ['user', userId], queryFn: fetchUser }, - { queryKey: ['posts', userId], queryFn: fetchPosts }, - { queryKey: ['comments', userId], queryFn: fetchComments }, - ], -}); -``` - -### Request Deduplication - -TanStack Query automatically deduplicates identical concurrent requests. - -### Compression - -Ensure server sends compressed responses: - -```http -Content-Encoding: gzip -Content-Encoding: br (Brotli, even better) -``` - -## Production Build Optimization - -### Vite Build Settings - -```typescript -// vite.config.ts -export default defineConfig({ - build: { - target: 'es2020', - minify: 'terser', - rollupOptions: { - output: { - manualChunks: { - vendor: ['react', 'react-dom'], - router: ['@tanstack/react-router'], - ui: ['lucide-react', 'motion'], - }, - }, - }, - }, -}); -``` - -### Environment-Specific Code - -```tsx -if (import.meta.env.DEV) { - // Development-only code (stripped in production) - console.log('Debug info'); -} - -if (import.meta.env.PROD) { - // Production-only code - initAnalytics(); -} -``` - -## Performance Checklist - -Use this checklist before deploying: - -- [ ] **Core Web Vitals**: INP < 200ms, LCP < 2.5s, CLS < 0.1 -- [ ] **React Compiler**: Enabled and verified working -- [ ] **Images**: Using WebP/AVIF, lazy loaded, responsive -- [ ] **Fonts**: Variable fonts, font-display: swap, preload critical -- [ ] **Bundle Size**: Analyzed, < 200KB initial bundle gzipped -- [ ] **Code Splitting**: Routes split, heavy components lazy loaded -- [ ] **Caching**: TanStack Query configured, stale times set -- [ ] **Animations**: GPU-accelerated properties only -- [ ] **Virtual Scrolling**: Implemented for lists > 100 items -- [ ] **Network**: Requests batched, compression enabled -- [ ] **Production Build**: Minified, tree-shaken, optimized chunks - -## Monitoring - -Set up continuous monitoring: - -```tsx -// Track Core Web Vitals -import { onCLS, onINP, onLCP } from 'web-vitals'; - -const sendToAnalytics = (metric) => { - // Send to your analytics service - fetch('/api/analytics', { - method: 'POST', - body: JSON.stringify(metric), - }); -}; - -onCLS(sendToAnalytics); -onINP(sendToAnalytics); -onLCP(sendToAnalytics); -``` - -**Tools**: -- Google Search Console (real user metrics) -- Chrome DevTools (Lighthouse) -- WebPageTest (comprehensive testing) -- Vercel Analytics (if deploying on Vercel) - ---- - -**Remember**: Performance is a feature, not an afterthought. Budget your performance from the start, measure continuously, and optimize based on real-world data, not assumptions. +# Performance Checklist - Spark App Template + +## Core Web Vitals 2026 + +Google's Core Web Vitals are essential metrics for user experience and SEO ranking. + +### Current Metrics + +**INP (Interaction to Next Paint)** - Replaced FID in March 2024 +- **Target**: < 200ms (Good) +- **What it measures**: Full interaction responsiveness (input delay + processing + paint) +- **Why it matters**: Captures complete user interaction experience, not just first click + +**LCP (Largest Contentful Paint)** +- **Target**: < 2.5s (Good) +- **What it measures**: Time for largest content element to render +- **Why it matters**: Perceived loading performance + +**CLS (Cumulative Layout Shift)** +- **Target**: < 0.1 (Good) +- **What it measures**: Visual stability (unexpected layout shifts) +- **Why it matters**: User frustration from elements moving during interaction + +### Measuring Core Web Vitals + +**In Development:** +```bash +# Chrome DevTools +1. Open DevTools (F12) +2. Lighthouse tab +3. Generate report +4. Check Performance score + Web Vitals +``` + +**In Production:** +```tsx +// Install web-vitals +pnpm add web-vitals + +// src/main.tsx +import { onCLS, onINP, onLCP } from 'web-vitals'; + +onCLS(console.log); +onINP(console.log); +onLCP(console.log); + +// Or send to analytics +function sendToAnalytics(metric) { + fetch('/analytics', { + method: 'POST', + body: JSON.stringify(metric), + }); +} + +onINP(sendToAnalytics); +``` + +## React 19 Compiler + +### What It Does + +The React Compiler automatically memoizes components and values, eliminating manual `useMemo`, `useCallback`, and `React.memo` in most cases. + +**Performance Gains**: +- 12% faster initial loads +- 2.5x faster interactions +- Reduces unnecessary re-renders automatically + +### Enabling React Compiler + +```bash +pnpm add -D babel-plugin-react-compiler +``` + +```typescript +// vite.config.ts +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', {}], + ], + }, + }), + ], +}); +``` + +### Verification + +Check that components are compiled: + +```tsx +// You'll still write normal React +function MyComponent() { + const [count, setCount] = useState(0); + + // Compiler automatically memoizes this + const expensiveValue = count * 2; + + return
{expensiveValue}
; +} + +// Compiler output (internal): +// - Tracks dependencies automatically +// - Memoizes render when dependencies don't change +// - No manual optimization needed +``` + +## Image Optimization + +### Use Modern Formats + +```tsx +// WebP with fallback + + + + Description + +``` + +### Responsive Images + +```tsx +Description +``` + +### Lazy Loading + +```tsx +// Native lazy loading (built-in) +Description + +// Eager load above-the-fold images +Hero + +// Or priority loading +Hero +``` + +### Image CDN + +Use image CDNs for automatic optimization: + +```tsx +// Example: Cloudinary +Optimized + +// w_400 = width 400px +// f_auto = automatic format (WebP/AVIF) +// q_auto = automatic quality +``` + +## Font Optimization + +### Variable Fonts + +```html + + +``` + +**Benefits**: +- Single HTTP request +- Smaller total file size +- Smooth weight interpolation + +### Font Display Strategy + +```css +@font-face { + font-family: 'Custom Font'; + src: url('/fonts/font.woff2') format('woff2'); + font-display: swap; /* Show fallback immediately */ +} +``` + +**Options**: +- `swap`: Best for most cases (show fallback, swap when loaded) +- `optional`: Only use if cached (best for performance) +- `fallback`: Brief invisible period, then fallback + +### Preload Critical Fonts + +```html + + + +``` + +**Only preload**: +- Hero/heading font +- Above-the-fold text +- Max 1-2 fonts + +### Font Subsetting + +If self-hosting, subset fonts to include only needed characters: + +```bash +# Install pyftsubset +pip install fonttools + +# Subset to Latin characters only +pyftsubset font.ttf \ + --output-file=font-subset.woff2 \ + --flavor=woff2 \ + --layout-features=* \ + --unicodes=U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD +``` + +## Code Splitting + +### Route-Based Splitting + +TanStack Router handles this automatically: + +```tsx +// Each route is automatically code-split +export const Route = createFileRoute('/dashboard')({ + component: Dashboard, // Only loaded when route is accessed +}); +``` + +### Component Lazy Loading + +```tsx +import { lazy, Suspense } from 'react'; + +const HeavyChart = lazy(() => import('./HeavyChart')); + +export function Dashboard() { + return ( + }> + + + ); +} +``` + +### Dynamic Imports + +```tsx +// Load on demand +async function handleExport() { + const { exportToPDF } = await import('./export-utils'); + exportToPDF(data); +} +``` + +## Bundle Size Optimization + +### Analyze Bundle + +```bash +pnpm add -D rollup-plugin-visualizer +``` + +```typescript +// vite.config.ts +import { visualizer } from 'rollup-plugin-visualizer'; + +export default defineConfig({ + plugins: [ + visualizer({ + open: true, + gzipSize: true, + brotliSize: true, + }), + ], +}); +``` + +### Tree-Shaking Tips + +```tsx +// ❌ Bad: Imports entire library +import _ from 'lodash'; + +// ✅ Good: Import only what you need +import debounce from 'lodash/debounce'; + +// ❌ Bad: Imports all icons +import * as Icons from 'lucide-react'; + +// ✅ Good: Import specific icons +import { Home, Settings } from 'lucide-react'; +``` + +### Remove Unused Code + +```bash +# Check unused dependencies +pnpm exec depcheck + +# Remove unused exports +pnpm add -D ts-prune +pnpm exec ts-prune +``` + +## TanStack Query Optimization + +### Caching Strategy + +```tsx +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, // 1 minute + gcTime: 5 * 60 * 1000, // 5 minutes (was cacheTime) + refetchOnWindowFocus: false, // Disable aggressive refetching + }, + }, +}); +``` + +### Prefetching + +```tsx +import { queryOptions, useSuspenseQuery } from '@tanstack/react-query'; + +const userQueryOptions = queryOptions({ + queryKey: ['user', userId], + queryFn: () => fetchUser(userId), +}); + +// Prefetch on hover + { + queryClient.prefetchQuery(userQueryOptions); + }} +> + View Profile + +``` + +### Suspense for Data Loading + +```tsx +export function UserProfile({ userId }: { userId: string }) { + // useSuspenseQuery throws promise, letting Suspense handle loading + const { data } = useSuspenseQuery({ + queryKey: ['user', userId], + queryFn: () => fetchUser(userId), + }); + + return
{data.name}
; +} + +// Parent component +}> + + +``` + +## Animation Performance + +### Use GPU-Accelerated Properties + +```css +/* ✅ GPU-accelerated (fast) */ +.animated { + transform: translateX(100px); + opacity: 0.5; +} + +/* ❌ CPU-bound (slow) */ +.animated { + margin-left: 100px; + width: 200px; +} +``` + +### Debounce Expensive Operations + +```tsx +import { debounce } from 'lodash'; +import { useEffect, useMemo } from 'react'; + +export function SearchInput() { + const [query, setQuery] = useState(''); + + const debouncedSearch = useMemo( + () => debounce((value: string) => { + // Expensive search operation + performSearch(value); + }, 300), + [] + ); + + useEffect(() => { + return () => debouncedSearch.cancel(); + }, [debouncedSearch]); + + return ( + { + setQuery(e.target.value); + debouncedSearch(e.target.value); + }} + /> + ); +} +``` + +### Use will-change Sparingly + +```css +/* Only during animation */ +.animating { + will-change: transform; +} + +/* Remove after animation */ +.animated { + will-change: auto; +} +``` + +## Rendering Optimization + +### Virtual Scrolling (Large Lists) + +```bash +pnpm add @tanstack/react-virtual +``` + +```tsx +import { useVirtualizer } from '@tanstack/react-virtual'; +import { useRef } from 'react'; + +export function VirtualList({ items }: { items: any[] }) { + const parentRef = useRef(null); + + const virtualizer = useVirtualizer({ + count: items.length, + getScrollElement: () => parentRef.current, + estimateSize: () => 50, + }); + + return ( +
+
+ {virtualizer.getVirtualItems().map((virtualItem) => ( +
+ {items[virtualItem.index].name} +
+ ))} +
+
+ ); +} +``` + +### Avoid Inline Functions in Render + +```tsx +// ❌ Bad: Creates new function every render + + +// ✅ Good: Memoized function (if React Compiler not enabled) +const handleClickItem = useCallback(() => { + handleClick(item.id); +}, [item.id]); + + + +// ✅ Best: With React Compiler, write naturally + +// Compiler auto-memoizes this +``` + +## Network Optimization + +### API Request Batching + +```tsx +// Batch multiple queries +const results = useQueries({ + queries: [ + { queryKey: ['user', userId], queryFn: fetchUser }, + { queryKey: ['posts', userId], queryFn: fetchPosts }, + { queryKey: ['comments', userId], queryFn: fetchComments }, + ], +}); +``` + +### Request Deduplication + +TanStack Query automatically deduplicates identical concurrent requests. + +### Compression + +Ensure server sends compressed responses: + +```http +Content-Encoding: gzip +Content-Encoding: br (Brotli, even better) +``` + +## Production Build Optimization + +### Vite Build Settings + +```typescript +// vite.config.ts +export default defineConfig({ + build: { + target: 'es2020', + minify: 'terser', + rollupOptions: { + output: { + manualChunks: { + vendor: ['react', 'react-dom'], + router: ['@tanstack/react-router'], + ui: ['lucide-react', 'motion'], + }, + }, + }, + }, +}); +``` + +### Environment-Specific Code + +```tsx +if (import.meta.env.DEV) { + // Development-only code (stripped in production) + console.log('Debug info'); +} + +if (import.meta.env.PROD) { + // Production-only code + initAnalytics(); +} +``` + +## Performance Checklist + +Use this checklist before deploying: + +- [ ] **Core Web Vitals**: INP < 200ms, LCP < 2.5s, CLS < 0.1 +- [ ] **React Compiler**: Enabled and verified working +- [ ] **Images**: Using WebP/AVIF, lazy loaded, responsive +- [ ] **Fonts**: Variable fonts, font-display: swap, preload critical +- [ ] **Bundle Size**: Analyzed, < 200KB initial bundle gzipped +- [ ] **Code Splitting**: Routes split, heavy components lazy loaded +- [ ] **Caching**: TanStack Query configured, stale times set +- [ ] **Animations**: GPU-accelerated properties only +- [ ] **Virtual Scrolling**: Implemented for lists > 100 items +- [ ] **Network**: Requests batched, compression enabled +- [ ] **Production Build**: Minified, tree-shaken, optimized chunks + +## Monitoring + +Set up continuous monitoring: + +```tsx +// Track Core Web Vitals +import { onCLS, onINP, onLCP } from 'web-vitals'; + +const sendToAnalytics = (metric) => { + // Send to your analytics service + fetch('/api/analytics', { + method: 'POST', + body: JSON.stringify(metric), + }); +}; + +onCLS(sendToAnalytics); +onINP(sendToAnalytics); +onLCP(sendToAnalytics); +``` + +**Tools**: +- Google Search Console (real user metrics) +- Chrome DevTools (Lighthouse) +- WebPageTest (comprehensive testing) +- Vercel Analytics (if deploying on Vercel) + +--- + +**Remember**: Performance is a feature, not an afterthought. Budget your performance from the start, measure continuously, and optimize based on real-world data, not assumptions. diff --git a/plugins/spark/skills/spark-app-template/references/prd-template.md b/plugins/spark/skills/spark-app-template/references/prd-template.md index efc332f..a12450e 100644 --- a/plugins/spark/skills/spark-app-template/references/prd-template.md +++ b/plugins/spark/skills/spark-app-template/references/prd-template.md @@ -1,302 +1,302 @@ -# PRD Template - Spark App Template - -## Purpose - -A Product Requirements Document (PRD) helps structure thinking before implementation. Use this simplified template to plan features, design direction, and success criteria. - -## When to Use - -- Planning new applications -- Adding major features -- Clarifying requirements -- Aligning design decisions -- Documenting design system choices - -## Template - ---- - -# [Application Name] - -## Purpose Statement - -*(One sentence describing what this web app does and why it exists)* - -Example: "A weekly meal planning application that helps users organize their meals and automatically generates consolidated grocery shopping lists." - ---- - -## Experience Qualities - -*(Three adjectives with one-sentence elaborations defining the user experience)* - -1. **[Adjective]** - [One-sentence elaboration] -2. **[Adjective]** - [One-sentence elaboration] -3. **[Adjective]** - [One-sentence elaboration] - -Example: -1. **Effortless** - Planning meals should feel intuitive and quick, not like a chore -2. **Organized** - Clear visual structure makes the week's meals easy to scan and manage -3. **Satisfying** - Generating a shopping list from planned meals should feel like magic - ---- - -## Complexity Level - -*(Select ONE and explain why)* - -- [ ] **Micro Tool** (single-purpose application) - - *Why*: [One-sentence justification] - - *Example*: Calculator app, color picker, unit converter - -- [ ] **Content Showcase** (information-focused) - - *Why*: [One-sentence justification] - - *Example*: Marketing landing page, portfolio, blog - -- [ ] **Light Application** (multiple features with basic state) - - *Why*: [One-sentence justification] - - *Example*: Todo list, meal planner, expense tracker - -- [ ] **Complex Application** (advanced functionality, multiple views) - - *Why*: [One-sentence justification] - - *Example*: CRM, analytics dashboard, project management tool - ---- - -## Essential Features - -*(For each core feature, document:)* - -### Feature 1: [Feature Name] - -- **Functionality**: What it does -- **Purpose**: Why it matters to users -- **Trigger**: How the user initiates it -- **Progression**: Terse UX flow (use → to separate steps) - - Example: `Click slot → Enter meal name + ingredients → Save → Meal saved to slot` -- **Success Criteria**: How we'll know it works - -### Feature 2: [Feature Name] - -*(Repeat structure above)* - ---- - -## Edge Case Handling - -*(How will the app handle unexpected situations?)* - -- **[Edge Case Name]**: [Short one-line solution] -- **[Edge Case Name]**: [Short one-line solution] - -Example: -- **Empty week**: Show friendly empty state with prompt to add first meal -- **No ingredients**: Allow meals without ingredients (eating out, leftovers) -- **Duplicate ingredients**: Combine same ingredients across meals in grocery list - ---- - -## Design Direction - -*(What specific feelings should the design evoke in users?)* - -Example: "The design should feel like a well-organized kitchen bulletin board - warm, practical, and inviting. It should reduce the cognitive load of meal planning by presenting information clearly and making actions obvious." - ---- - -## Color Selection - -*(Describe the color scheme approach and specific colors. Use OKLCH format.)* - -### Color Palette - -- **Primary Color**: `oklch(L C H)` - [What it communicates] -- **Secondary Colors**: `oklch(L C H)` - [Their purposes] -- **Accent Color**: `oklch(L C H)` - [For CTAs and important elements] - -### Foreground/Background Pairings - -*(Document text colors on backgrounds with WCAG AA validation)* - -- `Background (name oklch(L C H))`: `Text color (oklch(L C H))` - Ratio [X.X:1] [✓ or ✗] - -Example: -- `Background (Warm Cream oklch(0.96 0.02 85))`: `Dark brown text (oklch(0.25 0.02 55))` - Ratio 8.5:1 ✓ -- `Primary (Herb Green oklch(0.55 0.15 145))`: `White text (oklch(0.99 0 0))` - Ratio 4.8:1 ✓ - ---- - -## Font Selection - -*(What characteristics should the typefaces convey, and which fonts should be used?)* - -**Chosen Fonts**: -- **Headings**: [Font Name] - [Character description] -- **Body**: [Font Name] - [Character description] -- **Code** *(if applicable)*: [Font Name] - -### Typographic Hierarchy - -- **H1 (Page Title)**: [Font] [Weight]/[Size]px/[Tracking] -- **H2 (Section Headers)**: [Font] [Weight]/[Size]px/[Tracking] -- **H3 (Subsections)**: [Font] [Weight]/[Size]px/[Tracking] -- **Body (Main Text)**: [Font] [Weight]/[Size]px -- **Caption (Supporting)**: [Font] [Weight]/[Size]px - -Example: -- **H1 (App Title)**: Space Grotesk Bold/32px/tight letter spacing -- **Body (Meal Names)**: Source Sans 3 Regular/16px -- **Caption (Ingredients)**: Source Sans 3 Regular/14px/muted color - ---- - -## Animations - -*(How should animations be used? Balance subtle functionality with moments of delight.)* - -Example: "Subtle animations reinforce actions without slowing down the experience - meals should 'pop' into place when added, and the grocery list should build item by item when generated, creating a satisfying moment of accomplishment." - ---- - -## Component Selection - -### UI Components - -*(Which shadcn components will be used?)* - -- **[Component Name]**: [Use case] -- **[Component Name]**: [Use case] - -Example: -- **Card**: For each day's meal container and the grocery list panel -- **Dialog**: For adding/editing meals with ingredient entry -- **Button**: Primary for generate list, secondary for add meal actions -- **Checkbox**: For checking off grocery items - -### Customizations - -*(Any custom components needed beyond shadcn?)* - -- **[Custom Component]**: [Why needed, what it does] - -Example: -- **Meal Slot Component**: Custom component showing empty state vs filled state with hover interactions -- **Ingredient Chip**: Removable tags for ingredients during entry - -### Component States - -*(How should interactive elements behave in different states?)* - -- **[Element] - [State]**: [Behavior/appearance] - -Example: -- **Empty meal slot**: Dashed border, muted plus icon, hover brightens -- **Filled meal slot**: Solid background, meal name visible, hover shows edit option -- **Grocery item checked**: Reduced opacity, strikethrough, checkbox filled - -### Icon Selection - -*(Which Lucide icons represent each action?)* - -- **[Action]**: [Icon name] - -Example: -- **Add meal**: Plus -- **Remove meal**: Trash -- **Generate grocery list**: ShoppingCart -- **Edit meal**: Pencil - -### Spacing System - -*(Consistent padding and margin values using Tailwind scale)* - -- **Gap between [elements]**: gap-[X] -- **Padding inside [containers]**: p-[X] - -Example: -- **Gap between days**: gap-4 -- **Gap between meal slots**: gap-2 -- **Padding inside cards**: p-4 -- **Padding for main container**: p-6 - -### Mobile Responsive Strategy - -*(How components adapt on smaller screens)* - -Example: -- Stack days vertically on mobile -- Grocery list becomes full-screen overlay -- Larger touch targets for meal slots - ---- - -## Success Metrics - -*(How will we measure if the application succeeds?)* - -**User Experience Metrics**: -- [ ] [Metric name and target] -- [ ] [Metric name and target] - -**Technical Metrics**: -- [ ] INP < 200ms -- [ ] LCP < 2.5s -- [ ] CLS < 0.1 - -**Feature Adoption**: -- [ ] [Specific feature usage target] - ---- - -## Out of Scope - -*(What will NOT be included in the initial version?)* - -- [ ] [Feature or capability] -- [ ] [Feature or capability] - -Example: -- Recipe database integration -- Social sharing features -- Advanced meal planning algorithms - ---- - -## Implementation Notes - -*(Technical considerations, dependencies, or constraints)* - -- **Stack**: See Spark App Template default-webapp.md / data-dashboard.md / etc. -- **Data Persistence**: [Where/how data is stored] -- **Third-party Services**: [Any external APIs or services] - ---- - -## Next Steps - -1. [ ] Review PRD with stakeholders -2. [ ] Create color palette and validate contrast -3. [ ] Set up typography in `index.css` -4. [ ] Scaffold project structure -5. [ ] Implement features in priority order -6. [ ] Test with real users -7. [ ] Iterate based on feedback - ---- - -## Example: Complete PRD - -See the spark-fullstack-template PRD.md for a complete example following this structure. - ---- - -**Tips**: -- Be specific, not vague -- Use concrete examples -- Validate color contrast ratios -- Think through edge cases early -- Keep it concise but complete -- Update PRD as requirements evolve -- Use this as a living document, not a one-time exercise - -**Remember**: A good PRD prevents wasted development time. Spend 1 hour planning to save 10 hours of rework. +# PRD Template - Spark App Template + +## Purpose + +A Product Requirements Document (PRD) helps structure thinking before implementation. Use this simplified template to plan features, design direction, and success criteria. + +## When to Use + +- Planning new applications +- Adding major features +- Clarifying requirements +- Aligning design decisions +- Documenting design system choices + +## Template + +--- + +# [Application Name] + +## Purpose Statement + +*(One sentence describing what this web app does and why it exists)* + +Example: "A weekly meal planning application that helps users organize their meals and automatically generates consolidated grocery shopping lists." + +--- + +## Experience Qualities + +*(Three adjectives with one-sentence elaborations defining the user experience)* + +1. **[Adjective]** - [One-sentence elaboration] +2. **[Adjective]** - [One-sentence elaboration] +3. **[Adjective]** - [One-sentence elaboration] + +Example: +1. **Effortless** - Planning meals should feel intuitive and quick, not like a chore +2. **Organized** - Clear visual structure makes the week's meals easy to scan and manage +3. **Satisfying** - Generating a shopping list from planned meals should feel like magic + +--- + +## Complexity Level + +*(Select ONE and explain why)* + +- [ ] **Micro Tool** (single-purpose application) + - *Why*: [One-sentence justification] + - *Example*: Calculator app, color picker, unit converter + +- [ ] **Content Showcase** (information-focused) + - *Why*: [One-sentence justification] + - *Example*: Marketing landing page, portfolio, blog + +- [ ] **Light Application** (multiple features with basic state) + - *Why*: [One-sentence justification] + - *Example*: Todo list, meal planner, expense tracker + +- [ ] **Complex Application** (advanced functionality, multiple views) + - *Why*: [One-sentence justification] + - *Example*: CRM, analytics dashboard, project management tool + +--- + +## Essential Features + +*(For each core feature, document:)* + +### Feature 1: [Feature Name] + +- **Functionality**: What it does +- **Purpose**: Why it matters to users +- **Trigger**: How the user initiates it +- **Progression**: Terse UX flow (use → to separate steps) + - Example: `Click slot → Enter meal name + ingredients → Save → Meal saved to slot` +- **Success Criteria**: How we'll know it works + +### Feature 2: [Feature Name] + +*(Repeat structure above)* + +--- + +## Edge Case Handling + +*(How will the app handle unexpected situations?)* + +- **[Edge Case Name]**: [Short one-line solution] +- **[Edge Case Name]**: [Short one-line solution] + +Example: +- **Empty week**: Show friendly empty state with prompt to add first meal +- **No ingredients**: Allow meals without ingredients (eating out, leftovers) +- **Duplicate ingredients**: Combine same ingredients across meals in grocery list + +--- + +## Design Direction + +*(What specific feelings should the design evoke in users?)* + +Example: "The design should feel like a well-organized kitchen bulletin board - warm, practical, and inviting. It should reduce the cognitive load of meal planning by presenting information clearly and making actions obvious." + +--- + +## Color Selection + +*(Describe the color scheme approach and specific colors. Use OKLCH format.)* + +### Color Palette + +- **Primary Color**: `oklch(L C H)` - [What it communicates] +- **Secondary Colors**: `oklch(L C H)` - [Their purposes] +- **Accent Color**: `oklch(L C H)` - [For CTAs and important elements] + +### Foreground/Background Pairings + +*(Document text colors on backgrounds with WCAG AA validation)* + +- `Background (name oklch(L C H))`: `Text color (oklch(L C H))` - Ratio [X.X:1] [✓ or ✗] + +Example: +- `Background (Warm Cream oklch(0.96 0.02 85))`: `Dark brown text (oklch(0.25 0.02 55))` - Ratio 8.5:1 ✓ +- `Primary (Herb Green oklch(0.55 0.15 145))`: `White text (oklch(0.99 0 0))` - Ratio 4.8:1 ✓ + +--- + +## Font Selection + +*(What characteristics should the typefaces convey, and which fonts should be used?)* + +**Chosen Fonts**: +- **Headings**: [Font Name] - [Character description] +- **Body**: [Font Name] - [Character description] +- **Code** *(if applicable)*: [Font Name] + +### Typographic Hierarchy + +- **H1 (Page Title)**: [Font] [Weight]/[Size]px/[Tracking] +- **H2 (Section Headers)**: [Font] [Weight]/[Size]px/[Tracking] +- **H3 (Subsections)**: [Font] [Weight]/[Size]px/[Tracking] +- **Body (Main Text)**: [Font] [Weight]/[Size]px +- **Caption (Supporting)**: [Font] [Weight]/[Size]px + +Example: +- **H1 (App Title)**: Space Grotesk Bold/32px/tight letter spacing +- **Body (Meal Names)**: Source Sans 3 Regular/16px +- **Caption (Ingredients)**: Source Sans 3 Regular/14px/muted color + +--- + +## Animations + +*(How should animations be used? Balance subtle functionality with moments of delight.)* + +Example: "Subtle animations reinforce actions without slowing down the experience - meals should 'pop' into place when added, and the grocery list should build item by item when generated, creating a satisfying moment of accomplishment." + +--- + +## Component Selection + +### UI Components + +*(Which shadcn components will be used?)* + +- **[Component Name]**: [Use case] +- **[Component Name]**: [Use case] + +Example: +- **Card**: For each day's meal container and the grocery list panel +- **Dialog**: For adding/editing meals with ingredient entry +- **Button**: Primary for generate list, secondary for add meal actions +- **Checkbox**: For checking off grocery items + +### Customizations + +*(Any custom components needed beyond shadcn?)* + +- **[Custom Component]**: [Why needed, what it does] + +Example: +- **Meal Slot Component**: Custom component showing empty state vs filled state with hover interactions +- **Ingredient Chip**: Removable tags for ingredients during entry + +### Component States + +*(How should interactive elements behave in different states?)* + +- **[Element] - [State]**: [Behavior/appearance] + +Example: +- **Empty meal slot**: Dashed border, muted plus icon, hover brightens +- **Filled meal slot**: Solid background, meal name visible, hover shows edit option +- **Grocery item checked**: Reduced opacity, strikethrough, checkbox filled + +### Icon Selection + +*(Which Lucide icons represent each action?)* + +- **[Action]**: [Icon name] + +Example: +- **Add meal**: Plus +- **Remove meal**: Trash +- **Generate grocery list**: ShoppingCart +- **Edit meal**: Pencil + +### Spacing System + +*(Consistent padding and margin values using Tailwind scale)* + +- **Gap between [elements]**: gap-[X] +- **Padding inside [containers]**: p-[X] + +Example: +- **Gap between days**: gap-4 +- **Gap between meal slots**: gap-2 +- **Padding inside cards**: p-4 +- **Padding for main container**: p-6 + +### Mobile Responsive Strategy + +*(How components adapt on smaller screens)* + +Example: +- Stack days vertically on mobile +- Grocery list becomes full-screen overlay +- Larger touch targets for meal slots + +--- + +## Success Metrics + +*(How will we measure if the application succeeds?)* + +**User Experience Metrics**: +- [ ] [Metric name and target] +- [ ] [Metric name and target] + +**Technical Metrics**: +- [ ] INP < 200ms +- [ ] LCP < 2.5s +- [ ] CLS < 0.1 + +**Feature Adoption**: +- [ ] [Specific feature usage target] + +--- + +## Out of Scope + +*(What will NOT be included in the initial version?)* + +- [ ] [Feature or capability] +- [ ] [Feature or capability] + +Example: +- Recipe database integration +- Social sharing features +- Advanced meal planning algorithms + +--- + +## Implementation Notes + +*(Technical considerations, dependencies, or constraints)* + +- **Stack**: See Spark App Template default-webapp.md / data-dashboard.md / etc. +- **Data Persistence**: [Where/how data is stored] +- **Third-party Services**: [Any external APIs or services] + +--- + +## Next Steps + +1. [ ] Review PRD with stakeholders +2. [ ] Create color palette and validate contrast +3. [ ] Set up typography in `index.css` +4. [ ] Scaffold project structure +5. [ ] Implement features in priority order +6. [ ] Test with real users +7. [ ] Iterate based on feedback + +--- + +## Example: Complete PRD + +See the spark-fullstack-template PRD.md for a complete example following this structure. + +--- + +**Tips**: +- Be specific, not vague +- Use concrete examples +- Validate color contrast ratios +- Think through edge cases early +- Keep it concise but complete +- Update PRD as requirements evolve +- Use this as a living document, not a one-time exercise + +**Remember**: A good PRD prevents wasted development time. Spend 1 hour planning to save 10 hours of rework. diff --git a/plugins/spark/skills/spark-app-template/references/radix-migration-guide.md b/plugins/spark/skills/spark-app-template/references/radix-migration-guide.md index beb135c..e94e1c1 100644 --- a/plugins/spark/skills/spark-app-template/references/radix-migration-guide.md +++ b/plugins/spark/skills/spark-app-template/references/radix-migration-guide.md @@ -1,279 +1,279 @@ -# Radix UI Migration Guide - Spark App Template - -## Context - -Radix UI, the foundation of shadcn/ui, has received fewer updates since its acquisition by WorkOS. While Radix remains stable, the ecosystem is evolving with new alternatives. - -## Current Status (January 2026) - -**Radix UI**: -- ✅ Mature, stable, production-ready -- ✅ Powers shadcn/ui (45+ components) -- ✅ Used by millions of production apps -- ⚠️ Slower update cadence -- ⚠️ Uncertainty about long-term roadmap - -**Recommendation for New Projects**: Use Radix with confidence, but be aware of migration paths. - -## Migration Options - -### Option 1: Stay with Radix (Recommended for Most) - -**When to choose**: -- Building production apps today -- Need stability over cutting-edge features -- Want proven components with wide adoption -- Using shadcn/ui ecosystem - -**Action**: No changes needed. Continue using Radix-based shadcn components. - -**Monitoring**: Watch for shadcn/ui announcements about alternative foundations. - ---- - -### Option 2: Migrate to Base UI - -**What is Base UI?** -- Built by original Radix team (now at Vercel/MUI) -- Currently in beta, but "looking really good" per shadcn -- Designed for easy migration from Radix -- Similar API and component structure - -**Status**: Beta (as of January 2026) - -**Migration Path**: - -1. **Wait for shadcn/ui Support** - shadcn/ui now supports Base UI components. You can choose Radix or Base UI when installing: - - ```bash - pnpm dlx shadcn@latest init - # Choose Base UI when prompted - ``` - -2. **Gradual Component Migration** - shadcn components are framework-agnostic. When Base UI components are added to shadcn, you can: - - ```bash - # Install Base UI version of component - pnpm dlx shadcn@latest add button --base-ui - ``` - -3. **Auto-Detection** - The shadcn CLI auto-detects your library and applies the right transformations. - -**Trade-offs**: -- ✅ Future-proof choice -- ✅ Active development -- ✅ Backed by Vercel/MUI -- ⚠️ Still in beta -- ⚠️ Smaller ecosystem currently - ---- - -### Option 3: Migrate to React Aria - -**What is React Aria?** -- Built by Adobe -- Powers React Spectrum (Adobe's design system) -- Superior accessibility implementation -- Behavior-first hooks implementing WAI-ARIA spec -- Production-ready and actively maintained - -**When to choose**: -- Accessibility is top priority -- Need advanced customization -- Want long-term Adobe backing -- Building design systems - -**Migration Effort**: Moderate to High -- React Aria has different API patterns -- Requires rewriting component wrappers -- More control, but more work - -**Example Migration**: - -Before (Radix via shadcn): -```tsx -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; - - - Open - - - Title - - - -``` - -After (React Aria): -```tsx -import { DialogTrigger, Modal, Dialog, Heading } from 'react-aria-components'; - - - - - - Title - {/* Content */} - - - -``` - -**Resources**: -- [React Aria Documentation](https://react-spectrum.adobe.com/react-aria/) -- [React Aria Components](https://react-spectrum.adobe.com/react-aria/components.html) - ---- - -## Practical Migration Strategy - -### Phase 1: Assessment (Now) - -1. **Inventory your Radix usage** - ```bash - grep -r "@radix-ui" src/ - ``` - -2. **Identify critical components** - - Dialog/Modal - - Dropdown Menu - - Select - - Popover - - Tooltip - - etc. - -3. **Evaluate impact** - - How many components use Radix? - - Are they heavily customized? - - What's the migration cost vs. benefit? - -### Phase 2: Monitoring (Ongoing) - -**Watch for**: -- shadcn/ui announcements about Base UI support -- Radix UI update frequency -- Community migration patterns -- Base UI stable release - -**Action Items**: -- Subscribe to shadcn/ui GitHub releases -- Follow @shadcn on Twitter/X -- Monitor Radix UI GitHub activity - -### Phase 3: Migration (When Ready) - -**Trigger Migration When**: -- Base UI reaches stable v1.0 -- shadcn/ui fully supports Base UI -- Radix UI shows signs of abandonment -- Security vulnerabilities go unpatched - -**Migration Approach**: - -1. **Test Environment First** - - Set up new branch - - Migrate one component at a time - - Test thoroughly before production - -2. **Gradual Rollout** - ```bash - # Migrate component by component - pnpm dlx shadcn@latest add button --base-ui - pnpm dlx shadcn@latest add dialog --base-ui - ``` - -3. **Coexistence** - - Both Radix and Base UI can coexist temporarily - - Migrate high-traffic components first - - Monitor for issues - -### Phase 4: Complete Migration (Future) - -**Timeline**: Likely 2026-2027 - -**Steps**: -1. All new components use Base UI -2. Gradual migration of existing components -3. Remove Radix dependencies when complete -4. Update documentation - ---- - -## For Spark App Template Users - -### Current Recommendation - -**Default**: Use Radix-based shadcn/ui -- Production-ready today -- Extensive component library (45+) -- Proven track record -- Wide community support - -**Exception**: If building from scratch in Q3 2026+, consider Base UI if stable. - -### Staying Updated - -Spark App Template will be updated when: -- Base UI reaches stable v1.0 -- shadcn/ui completes Base UI integration -- Migration path is proven and low-risk - -**Check for updates**: -- Spark App Template GitHub releases -- shadcn/ui changelog -- This migration guide (will be updated) - ---- - -## FAQ - -**Q: Should I worry about Radix today?** -A: No. Radix is stable and production-ready. Use it with confidence. - -**Q: When should I migrate?** -A: When Base UI is stable (v1.0+) and shadcn/ui fully supports it, likely mid-to-late 2026. - -**Q: Can I use Radix for new projects now?** -A: Yes. The migration path will be straightforward when Base UI is ready. - -**Q: What about React Aria?** -A: Excellent choice for accessibility-first projects, but requires more custom work. - -**Q: Will shadcn/ui abandon Radix?** -A: No indication of abandonment. shadcn is adding Base UI as an option, not replacing Radix. - -**Q: How much work is the migration?** -A: Minimal if using shadcn/ui. Components can be swapped one at a time with CLI. - ---- - -## Resources - -**Radix UI**: -- Documentation: [radix-ui.com](https://www.radix-ui.com/) -- GitHub: [github.com/radix-ui/primitives](https://github.com/radix-ui/primitives) - -**Base UI**: -- Documentation: [mui.com/base-ui](https://mui.com/base-ui/) -- GitHub: [github.com/mui/base-ui](https://github.com/mui/base-ui) - -**React Aria**: -- Documentation: [react-spectrum.adobe.com/react-aria](https://react-spectrum.adobe.com/react-aria/) -- GitHub: [github.com/adobe/react-spectrum](https://github.com/adobe/react-spectrum) - -**shadcn/ui**: -- Documentation: [ui.shadcn.com](https://ui.shadcn.com/) -- GitHub: [github.com/shadcn-ui/ui](https://github.com/shadcn-ui/ui) - ---- - -**Last Updated**: January 2026 - -**Next Review**: Q2 2026 (when Base UI v1.0 expected) - ---- - -**Remember**: Don't let uncertainty paralyze you. Radix is production-ready today. When Base UI reaches stability, migration will be straightforward. Build now, migrate later if needed. +# Radix UI Migration Guide - Spark App Template + +## Context + +Radix UI, the foundation of shadcn/ui, has received fewer updates since its acquisition by WorkOS. While Radix remains stable, the ecosystem is evolving with new alternatives. + +## Current Status (January 2026) + +**Radix UI**: +- ✅ Mature, stable, production-ready +- ✅ Powers shadcn/ui (45+ components) +- ✅ Used by millions of production apps +- ⚠️ Slower update cadence +- ⚠️ Uncertainty about long-term roadmap + +**Recommendation for New Projects**: Use Radix with confidence, but be aware of migration paths. + +## Migration Options + +### Option 1: Stay with Radix (Recommended for Most) + +**When to choose**: +- Building production apps today +- Need stability over cutting-edge features +- Want proven components with wide adoption +- Using shadcn/ui ecosystem + +**Action**: No changes needed. Continue using Radix-based shadcn components. + +**Monitoring**: Watch for shadcn/ui announcements about alternative foundations. + +--- + +### Option 2: Migrate to Base UI + +**What is Base UI?** +- Built by original Radix team (now at Vercel/MUI) +- Currently in beta, but "looking really good" per shadcn +- Designed for easy migration from Radix +- Similar API and component structure + +**Status**: Beta (as of January 2026) + +**Migration Path**: + +1. **Wait for shadcn/ui Support** + shadcn/ui now supports Base UI components. You can choose Radix or Base UI when installing: + + ```bash + pnpm dlx shadcn@latest init + # Choose Base UI when prompted + ``` + +2. **Gradual Component Migration** + shadcn components are framework-agnostic. When Base UI components are added to shadcn, you can: + + ```bash + # Install Base UI version of component + pnpm dlx shadcn@latest add button --base-ui + ``` + +3. **Auto-Detection** + The shadcn CLI auto-detects your library and applies the right transformations. + +**Trade-offs**: +- ✅ Future-proof choice +- ✅ Active development +- ✅ Backed by Vercel/MUI +- ⚠️ Still in beta +- ⚠️ Smaller ecosystem currently + +--- + +### Option 3: Migrate to React Aria + +**What is React Aria?** +- Built by Adobe +- Powers React Spectrum (Adobe's design system) +- Superior accessibility implementation +- Behavior-first hooks implementing WAI-ARIA spec +- Production-ready and actively maintained + +**When to choose**: +- Accessibility is top priority +- Need advanced customization +- Want long-term Adobe backing +- Building design systems + +**Migration Effort**: Moderate to High +- React Aria has different API patterns +- Requires rewriting component wrappers +- More control, but more work + +**Example Migration**: + +Before (Radix via shadcn): +```tsx +import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; + + + Open + + + Title + + + +``` + +After (React Aria): +```tsx +import { DialogTrigger, Modal, Dialog, Heading } from 'react-aria-components'; + + + + + + Title + {/* Content */} + + + +``` + +**Resources**: +- [React Aria Documentation](https://react-spectrum.adobe.com/react-aria/) +- [React Aria Components](https://react-spectrum.adobe.com/react-aria/components.html) + +--- + +## Practical Migration Strategy + +### Phase 1: Assessment (Now) + +1. **Inventory your Radix usage** + ```bash + grep -r "@radix-ui" src/ + ``` + +2. **Identify critical components** + - Dialog/Modal + - Dropdown Menu + - Select + - Popover + - Tooltip + - etc. + +3. **Evaluate impact** + - How many components use Radix? + - Are they heavily customized? + - What's the migration cost vs. benefit? + +### Phase 2: Monitoring (Ongoing) + +**Watch for**: +- shadcn/ui announcements about Base UI support +- Radix UI update frequency +- Community migration patterns +- Base UI stable release + +**Action Items**: +- Subscribe to shadcn/ui GitHub releases +- Follow @shadcn on Twitter/X +- Monitor Radix UI GitHub activity + +### Phase 3: Migration (When Ready) + +**Trigger Migration When**: +- Base UI reaches stable v1.0 +- shadcn/ui fully supports Base UI +- Radix UI shows signs of abandonment +- Security vulnerabilities go unpatched + +**Migration Approach**: + +1. **Test Environment First** + - Set up new branch + - Migrate one component at a time + - Test thoroughly before production + +2. **Gradual Rollout** + ```bash + # Migrate component by component + pnpm dlx shadcn@latest add button --base-ui + pnpm dlx shadcn@latest add dialog --base-ui + ``` + +3. **Coexistence** + - Both Radix and Base UI can coexist temporarily + - Migrate high-traffic components first + - Monitor for issues + +### Phase 4: Complete Migration (Future) + +**Timeline**: Likely 2026-2027 + +**Steps**: +1. All new components use Base UI +2. Gradual migration of existing components +3. Remove Radix dependencies when complete +4. Update documentation + +--- + +## For Spark App Template Users + +### Current Recommendation + +**Default**: Use Radix-based shadcn/ui +- Production-ready today +- Extensive component library (45+) +- Proven track record +- Wide community support + +**Exception**: If building from scratch in Q3 2026+, consider Base UI if stable. + +### Staying Updated + +Spark App Template will be updated when: +- Base UI reaches stable v1.0 +- shadcn/ui completes Base UI integration +- Migration path is proven and low-risk + +**Check for updates**: +- Spark App Template GitHub releases +- shadcn/ui changelog +- This migration guide (will be updated) + +--- + +## FAQ + +**Q: Should I worry about Radix today?** +A: No. Radix is stable and production-ready. Use it with confidence. + +**Q: When should I migrate?** +A: When Base UI is stable (v1.0+) and shadcn/ui fully supports it, likely mid-to-late 2026. + +**Q: Can I use Radix for new projects now?** +A: Yes. The migration path will be straightforward when Base UI is ready. + +**Q: What about React Aria?** +A: Excellent choice for accessibility-first projects, but requires more custom work. + +**Q: Will shadcn/ui abandon Radix?** +A: No indication of abandonment. shadcn is adding Base UI as an option, not replacing Radix. + +**Q: How much work is the migration?** +A: Minimal if using shadcn/ui. Components can be swapped one at a time with CLI. + +--- + +## Resources + +**Radix UI**: +- Documentation: [radix-ui.com](https://www.radix-ui.com/) +- GitHub: [github.com/radix-ui/primitives](https://github.com/radix-ui/primitives) + +**Base UI**: +- Documentation: [mui.com/base-ui](https://mui.com/base-ui/) +- GitHub: [github.com/mui/base-ui](https://github.com/mui/base-ui) + +**React Aria**: +- Documentation: [react-spectrum.adobe.com/react-aria](https://react-spectrum.adobe.com/react-aria/) +- GitHub: [github.com/adobe/react-spectrum](https://github.com/adobe/react-spectrum) + +**shadcn/ui**: +- Documentation: [ui.shadcn.com](https://ui.shadcn.com/) +- GitHub: [github.com/shadcn-ui/ui](https://github.com/shadcn-ui/ui) + +--- + +**Last Updated**: January 2026 + +**Next Review**: Q2 2026 (when Base UI v1.0 expected) + +--- + +**Remember**: Don't let uncertainty paralyze you. Radix is production-ready today. When Base UI reaches stability, migration will be straightforward. Build now, migrate later if needed. diff --git a/plugins/spark/skills/spark-app-template/references/typography-pairings.md b/plugins/spark/skills/spark-app-template/references/typography-pairings.md index 11c7675..a7db934 100644 --- a/plugins/spark/skills/spark-app-template/references/typography-pairings.md +++ b/plugins/spark/skills/spark-app-template/references/typography-pairings.md @@ -1,475 +1,475 @@ -# Typography Pairings - Spark App Template - -## Typography as Identity - -Typography is voice made visible. Your font choices communicate personality, professionalism, and brand identity before users read a single word. - -## Fonts to Avoid (Overused) - -These fonts have become clichés in modern web design: - -❌ **Inter** - The default choice for everything. Overused to the point of invisibility. -❌ **Roboto** - Google's everywhere font. Safe but soulless. -❌ **Arial / Helvetica** - Corporate boredom incarnate. -❌ **Space Grotesk** - Was trendy in 2023-2024, now cliché. -❌ **Poppins** - Every Figma tutorial uses this. - -**Why avoid them?** They're not bad fonts, they're just everywhere. Your brand deserves distinction. - -## Font Personality Guide - -Choose fonts based on the character you want to project: - -### Serious & Professional -- IBM Plex Sans, Source Sans 3, Work Sans -- Clean, readable, trustworthy -- Use for: B2B SaaS, enterprise tools, financial services - -### Creative & Distinctive -- Bricolage Grotesque, Cabinet Grotesk, General Sans -- Unique character, memorable -- Use for: Agencies, design tools, creative platforms - -### Technical & Precise -- JetBrains Mono, IBM Plex Mono, Fira Code -- Monospace aesthetic, developer-friendly -- Use for: Developer tools, code editors, technical products - -### Editorial & Elegant -- Newsreader, Playfair Display, Spectral -- Timeless serif styling -- Use for: Publications, content platforms, luxury brands - -### Modern & Friendly -- DM Sans, Plus Jakarta Sans, Outfit -- Approachable, warm, contemporary -- Use for: Consumer apps, community platforms, social products - -### Bold & Expressive -- Darker Grotesque, Lexend, Syne -- Strong personality, attention-grabbing -- Use for: Marketing sites, landing pages, bold brands - -## Recommended Pairings - -### Pairing 1: Technical & Clean -**Headings**: IBM Plex Sans (600, 700) -**Body**: Source Sans 3 (400, 500, 600) - -```html - -``` - -```css -:root { - --font-heading: 'IBM Plex Sans', sans-serif; - --font-body: 'Source Sans 3', sans-serif; -} -``` - -**Character**: Professional, technical, trustworthy -**Best for**: SaaS platforms, B2B tools, developer products -**Why it works**: Both fonts share geometric structure but distinct enough for hierarchy - ---- - -### Pairing 2: Editorial & Sophisticated -**Headings**: Newsreader (600, 700) -**Body**: Source Sans 3 (400, 500, 600) - -```html - -``` - -```css -:root { - --font-heading: 'Newsreader', serif; - --font-body: 'Source Sans 3', sans-serif; -} -``` - -**Character**: Editorial, classic, authoritative -**Best for**: Publications, content platforms, journalism, blogs -**Why it works**: Serif + sans-serif contrast creates clear hierarchy - ---- - -### Pairing 3: Modern & Distinctive -**Headings**: Bricolage Grotesque (600, 700, 800) -**Body**: DM Sans (400, 500, 600) - -```html - -``` - -```css -:root { - --font-heading: 'Bricolage Grotesque', sans-serif; - --font-body: 'DM Sans', sans-serif; -} -``` - -**Character**: Modern, distinctive, creative -**Best for**: Design agencies, creative tools, innovative products -**Why it works**: Bricolage's unique character balanced by DM Sans' neutrality - ---- - -### Pairing 4: Developer-Focused -**Headings**: IBM Plex Sans (600, 700) -**Body**: IBM Plex Sans (400, 500) -**Code**: IBM Plex Mono (400, 500) - -```html - -``` - -```css -:root { - --font-heading: 'IBM Plex Sans', sans-serif; - --font-body: 'IBM Plex Sans', sans-serif; - --font-mono: 'IBM Plex Mono', monospace; -} - -code, pre { - font-family: var(--font-mono); -} -``` - -**Character**: Technical, precise, developer-friendly -**Best for**: Code editors, dev tools, technical documentation -**Why it works**: Unified family creates cohesion; mono variant for code - ---- - -### Pairing 5: Warm & Approachable -**Headings**: Outfit (600, 700, 800) -**Body**: Plus Jakarta Sans (400, 500, 600) - -```html - -``` - -```css -:root { - --font-heading: 'Outfit', sans-serif; - --font-body: 'Plus Jakarta Sans', sans-serif; -} -``` - -**Character**: Friendly, modern, accessible -**Best for**: Consumer apps, community platforms, social products -**Why it works**: Both fonts have rounded, friendly forms - ---- - -### Pairing 6: Bold & Impactful -**Headings**: Syne (700, 800) -**Body**: Work Sans (400, 500, 600) - -```html - -``` - -```css -:root { - --font-heading: 'Syne', sans-serif; - --font-body: 'Work Sans', sans-serif; -} -``` - -**Character**: Bold, attention-grabbing, confident -**Best for**: Marketing sites, landing pages, bold brands -**Why it works**: Syne's distinctive style balanced by Work Sans' neutrality - ---- - -### Pairing 7: Minimalist & Refined -**Headings**: DM Sans (500, 600, 700) -**Body**: DM Sans (400, 500) - -```html - -``` - -```css -:root { - --font-heading: 'DM Sans', sans-serif; - --font-body: 'DM Sans', sans-serif; -} - -h1, h2, h3, h4, h5, h6 { - font-family: var(--font-heading); - letter-spacing: -0.02em; /* Tighter tracking for headings */ -} -``` - -**Character**: Clean, minimalist, modern -**Best for**: Minimalist designs, tools, utilities -**Why it works**: Single-font system with weight differentiation - ---- - -## Typography Scale - -Use these scales with your chosen pairing: - -### Standard Scale (Default) -```css -:root { - --text-xs: 0.75rem; /* 12px */ - --text-sm: 0.875rem; /* 14px */ - --text-base: 1rem; /* 16px */ - --text-lg: 1.125rem; /* 18px */ - --text-xl: 1.25rem; /* 20px */ - --text-2xl: 1.5rem; /* 24px */ - --text-3xl: 1.875rem; /* 30px */ - --text-4xl: 2.25rem; /* 36px */ - --text-5xl: 3rem; /* 48px */ - --text-6xl: 3.75rem; /* 60px */ -} -``` - -### Large Scale (Content-Focused) -```css -:root { - --text-base: 1.125rem; /* 18px body text */ - --text-lg: 1.25rem; /* 20px lead text */ - --text-xl: 1.5rem; /* 24px */ - --text-2xl: 2rem; /* 32px */ - --text-3xl: 2.5rem; /* 40px */ - --text-4xl: 3rem; /* 48px */ - --text-5xl: 3.5rem; /* 56px */ - --text-6xl: 4rem; /* 64px */ -} -``` - -### Compact Scale (Data-Dense) -```css -:root { - --text-xs: 0.6875rem; /* 11px */ - --text-sm: 0.8125rem; /* 13px */ - --text-base: 0.9375rem; /* 15px */ - --text-lg: 1.0625rem; /* 17px */ - --text-xl: 1.25rem; /* 20px */ - --text-2xl: 1.5rem; /* 24px */ - --text-3xl: 2rem; /* 32px */ - --text-4xl: 2.5rem; /* 40px */ -} -``` - -## Line Height Guidelines - -```css -/* Tight - for headings */ -.line-height-tight { - line-height: 1.2; -} - -/* Normal - for UI text */ -.line-height-normal { - line-height: 1.5; -} - -/* Relaxed - for body content */ -.line-height-relaxed { - line-height: 1.7; -} - -/* Loose - for large body text */ -.line-height-loose { - line-height: 1.8; -} -``` - -**Rule of thumb**: -- Larger text → tighter line-height (headings: 1.1-1.3) -- Smaller text → looser line-height (body: 1.5-1.7) -- Narrow columns → looser line-height -- Wide columns → tighter line-height - -## Letter Spacing (Tracking) - -```css -/* Tight - for headings, large text */ -.tracking-tight { - letter-spacing: -0.02em; -} - -/* Normal - default */ -.tracking-normal { - letter-spacing: 0; -} - -/* Wide - for small caps, labels */ -.tracking-wide { - letter-spacing: 0.05em; -} - -/* Wider - for uppercase labels */ -.tracking-wider { - letter-spacing: 0.1em; -} -``` - -**When to use**: -- Large headings (48px+): `-0.02em` to `-0.04em` -- Body text: `0` (default) -- Small uppercase labels: `0.05em` to `0.1em` -- Never positive tracking on lowercase text - -## Font Loading Best Practices - -### Use Variable Fonts When Available - -Variable fonts = one file, multiple weights. - -```html - - - - - - - -``` - -**Performance win**: Fewer HTTP requests, smaller total size, smooth weight interpolation. - -### Font Display Strategy - -```css -@font-face { - font-family: 'Custom Font'; - src: url('/fonts/font.woff2') format('woff2'); - font-display: swap; /* Show fallback immediately, swap when loaded */ - font-weight: 400 700; /* Variable font weight range */ -} -``` - -**Options**: -- `swap` (recommended): Show fallback, swap when loaded -- `optional`: Use custom font only if cached -- `fallback`: Brief invisible period, then show fallback - -### Preload Critical Fonts - -```html - - - - -``` - -**Only preload**: -- Heading font (if custom-hosted) -- Above-the-fold text -- Max 1-2 fonts - -## Fallback Font Stacks - -Define system fallbacks that match your custom font's metrics: - -```css -:root { - /* Sans-serif stacks */ - --font-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - - /* Serif stacks */ - --font-serif: 'Newsreader', 'Iowan Old Style', 'Apple Garamond', 'Palatino Linotype', 'Times New Roman', serif; - - /* Monospace stacks */ - --font-mono: 'IBM Plex Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Courier New', monospace; -} -``` - -## Responsive Typography - -### Fluid Type Scale - -```css -h1 { - font-size: clamp(2.5rem, 5vw + 1rem, 4rem); - /* Min: 40px, Scales with viewport, Max: 64px */ -} - -h2 { - font-size: clamp(2rem, 4vw + 0.5rem, 3rem); -} - -body { - font-size: clamp(1rem, 2vw, 1.125rem); -} -``` - -### Breakpoint-Based (Tailwind) - -```tsx -

- Responsive Heading -

-``` - -## Accessibility Considerations - -**Minimum Sizes**: -- Body text: 16px minimum (1rem) -- Small text (captions): 14px minimum (0.875rem) -- Never go below 12px for any text - -**Contrast**: -- Body text: 4.5:1 contrast ratio (WCAG AA) -- Large text (18px+ or 14px bold): 3:1 contrast ratio - -**Line Length**: -- Optimal: 60-75 characters per line -- Max: 90 characters per line -- Use `max-width: 65ch` for readable content blocks - -## Testing Your Typography - -**Checklist**: -- [ ] Readable at all sizes (mobile to desktop) -- [ ] Clear hierarchy (can distinguish h1 from h2 from h3) -- [ ] Sufficient contrast (pass WCAG AA) -- [ ] Line length appropriate (not too wide) -- [ ] Loads quickly (< 100ms font load) -- [ ] Fallback fonts match proportions -- [ ] Accessible (zoom to 200% still readable) - -**Tools**: -- Google Fonts: fonts.google.com -- Type Scale Calculator: type-scale.com -- Font Pairing: fontpair.co -- Contrast Checker: whocanuse.com - ---- - -**Remember**: Typography is not just decoration—it's the primary interface between your content and your users. Choose wisely, test thoroughly, and iterate based on feedback. +# Typography Pairings - Spark App Template + +## Typography as Identity + +Typography is voice made visible. Your font choices communicate personality, professionalism, and brand identity before users read a single word. + +## Fonts to Avoid (Overused) + +These fonts have become clichés in modern web design: + +❌ **Inter** - The default choice for everything. Overused to the point of invisibility. +❌ **Roboto** - Google's everywhere font. Safe but soulless. +❌ **Arial / Helvetica** - Corporate boredom incarnate. +❌ **Space Grotesk** - Was trendy in 2023-2024, now cliché. +❌ **Poppins** - Every Figma tutorial uses this. + +**Why avoid them?** They're not bad fonts, they're just everywhere. Your brand deserves distinction. + +## Font Personality Guide + +Choose fonts based on the character you want to project: + +### Serious & Professional +- IBM Plex Sans, Source Sans 3, Work Sans +- Clean, readable, trustworthy +- Use for: B2B SaaS, enterprise tools, financial services + +### Creative & Distinctive +- Bricolage Grotesque, Cabinet Grotesk, General Sans +- Unique character, memorable +- Use for: Agencies, design tools, creative platforms + +### Technical & Precise +- JetBrains Mono, IBM Plex Mono, Fira Code +- Monospace aesthetic, developer-friendly +- Use for: Developer tools, code editors, technical products + +### Editorial & Elegant +- Newsreader, Playfair Display, Spectral +- Timeless serif styling +- Use for: Publications, content platforms, luxury brands + +### Modern & Friendly +- DM Sans, Plus Jakarta Sans, Outfit +- Approachable, warm, contemporary +- Use for: Consumer apps, community platforms, social products + +### Bold & Expressive +- Darker Grotesque, Lexend, Syne +- Strong personality, attention-grabbing +- Use for: Marketing sites, landing pages, bold brands + +## Recommended Pairings + +### Pairing 1: Technical & Clean +**Headings**: IBM Plex Sans (600, 700) +**Body**: Source Sans 3 (400, 500, 600) + +```html + +``` + +```css +:root { + --font-heading: 'IBM Plex Sans', sans-serif; + --font-body: 'Source Sans 3', sans-serif; +} +``` + +**Character**: Professional, technical, trustworthy +**Best for**: SaaS platforms, B2B tools, developer products +**Why it works**: Both fonts share geometric structure but distinct enough for hierarchy + +--- + +### Pairing 2: Editorial & Sophisticated +**Headings**: Newsreader (600, 700) +**Body**: Source Sans 3 (400, 500, 600) + +```html + +``` + +```css +:root { + --font-heading: 'Newsreader', serif; + --font-body: 'Source Sans 3', sans-serif; +} +``` + +**Character**: Editorial, classic, authoritative +**Best for**: Publications, content platforms, journalism, blogs +**Why it works**: Serif + sans-serif contrast creates clear hierarchy + +--- + +### Pairing 3: Modern & Distinctive +**Headings**: Bricolage Grotesque (600, 700, 800) +**Body**: DM Sans (400, 500, 600) + +```html + +``` + +```css +:root { + --font-heading: 'Bricolage Grotesque', sans-serif; + --font-body: 'DM Sans', sans-serif; +} +``` + +**Character**: Modern, distinctive, creative +**Best for**: Design agencies, creative tools, innovative products +**Why it works**: Bricolage's unique character balanced by DM Sans' neutrality + +--- + +### Pairing 4: Developer-Focused +**Headings**: IBM Plex Sans (600, 700) +**Body**: IBM Plex Sans (400, 500) +**Code**: IBM Plex Mono (400, 500) + +```html + +``` + +```css +:root { + --font-heading: 'IBM Plex Sans', sans-serif; + --font-body: 'IBM Plex Sans', sans-serif; + --font-mono: 'IBM Plex Mono', monospace; +} + +code, pre { + font-family: var(--font-mono); +} +``` + +**Character**: Technical, precise, developer-friendly +**Best for**: Code editors, dev tools, technical documentation +**Why it works**: Unified family creates cohesion; mono variant for code + +--- + +### Pairing 5: Warm & Approachable +**Headings**: Outfit (600, 700, 800) +**Body**: Plus Jakarta Sans (400, 500, 600) + +```html + +``` + +```css +:root { + --font-heading: 'Outfit', sans-serif; + --font-body: 'Plus Jakarta Sans', sans-serif; +} +``` + +**Character**: Friendly, modern, accessible +**Best for**: Consumer apps, community platforms, social products +**Why it works**: Both fonts have rounded, friendly forms + +--- + +### Pairing 6: Bold & Impactful +**Headings**: Syne (700, 800) +**Body**: Work Sans (400, 500, 600) + +```html + +``` + +```css +:root { + --font-heading: 'Syne', sans-serif; + --font-body: 'Work Sans', sans-serif; +} +``` + +**Character**: Bold, attention-grabbing, confident +**Best for**: Marketing sites, landing pages, bold brands +**Why it works**: Syne's distinctive style balanced by Work Sans' neutrality + +--- + +### Pairing 7: Minimalist & Refined +**Headings**: DM Sans (500, 600, 700) +**Body**: DM Sans (400, 500) + +```html + +``` + +```css +:root { + --font-heading: 'DM Sans', sans-serif; + --font-body: 'DM Sans', sans-serif; +} + +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-heading); + letter-spacing: -0.02em; /* Tighter tracking for headings */ +} +``` + +**Character**: Clean, minimalist, modern +**Best for**: Minimalist designs, tools, utilities +**Why it works**: Single-font system with weight differentiation + +--- + +## Typography Scale + +Use these scales with your chosen pairing: + +### Standard Scale (Default) +```css +:root { + --text-xs: 0.75rem; /* 12px */ + --text-sm: 0.875rem; /* 14px */ + --text-base: 1rem; /* 16px */ + --text-lg: 1.125rem; /* 18px */ + --text-xl: 1.25rem; /* 20px */ + --text-2xl: 1.5rem; /* 24px */ + --text-3xl: 1.875rem; /* 30px */ + --text-4xl: 2.25rem; /* 36px */ + --text-5xl: 3rem; /* 48px */ + --text-6xl: 3.75rem; /* 60px */ +} +``` + +### Large Scale (Content-Focused) +```css +:root { + --text-base: 1.125rem; /* 18px body text */ + --text-lg: 1.25rem; /* 20px lead text */ + --text-xl: 1.5rem; /* 24px */ + --text-2xl: 2rem; /* 32px */ + --text-3xl: 2.5rem; /* 40px */ + --text-4xl: 3rem; /* 48px */ + --text-5xl: 3.5rem; /* 56px */ + --text-6xl: 4rem; /* 64px */ +} +``` + +### Compact Scale (Data-Dense) +```css +:root { + --text-xs: 0.6875rem; /* 11px */ + --text-sm: 0.8125rem; /* 13px */ + --text-base: 0.9375rem; /* 15px */ + --text-lg: 1.0625rem; /* 17px */ + --text-xl: 1.25rem; /* 20px */ + --text-2xl: 1.5rem; /* 24px */ + --text-3xl: 2rem; /* 32px */ + --text-4xl: 2.5rem; /* 40px */ +} +``` + +## Line Height Guidelines + +```css +/* Tight - for headings */ +.line-height-tight { + line-height: 1.2; +} + +/* Normal - for UI text */ +.line-height-normal { + line-height: 1.5; +} + +/* Relaxed - for body content */ +.line-height-relaxed { + line-height: 1.7; +} + +/* Loose - for large body text */ +.line-height-loose { + line-height: 1.8; +} +``` + +**Rule of thumb**: +- Larger text → tighter line-height (headings: 1.1-1.3) +- Smaller text → looser line-height (body: 1.5-1.7) +- Narrow columns → looser line-height +- Wide columns → tighter line-height + +## Letter Spacing (Tracking) + +```css +/* Tight - for headings, large text */ +.tracking-tight { + letter-spacing: -0.02em; +} + +/* Normal - default */ +.tracking-normal { + letter-spacing: 0; +} + +/* Wide - for small caps, labels */ +.tracking-wide { + letter-spacing: 0.05em; +} + +/* Wider - for uppercase labels */ +.tracking-wider { + letter-spacing: 0.1em; +} +``` + +**When to use**: +- Large headings (48px+): `-0.02em` to `-0.04em` +- Body text: `0` (default) +- Small uppercase labels: `0.05em` to `0.1em` +- Never positive tracking on lowercase text + +## Font Loading Best Practices + +### Use Variable Fonts When Available + +Variable fonts = one file, multiple weights. + +```html + + + + + + + +``` + +**Performance win**: Fewer HTTP requests, smaller total size, smooth weight interpolation. + +### Font Display Strategy + +```css +@font-face { + font-family: 'Custom Font'; + src: url('/fonts/font.woff2') format('woff2'); + font-display: swap; /* Show fallback immediately, swap when loaded */ + font-weight: 400 700; /* Variable font weight range */ +} +``` + +**Options**: +- `swap` (recommended): Show fallback, swap when loaded +- `optional`: Use custom font only if cached +- `fallback`: Brief invisible period, then show fallback + +### Preload Critical Fonts + +```html + + + + +``` + +**Only preload**: +- Heading font (if custom-hosted) +- Above-the-fold text +- Max 1-2 fonts + +## Fallback Font Stacks + +Define system fallbacks that match your custom font's metrics: + +```css +:root { + /* Sans-serif stacks */ + --font-sans: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + + /* Serif stacks */ + --font-serif: 'Newsreader', 'Iowan Old Style', 'Apple Garamond', 'Palatino Linotype', 'Times New Roman', serif; + + /* Monospace stacks */ + --font-mono: 'IBM Plex Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Courier New', monospace; +} +``` + +## Responsive Typography + +### Fluid Type Scale + +```css +h1 { + font-size: clamp(2.5rem, 5vw + 1rem, 4rem); + /* Min: 40px, Scales with viewport, Max: 64px */ +} + +h2 { + font-size: clamp(2rem, 4vw + 0.5rem, 3rem); +} + +body { + font-size: clamp(1rem, 2vw, 1.125rem); +} +``` + +### Breakpoint-Based (Tailwind) + +```tsx +

+ Responsive Heading +

+``` + +## Accessibility Considerations + +**Minimum Sizes**: +- Body text: 16px minimum (1rem) +- Small text (captions): 14px minimum (0.875rem) +- Never go below 12px for any text + +**Contrast**: +- Body text: 4.5:1 contrast ratio (WCAG AA) +- Large text (18px+ or 14px bold): 3:1 contrast ratio + +**Line Length**: +- Optimal: 60-75 characters per line +- Max: 90 characters per line +- Use `max-width: 65ch` for readable content blocks + +## Testing Your Typography + +**Checklist**: +- [ ] Readable at all sizes (mobile to desktop) +- [ ] Clear hierarchy (can distinguish h1 from h2 from h3) +- [ ] Sufficient contrast (pass WCAG AA) +- [ ] Line length appropriate (not too wide) +- [ ] Loads quickly (< 100ms font load) +- [ ] Fallback fonts match proportions +- [ ] Accessible (zoom to 200% still readable) + +**Tools**: +- Google Fonts: fonts.google.com +- Type Scale Calculator: type-scale.com +- Font Pairing: fontpair.co +- Contrast Checker: whocanuse.com + +--- + +**Remember**: Typography is not just decoration—it's the primary interface between your content and your users. Choose wisely, test thoroughly, and iterate based on feedback. diff --git a/plugins/spark/skills/spark-app-template/stacks/complex-application.md b/plugins/spark/skills/spark-app-template/stacks/complex-application.md index 1e024bc..4fbce90 100644 --- a/plugins/spark/skills/spark-app-template/stacks/complex-application.md +++ b/plugins/spark/skills/spark-app-template/stacks/complex-application.md @@ -1,896 +1,896 @@ -# Complex Application Stack - -## Overview - -The complex application stack is designed for sophisticated multi-view applications requiring advanced state management, complex navigation, and robust architecture. Use for SaaS platforms, enterprise tools, and feature-rich applications. - -## When to Use - -- SaaS platforms -- Enterprise applications -- Multi-user systems -- Complex workflows with many views -- Applications requiring centralized state -- Tools with advanced features and interactions - -## Extends Default Stack - -This stack includes ALL packages from `default-webapp.md` PLUS the following additive packages. - -## Additional Packages - -### State Management -```bash -pnpm add zustand # Lightweight, flexible state management -``` - -### Date & Time Handling -```bash -pnpm add date-fns -``` - -### Additional Utilities -```bash -pnpm add uuid # Generate unique IDs -pnpm add react-resizable-panels # Resizable layouts (often in shadcn) -``` - -### Additional shadcn Components -```bash -# Navigation & Layout -pnpm dlx shadcn@latest add navigation-menu -pnpm dlx shadcn@latest add breadcrumb -pnpm dlx shadcn@latest add sidebar -pnpm dlx shadcn@latest add resizable -pnpm dlx shadcn@latest add sheet - -# Data & Forms -pnpm dlx shadcn@latest add table -pnpm dlx shadcn@latest add select -pnpm dlx shadcn@latest add combobox -pnpm dlx shadcn@latest add command -pnpm dlx shadcn@latest add calendar -pnpm dlx shadcn@latest add popover -pnpm dlx shadcn@latest add dropdown-menu - -# Feedback -pnpm dlx shadcn@latest add alert -pnpm dlx shadcn@latest add alert-dialog -pnpm dlx shadcn@latest add toast -pnpm dlx shadcn@latest add progress -pnpm dlx shadcn@latest add skeleton -``` - -## Architecture Patterns - -### State Management with Zustand - -Create stores for different domains: - -```tsx -// src/stores/useAuthStore.ts -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; - -interface User { - id: string; - name: string; - email: string; -} - -interface AuthState { - user: User | null; - token: string | null; - login: (user: User, token: string) => void; - logout: () => void; -} - -export const useAuthStore = create()( - persist( - (set) => ({ - user: null, - token: null, - login: (user, token) => set({ user, token }), - logout: () => set({ user: null, token: null }), - }), - { - name: 'auth-storage', - } - ) -); -``` - -```tsx -// src/stores/useAppStore.ts -import { create } from 'zustand'; - -interface AppState { - sidebarOpen: boolean; - currentView: string; - toggleSidebar: () => void; - setView: (view: string) => void; -} - -export const useAppStore = create((set) => ({ - sidebarOpen: true, - currentView: 'dashboard', - toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })), - setView: (view) => set({ currentView: view }), -})); -``` - -### Application Layout - -```tsx -// src/components/AppLayout.tsx -import { Outlet } from '@tanstack/react-router'; -import { Sidebar } from './Sidebar'; -import { Header } from './Header'; -import { useAppStore } from '@/stores/useAppStore'; - -export function AppLayout() { - const sidebarOpen = useAppStore((state) => state.sidebarOpen); - - return ( -
- {/* Sidebar */} - {sidebarOpen && ( - - )} - - {/* Main content */} -
-
-
- -
-
-
- ); -} -``` - -## Layout Scrolling Patterns - -Complex applications often need independent scrolling areas (sidebar, main content, modals). Getting scrolling right requires understanding flexbox constraints and when to use ScrollArea vs native overflow. - -### Core Principle: Flexbox Container Pattern - -For scrolling to work in constrained spaces, follow this pattern: - -```tsx -
{/* Define height constraint */} -
Fixed header
-
Scrollable content
-
Fixed footer
-
-``` - -**Key rules:** -- Parent must have explicit height (`h-screen`, `h-full`, or `flex-1` from its parent) -- Fixed elements use `flex-shrink-0` -- Scrollable element uses `flex-1` to fill remaining space -- Scrollable element needs `overflow-auto` or be a `ScrollArea` component - -### Split-Pane Layout (Sidebar + Content) - -Most complex apps use this pattern: - -```tsx -// Full-height split pane with independent scrolling -export function AppShell() { - return ( -
- {/* Left Sidebar */} -
-
-

Sidebar Header

-
-
- -
-
- - {/* Right Content */} -
-
-

Page Header

-
-
-
- {/* Main content that scrolls */} -
-
-
-
- ); -} -``` - -**Why this works:** -- Root uses `h-screen overflow-hidden` to constrain total height -- Both panes use `flex flex-col` to stack header + scrollable area -- Headers use `flex-shrink-0` to prevent compression -- Scrollable areas use `flex-1 overflow-auto` to fill remaining space - -### When to Use ScrollArea vs Native Overflow - -**Use native `overflow-auto` (recommended):** -- Full-height scrolling areas (sidebars, main content) -- Simpler implementation, more reliable -- Better browser support and performance -- Mobile-friendly (respects system scroll behavior) -- Works consistently with flexbox layouts - -**Use shadcn `ScrollArea` (advanced):** -- Small contained regions with custom scrollbar styling -- Modals/dialogs with fixed max-height -- When you need precise scrollbar customization -- Note: Can have edge cases with flex-1, prefer native overflow for full-height - -```tsx -{/* Full-height areas - use native overflow (recommended) */} -
-
Sidebar or main content
-
- -{/* Small contained areas - ScrollArea acceptable */} - -
Fixed height content
-
-``` - -### Common Mistakes to Avoid - -❌ **Don't use calc() for scroll heights:** -```tsx -// BAD: Brittle, breaks on content changes - -``` - -✅ **Do use flexbox:** -```tsx -// GOOD: Flexible, adapts to any layout -
-``` - -❌ **Don't forget parent constraints:** -```tsx -// BAD: flex-1 without parent height does nothing -
-``` - -✅ **Do establish height on parent:** -```tsx -// GOOD: Parent has h-screen -
-
-``` - -❌ **Don't skip overflow-hidden on parent:** -```tsx -// BAD: Can cause layout issues -
-
-``` - -✅ **Do add overflow-hidden to parent:** -```tsx -// GOOD: Prevents flex-1 from growing beyond bounds -
-
-``` - -### Modal with Scrollable Content - -```tsx - - - Modal Title - - -
- {/* Long scrollable content */} -
-
- - - -
-``` - -### Debugging Scrolling Issues - -If scrolling doesn't work: - -1. **Check parent height:** Use browser devtools to verify the scrollable element's parent has a constrained height -2. **Verify flex setup:** Ensure `flex flex-col` on parent, `flex-1` on scrollable child -3. **Confirm overflow:** Check if `overflow-auto` or ScrollArea is applied -4. **Look for overflow-hidden:** Parent of scrollable might need `overflow-hidden` to constrain growth - -**Quick diagnostic:** -```tsx -// Add temporary red border to see element bounds -
-``` - -If the red border doesn't have the height you expect, the problem is in the parent flex setup, not the scrolling itself. - -### Protected Routes - -```tsx -// src/routes/_authenticated.tsx -import { createFileRoute, redirect } from '@tanstack/react-router'; -import { useAuthStore } from '@/stores/useAuthStore'; - -export const Route = createFileRoute('/_authenticated')({ - beforeLoad: async () => { - const token = useAuthStore.getState().token; - if (!token) { - throw redirect({ to: '/login' }); - } - }, - component: AppLayout, -}); -``` - -```tsx -// src/routes/_authenticated/dashboard.tsx -export const Route = createFileRoute('/_authenticated/dashboard')({ - component: Dashboard, -}); -``` - -## Navigation Patterns - -### Sidebar Navigation - -```tsx -import { Link } from '@tanstack/react-router'; -import { Home, Users, Settings, FileText } from 'lucide-react'; -import { cn } from '@/lib/utils'; - -const navigation = [ - { name: 'Dashboard', href: '/dashboard', icon: Home }, - { name: 'Users', href: '/users', icon: Users }, - { name: 'Documents', href: '/documents', icon: FileText }, - { name: 'Settings', href: '/settings', icon: Settings }, -]; - -export function Sidebar() { - return ( - - ); -} -``` - -### Hierarchical Sidebar Items - -When displaying hierarchical data (org charts, nested navigation, file trees) in sidebars, use padding-based indentation to prevent text clipping. - -**✅ Correct Pattern:** -```tsx -interface HierarchyItemProps { - person: { name: string; title: string; initials: string }; - level: number; // 0, 1, 2 for depth - isSelected: boolean; -} - -function HierarchyItem({ person, level, isSelected }: HierarchyItemProps) { - const paddingLeft = level === 0 ? 'pl-3' : level === 1 ? 'pl-5' : 'pl-7'; - - return ( - - ); -} -``` - -**Key Rules:** - -❌ **Don't use margin for indentation:** -```tsx - - Page {page} - -
-
- ); -} -``` - -## Complex Forms - -### Multi-Step Form - -```tsx -import { useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { z } from 'zod'; -import { Button } from '@/components/ui/button'; -import { Progress } from '@/components/ui/progress'; - -const step1Schema = z.object({ - name: z.string().min(2), - email: z.string().email(), -}); - -const step2Schema = z.object({ - company: z.string().min(2), - role: z.string(), -}); - -export function MultiStepForm() { - const [step, setStep] = useState(1); - const [formData, setFormData] = useState({}); - - const schema = step === 1 ? step1Schema : step2Schema; - const form = useForm({ - resolver: zodResolver(schema), - }); - - const onSubmit = (data: any) => { - if (step === 1) { - setFormData({ ...formData, ...data }); - setStep(2); - } else { - // Final submission - const finalData = { ...formData, ...data }; - console.log(finalData); - } - }; - - const progress = (step / 2) * 100; - - return ( -
- - -
- {step === 1 && ( - <> - {/* Step 1 fields */} - - - - )} - - {step === 2 && ( - <> - {/* Step 2 fields */} - - - - )} - -
- {step > 1 && ( - - )} - -
-
-
- ); -} -``` - -## Performance Optimization - -### Code Splitting by Route - -TanStack Router handles this automatically. Each route is lazy-loaded. - -### Virtual Scrolling for Large Lists - -```tsx -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useRef } from 'react'; - -export function VirtualList({ items }: { items: any[] }) { - const parentRef = useRef(null); - - const virtualizer = useVirtualizer({ - count: items.length, - getScrollElement: () => parentRef.current, - estimateSize: () => 50, - }); - - return ( -
-
- {virtualizer.getVirtualItems().map((virtualItem) => ( -
- {items[virtualItem.index].name} -
- ))} -
-
- ); -} -``` - -### React Compiler - -Enable for automatic memoization: - -```bash -pnpm add -D babel-plugin-react-compiler -``` - -Configure in Vite: -```typescript -// vite.config.ts -export default defineConfig({ - plugins: [ - react({ - babel: { - plugins: [ - ['babel-plugin-react-compiler', {}], - ], - }, - }), - ], -}); -``` - -## Testing Strategy - -### Component Testing - -```tsx -import { render, screen } from '@testing-library/react'; -import { Button } from './button'; - -test('renders button with text', () => { - render(); - expect(screen.getByText('Click me')).toBeInTheDocument(); -}); -``` - -### E2E Testing (Playwright) - -```bash -pnpm add -D @playwright/test -``` - -```typescript -// tests/login.spec.ts -import { test, expect } from '@playwright/test'; - -test('user can log in', async ({ page }) => { - await page.goto('/login'); - await page.fill('[name="email"]', 'user@example.com'); - await page.fill('[name="password"]', 'password'); - await page.click('button[type="submit"]'); - await expect(page).toHaveURL('/dashboard'); -}); -``` - -## Security Considerations - -- Validate all inputs with Zod -- Sanitize user-generated content -- Use HTTPS in production -- Implement CSRF protection -- Set secure cookie flags -- Use environment variables for secrets -- Implement rate limiting -- Regular dependency updates - -## Deployment - -### Environment Variables - -```bash -# .env.production -VITE_API_URL=https://api.production.com -VITE_APP_URL=https://app.production.com -``` - -Access in code: -```typescript -const API_URL = import.meta.env.VITE_API_URL; -``` - -### Build Optimization - -```bash -# Production build -pnpm build - -# Analyze bundle size -pnpm add -D rollup-plugin-visualizer -``` - -## Next Steps - -1. Define application architecture and feature domains -2. Set up Zustand stores for global state -3. Create protected route structure -4. Implement authentication flow -5. Build core navigation (sidebar, command palette) -6. Develop feature modules -7. Add comprehensive error handling -8. Optimize performance (code splitting, caching) -9. Implement testing strategy -10. Deploy to production +# Complex Application Stack + +## Overview + +The complex application stack is designed for sophisticated multi-view applications requiring advanced state management, complex navigation, and robust architecture. Use for SaaS platforms, enterprise tools, and feature-rich applications. + +## When to Use + +- SaaS platforms +- Enterprise applications +- Multi-user systems +- Complex workflows with many views +- Applications requiring centralized state +- Tools with advanced features and interactions + +## Extends Default Stack + +This stack includes ALL packages from `default-webapp.md` PLUS the following additive packages. + +## Additional Packages + +### State Management +```bash +pnpm add zustand # Lightweight, flexible state management +``` + +### Date & Time Handling +```bash +pnpm add date-fns +``` + +### Additional Utilities +```bash +pnpm add uuid # Generate unique IDs +pnpm add react-resizable-panels # Resizable layouts (often in shadcn) +``` + +### Additional shadcn Components +```bash +# Navigation & Layout +pnpm dlx shadcn@latest add navigation-menu +pnpm dlx shadcn@latest add breadcrumb +pnpm dlx shadcn@latest add sidebar +pnpm dlx shadcn@latest add resizable +pnpm dlx shadcn@latest add sheet + +# Data & Forms +pnpm dlx shadcn@latest add table +pnpm dlx shadcn@latest add select +pnpm dlx shadcn@latest add combobox +pnpm dlx shadcn@latest add command +pnpm dlx shadcn@latest add calendar +pnpm dlx shadcn@latest add popover +pnpm dlx shadcn@latest add dropdown-menu + +# Feedback +pnpm dlx shadcn@latest add alert +pnpm dlx shadcn@latest add alert-dialog +pnpm dlx shadcn@latest add toast +pnpm dlx shadcn@latest add progress +pnpm dlx shadcn@latest add skeleton +``` + +## Architecture Patterns + +### State Management with Zustand + +Create stores for different domains: + +```tsx +// src/stores/useAuthStore.ts +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +interface User { + id: string; + name: string; + email: string; +} + +interface AuthState { + user: User | null; + token: string | null; + login: (user: User, token: string) => void; + logout: () => void; +} + +export const useAuthStore = create()( + persist( + (set) => ({ + user: null, + token: null, + login: (user, token) => set({ user, token }), + logout: () => set({ user: null, token: null }), + }), + { + name: 'auth-storage', + } + ) +); +``` + +```tsx +// src/stores/useAppStore.ts +import { create } from 'zustand'; + +interface AppState { + sidebarOpen: boolean; + currentView: string; + toggleSidebar: () => void; + setView: (view: string) => void; +} + +export const useAppStore = create((set) => ({ + sidebarOpen: true, + currentView: 'dashboard', + toggleSidebar: () => set((state) => ({ sidebarOpen: !state.sidebarOpen })), + setView: (view) => set({ currentView: view }), +})); +``` + +### Application Layout + +```tsx +// src/components/AppLayout.tsx +import { Outlet } from '@tanstack/react-router'; +import { Sidebar } from './Sidebar'; +import { Header } from './Header'; +import { useAppStore } from '@/stores/useAppStore'; + +export function AppLayout() { + const sidebarOpen = useAppStore((state) => state.sidebarOpen); + + return ( +
+ {/* Sidebar */} + {sidebarOpen && ( + + )} + + {/* Main content */} +
+
+
+ +
+
+
+ ); +} +``` + +## Layout Scrolling Patterns + +Complex applications often need independent scrolling areas (sidebar, main content, modals). Getting scrolling right requires understanding flexbox constraints and when to use ScrollArea vs native overflow. + +### Core Principle: Flexbox Container Pattern + +For scrolling to work in constrained spaces, follow this pattern: + +```tsx +
{/* Define height constraint */} +
Fixed header
+
Scrollable content
+
Fixed footer
+
+``` + +**Key rules:** +- Parent must have explicit height (`h-screen`, `h-full`, or `flex-1` from its parent) +- Fixed elements use `flex-shrink-0` +- Scrollable element uses `flex-1` to fill remaining space +- Scrollable element needs `overflow-auto` or be a `ScrollArea` component + +### Split-Pane Layout (Sidebar + Content) + +Most complex apps use this pattern: + +```tsx +// Full-height split pane with independent scrolling +export function AppShell() { + return ( +
+ {/* Left Sidebar */} +
+
+

Sidebar Header

+
+
+ +
+
+ + {/* Right Content */} +
+
+

Page Header

+
+
+
+ {/* Main content that scrolls */} +
+
+
+
+ ); +} +``` + +**Why this works:** +- Root uses `h-screen overflow-hidden` to constrain total height +- Both panes use `flex flex-col` to stack header + scrollable area +- Headers use `flex-shrink-0` to prevent compression +- Scrollable areas use `flex-1 overflow-auto` to fill remaining space + +### When to Use ScrollArea vs Native Overflow + +**Use native `overflow-auto` (recommended):** +- Full-height scrolling areas (sidebars, main content) +- Simpler implementation, more reliable +- Better browser support and performance +- Mobile-friendly (respects system scroll behavior) +- Works consistently with flexbox layouts + +**Use shadcn `ScrollArea` (advanced):** +- Small contained regions with custom scrollbar styling +- Modals/dialogs with fixed max-height +- When you need precise scrollbar customization +- Note: Can have edge cases with flex-1, prefer native overflow for full-height + +```tsx +{/* Full-height areas - use native overflow (recommended) */} +
+
Sidebar or main content
+
+ +{/* Small contained areas - ScrollArea acceptable */} + +
Fixed height content
+
+``` + +### Common Mistakes to Avoid + +❌ **Don't use calc() for scroll heights:** +```tsx +// BAD: Brittle, breaks on content changes + +``` + +✅ **Do use flexbox:** +```tsx +// GOOD: Flexible, adapts to any layout +
+``` + +❌ **Don't forget parent constraints:** +```tsx +// BAD: flex-1 without parent height does nothing +
+``` + +✅ **Do establish height on parent:** +```tsx +// GOOD: Parent has h-screen +
+
+``` + +❌ **Don't skip overflow-hidden on parent:** +```tsx +// BAD: Can cause layout issues +
+
+``` + +✅ **Do add overflow-hidden to parent:** +```tsx +// GOOD: Prevents flex-1 from growing beyond bounds +
+
+``` + +### Modal with Scrollable Content + +```tsx + + + Modal Title + + +
+ {/* Long scrollable content */} +
+
+ + + +
+``` + +### Debugging Scrolling Issues + +If scrolling doesn't work: + +1. **Check parent height:** Use browser devtools to verify the scrollable element's parent has a constrained height +2. **Verify flex setup:** Ensure `flex flex-col` on parent, `flex-1` on scrollable child +3. **Confirm overflow:** Check if `overflow-auto` or ScrollArea is applied +4. **Look for overflow-hidden:** Parent of scrollable might need `overflow-hidden` to constrain growth + +**Quick diagnostic:** +```tsx +// Add temporary red border to see element bounds +
+``` + +If the red border doesn't have the height you expect, the problem is in the parent flex setup, not the scrolling itself. + +### Protected Routes + +```tsx +// src/routes/_authenticated.tsx +import { createFileRoute, redirect } from '@tanstack/react-router'; +import { useAuthStore } from '@/stores/useAuthStore'; + +export const Route = createFileRoute('/_authenticated')({ + beforeLoad: async () => { + const token = useAuthStore.getState().token; + if (!token) { + throw redirect({ to: '/login' }); + } + }, + component: AppLayout, +}); +``` + +```tsx +// src/routes/_authenticated/dashboard.tsx +export const Route = createFileRoute('/_authenticated/dashboard')({ + component: Dashboard, +}); +``` + +## Navigation Patterns + +### Sidebar Navigation + +```tsx +import { Link } from '@tanstack/react-router'; +import { Home, Users, Settings, FileText } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +const navigation = [ + { name: 'Dashboard', href: '/dashboard', icon: Home }, + { name: 'Users', href: '/users', icon: Users }, + { name: 'Documents', href: '/documents', icon: FileText }, + { name: 'Settings', href: '/settings', icon: Settings }, +]; + +export function Sidebar() { + return ( + + ); +} +``` + +### Hierarchical Sidebar Items + +When displaying hierarchical data (org charts, nested navigation, file trees) in sidebars, use padding-based indentation to prevent text clipping. + +**✅ Correct Pattern:** +```tsx +interface HierarchyItemProps { + person: { name: string; title: string; initials: string }; + level: number; // 0, 1, 2 for depth + isSelected: boolean; +} + +function HierarchyItem({ person, level, isSelected }: HierarchyItemProps) { + const paddingLeft = level === 0 ? 'pl-3' : level === 1 ? 'pl-5' : 'pl-7'; + + return ( + + ); +} +``` + +**Key Rules:** + +❌ **Don't use margin for indentation:** +```tsx + + Page {page} + +
+
+ ); +} +``` + +## Complex Forms + +### Multi-Step Form + +```tsx +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; +import { Button } from '@/components/ui/button'; +import { Progress } from '@/components/ui/progress'; + +const step1Schema = z.object({ + name: z.string().min(2), + email: z.string().email(), +}); + +const step2Schema = z.object({ + company: z.string().min(2), + role: z.string(), +}); + +export function MultiStepForm() { + const [step, setStep] = useState(1); + const [formData, setFormData] = useState({}); + + const schema = step === 1 ? step1Schema : step2Schema; + const form = useForm({ + resolver: zodResolver(schema), + }); + + const onSubmit = (data: any) => { + if (step === 1) { + setFormData({ ...formData, ...data }); + setStep(2); + } else { + // Final submission + const finalData = { ...formData, ...data }; + console.log(finalData); + } + }; + + const progress = (step / 2) * 100; + + return ( +
+ + +
+ {step === 1 && ( + <> + {/* Step 1 fields */} + + + + )} + + {step === 2 && ( + <> + {/* Step 2 fields */} + + + + )} + +
+ {step > 1 && ( + + )} + +
+
+
+ ); +} +``` + +## Performance Optimization + +### Code Splitting by Route + +TanStack Router handles this automatically. Each route is lazy-loaded. + +### Virtual Scrolling for Large Lists + +```tsx +import { useVirtualizer } from '@tanstack/react-virtual'; +import { useRef } from 'react'; + +export function VirtualList({ items }: { items: any[] }) { + const parentRef = useRef(null); + + const virtualizer = useVirtualizer({ + count: items.length, + getScrollElement: () => parentRef.current, + estimateSize: () => 50, + }); + + return ( +
+
+ {virtualizer.getVirtualItems().map((virtualItem) => ( +
+ {items[virtualItem.index].name} +
+ ))} +
+
+ ); +} +``` + +### React Compiler + +Enable for automatic memoization: + +```bash +pnpm add -D babel-plugin-react-compiler +``` + +Configure in Vite: +```typescript +// vite.config.ts +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', {}], + ], + }, + }), + ], +}); +``` + +## Testing Strategy + +### Component Testing + +```tsx +import { render, screen } from '@testing-library/react'; +import { Button } from './button'; + +test('renders button with text', () => { + render(); + expect(screen.getByText('Click me')).toBeInTheDocument(); +}); +``` + +### E2E Testing (Playwright) + +```bash +pnpm add -D @playwright/test +``` + +```typescript +// tests/login.spec.ts +import { test, expect } from '@playwright/test'; + +test('user can log in', async ({ page }) => { + await page.goto('/login'); + await page.fill('[name="email"]', 'user@example.com'); + await page.fill('[name="password"]', 'password'); + await page.click('button[type="submit"]'); + await expect(page).toHaveURL('/dashboard'); +}); +``` + +## Security Considerations + +- Validate all inputs with Zod +- Sanitize user-generated content +- Use HTTPS in production +- Implement CSRF protection +- Set secure cookie flags +- Use environment variables for secrets +- Implement rate limiting +- Regular dependency updates + +## Deployment + +### Environment Variables + +```bash +# .env.production +VITE_API_URL=https://api.production.com +VITE_APP_URL=https://app.production.com +``` + +Access in code: +```typescript +const API_URL = import.meta.env.VITE_API_URL; +``` + +### Build Optimization + +```bash +# Production build +pnpm build + +# Analyze bundle size +pnpm add -D rollup-plugin-visualizer +``` + +## Next Steps + +1. Define application architecture and feature domains +2. Set up Zustand stores for global state +3. Create protected route structure +4. Implement authentication flow +5. Build core navigation (sidebar, command palette) +6. Develop feature modules +7. Add comprehensive error handling +8. Optimize performance (code splitting, caching) +9. Implement testing strategy +10. Deploy to production diff --git a/plugins/spark/skills/spark-app-template/stacks/content-showcase.md b/plugins/spark/skills/spark-app-template/stacks/content-showcase.md index 9e924af..0fbff84 100644 --- a/plugins/spark/skills/spark-app-template/stacks/content-showcase.md +++ b/plugins/spark/skills/spark-app-template/stacks/content-showcase.md @@ -1,452 +1,452 @@ -# Content Showcase Stack - -## Overview - -The content showcase stack is optimized for content-focused applications including marketing sites, portfolios, blogs, documentation sites, and landing pages where typography and reading experience are paramount. - -## When to Use - -- Marketing websites and landing pages -- Portfolio sites -- Blog platforms -- Documentation sites -- Content-heavy applications -- Informational websites - -## Extends Default Stack - -This stack includes ALL packages from `default-webapp.md` PLUS the following additive packages. - -## Additional Packages - -### Content Processing -```bash -pnpm add marked # Markdown to HTML -pnpm add dompurify # Sanitize HTML (security) -``` - -### Additional shadcn Components -```bash -# Content components -pnpm dlx shadcn@latest add separator -pnpm dlx shadcn@latest add breadcrumb -pnpm dlx shadcn@latest add navigation-menu -pnpm dlx shadcn@latest add accordion -``` - -## Design Guidance - -### Typography-First Design - -Content showcases live or die by their typography. The reading experience must be exceptional. - -**Type Scale** (larger than default): -```css -/* Add to index.css */ -h1: 3.5rem (56px), line-height: 1.1, font-weight: 700 -h2: 2.5rem (40px), line-height: 1.2, font-weight: 600 -h3: 2rem (32px), line-height: 1.3, font-weight: 600 -h4: 1.5rem (24px), line-height: 1.4, font-weight: 600 -body: 1.125rem (18px), line-height: 1.7, font-weight: 400 -lead: 1.25rem (20px), line-height: 1.6, font-weight: 400 -``` - -**Line Length**: Optimal reading is 60-75 characters per line -```css -.prose { - max-width: 65ch; -} -``` - -**Vertical Rhythm**: Consistent spacing between elements -```css -/* Spacing scale */ -h1: mb-6 -h2: mt-12 mb-4 -h3: mt-8 mb-3 -p: mb-4 -``` - -### Distinctive Font Pairings - -**Recommended for Content**: - -**Option 1: Editorial** -- Headings: **Playfair Display** (serif, elegant) -- Body: **Source Sans 3** (sans-serif, readable) -- Use: Magazine-style, luxury brands, editorial content - -**Option 2: Modern Technical** -- Headings: **Space Grotesk** (geometric, modern) -- Body: **IBM Plex Sans** (clean, professional) -- Use: Tech companies, startups, modern brands - -**Option 3: Classic** -- Headings: **Newsreader** (serif, traditional) -- Body: **Source Sans 3** (sans-serif) -- Use: Publications, journalism, classic brands - -Update `index.html`: -```html - - -``` - -Update `index.css`: -```css -body { - font-family: 'Source Sans 3', sans-serif; -} - -h1, h2, h3, h4, h5, h6 { - font-family: 'Playfair Display', serif; -} -``` - -### Color for Content - -**Muted, Sophisticated Palette**: -```css -:root { - /* Warm, readable background */ - --background: oklch(0.98 0.005 85); - --foreground: oklch(0.22 0.01 75); - - /* Subtle, elegant primary */ - --primary: oklch(0.40 0.08 240); - --primary-foreground: oklch(0.99 0 0); - - /* Warm accent for links */ - --accent: oklch(0.55 0.12 35); - --accent-foreground: oklch(0.22 0.01 75); - - /* Larger radius for softer feel */ - --radius: 0.75rem; -} -``` - -### Whitespace & Breathing Room - -Content needs generous spacing: -- **Section padding**: py-16 to py-24 (mobile), py-24 to py-32 (desktop) -- **Content width**: max-w-4xl or max-w-5xl centered -- **Grid gaps**: gap-8 to gap-12 -- **Margins**: Generous margins around content blocks - -## Layout Patterns - -### Hero Section - -```tsx -export function Hero() { - return ( -
-
-
-

- Build Beautiful Web Experiences -

-

- A toolkit for creating applications with design and performance - in mind. -

-
- - -
-
-
-
- ); -} -``` - -### Content Grid (Features, Services, etc.) - -```tsx -import { Card, CardContent } from '@/components/ui/card'; - -const features = [ - { - title: 'Fast Performance', - description: 'Built with modern tools for lightning-fast load times.', - icon: Zap - }, - // ... -]; - -export function Features() { - return ( -
-
-
-

Why Choose Us

-

- Everything you need to build exceptional web applications -

-
- -
- {features.map((feature) => ( - - - -

{feature.title}

-

- {feature.description} -

-
-
- ))} -
-
-
- ); -} -``` - -### Long-Form Content (Blog Post, Article) - -```tsx -import { Separator } from '@/components/ui/separator'; - -export function Article({ content }: { content: string }) { - return ( -
-
- {/* Article header */} -
-

Article Title

-
- - - 5 min read -
-
- - {/* Article content */} -
-
-
- ); -} -``` - -## Markdown Processing - -### Convert Markdown to HTML - -```tsx -import { marked } from 'marked'; -import DOMPurify from 'dompurify'; - -// Configure marked for better output -marked.setOptions({ - gfm: true, // GitHub Flavored Markdown - breaks: true, // Convert \n to
-}); - -export function renderMarkdown(markdown: string): string { - const html = marked(markdown); - return DOMPurify.sanitize(html); -} -``` - -### Markdown Component - -```tsx -interface MarkdownProps { - content: string; -} - -export function Markdown({ content }: MarkdownProps) { - const html = renderMarkdown(content); - - return ( -
- ); -} -``` - -## Navigation Patterns - -### Header Navigation - -```tsx -import { NavigationMenu, NavigationMenuItem, NavigationMenuLink, NavigationMenuList } from '@/components/ui/navigation-menu'; -import { Button } from '@/components/ui/button'; - -export function Header() { - return ( -
-
-
- Brand - - - - - Features - - - Pricing - - - Blog - - - -
- -
- - -
-
-
- ); -} -``` - -### Footer - -```tsx -export function Footer() { - return ( -
-
-
-
-

Product

- -
- {/* More columns */} -
- -
-

© 2026 Your Company. All rights reserved.

-
-
-
- ); -} -``` - -## SEO Optimization - -### Meta Tags (in route components) - -```tsx -// src/routes/index.tsx -import { createFileRoute } from '@tanstack/react-router'; -import { Helmet } from 'react-helmet-async'; // Install if needed - -export const Route = createFileRoute('/')({ - component: HomePage, -}); - -function HomePage() { - return ( - <> - - Your App - Tagline - - - - - - - - {/* Page content */} - - ); -} -``` - -## Performance for Content Sites - -### Image Optimization - -```tsx -// Use WebP with fallbacks - - - - Description - -``` - -### Font Loading Strategy - -Already using `display=swap` for optimal font loading. Consider: -```html - - -``` - -### Code Splitting - -Content pages should load instantly: -```tsx -// Lazy load heavy components -const HeavyComponent = lazy(() => import('./HeavyComponent')); - -}> - - -``` - -## Accessibility - -- Use semantic HTML (`
`, `
`, `