diff --git a/README.md b/README.md index 6cd3e9c..1043597 100644 --- a/README.md +++ b/README.md @@ -1,566 +1,348 @@ -# vite-plugin-flatwave-react +# 🌊 vite-plugin-flatwave-react -[![npm version](https://img.shields.io/npm/v/@kamansoft/vite-plugin-flatwave-react.svg)](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) -[![npm downloads](https://img.shields.io/npm/dw/@kamansoft/vite-plugin-flatwave-react.svg)](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) -[![CI](https://github.com/kamansoft/vite-plugin-flatwave-react/actions/workflows/ci.yml/badge.svg)](https://github.com/kamansoft/vite-plugin-flatwave-react/actions/workflows/ci.yml) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) +[![npm version](https://img.shields.io/npm/v/@kamansoft/vite-plugin-flatwave-react?style=flat-square&color=61DAFB)](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) +[![npm downloads](https://img.shields.io/npm/dw/@kamansoft/vite-plugin-flatwave-react?style=flat-square&color=4FC08D)](https://www.npmjs.com/package/@kamansoft/vite-plugin-flatwave-react) +[![CI status](https://img.shields.io/github/actions/workflow/status/kamansoft/vite-plugin-flatwave-react/ci.yml?branch=main&style=flat-square&logo=githubactions)](https://github.com/kamansoft/vite-plugin-flatwave-react/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/github/license/kamansoft/vite-plugin-flatwave-react?style=flat-square&color=F7DF1E)](./LICENSE) +[![Node.js version](https://img.shields.io/node/v/@kamansoft/vite-plugin-flatwave-react?style=flat-square&logo=nodedotjs&color=339933)](https://nodejs.org/en/about/releases/) +[![Discord](https://img.shields.io/badge/chat-discord-7289DA?style=flat-square&logo=discord)](https://discord.gg/vite) -A Vite plugin that turns a directory of Markdown files into a **fully typed, i18n-aware, statically generated React site** — zero runtime dependencies, no MDX, no server required. - -At build time the plugin: - -- Scans `src/content/{locale}/*.md` and parses front-matter with [`gray-matter`](https://github.com/jonschlinkert/gray-matter) -- Validates required fields, duplicate IDs, slugs, and missing locale variants -- Exposes a **virtual module** (`virtual:flatwave/content`) with typed helper functions usable in any React component -- Generates locale-prefixed static HTML pages via `react-dom/server` -- Emits `sitemap.xml`, `robots.txt`, and `route-manifest.json` +> **Turn Markdown into a fully-typed, i18n-ready, static React site — zero runtime, no MDX, no server.** +> +> Works in **any Vite + React project**. Drop it in, point to your content folder, done. --- -## Table of Contents - -1. [Installation](#installation) -2. [Integration](#integration) - - [Adding the Plugin to Vite](#adding-the-plugin-to-vite) - - [Content Directory Layout](#content-directory-layout) - - [Frontmatter Schema](#frontmatter-schema) -3. [Features](#features) - - [Automatic Route Generation](#automatic-route-generation) - - [Virtual Module API](#virtual-module-api) - - [React Hooks](#react-hooks) - - [Static Site Generation (SSG)](#static-site-generation-ssg) - - [SSG Hook Phases](#ssg-hook-phases) - - [Custom Render Strategy](#custom-render-strategy) - - [SEO and Meta Tags](#seo-and-meta-tags) - - [Content Validation](#content-validation) - - [Standalone Validation CLI](#standalone-validation-cli) - - [Language Switcher](#language-switcher) - - [Hot Module Replacement](#hot-module-replacement) -4. [Docker-Based Development](#docker-based-development) -5. [Using the Plugin Before npm Publication](#using-the-plugin-before-npm-publication) -6. [Development Commands](#development-commands) -7. [Releases and Versioning](#releases-and-versioning) -8. [Documentation](#documentation) -9. [Contributing](#contributing) +## ✨ Why Flatwave? + +| Problem | Flatwave Solution | +| ------------------------------------ | ------------------------------------------------------------------------------------------------- | +| MDX locks you into custom components | **Pure Markdown** — use any React component via virtual module | +| i18n is an afterthought | **First-class i18n** — locale routes (`/en/about`, `/es/about`), auto hreflang, language switcher | +| TypeScript support is partial | **Fully typed** — virtual module + React hooks with full IntelliSense | +| SSG requires complex config | **Zero-config SSG** — static HTML at build, deploy to Netlify, Vercel, S3, GitHub Pages, Nginx | +| Content validation is manual | **Built-in validation** — catches missing fields, duplicate IDs, broken links at build time | --- -## Installation +## 🚀 Quick Start (30 seconds) ```bash +# 1. Install npm install @kamansoft/vite-plugin-flatwave-react -``` - -**Peer dependencies** (must be installed separately): - -```bash -npm install vite react react-dom -``` - -**Node.js ≥ 22.0.0** is required. - ---- -## Integration - -### Adding the Plugin to Vite - -```ts -// vite.config.ts +# 2. Add to vite.config.ts +import { flatwaveContent } from '@kamansoft/vite-plugin-flatwave-react'; import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'node:path'; -import { flatwaveContent } from '@kamansoft/vite-plugin-flatwave-react'; export default defineConfig({ plugins: [ react(), flatwaveContent({ - contentDir: path.resolve(__dirname, 'src/content'), // where .md files live - locales: ['es', 'pt'], // all supported locales - defaultLocale: 'es', // must be in locales[] - strictMissingLocales: false, // true → missing locale = build error - sitemap: { - hostname: 'https://example.com', // used in sitemap.xml and robots.txt - }, + contentDir: path.resolve(__dirname, 'src/content'), + locales: ['en', 'es'], + defaultLocale: 'en', }), ], }); -``` -### Content Directory Layout - -The plugin expects one sub-directory per locale inside `contentDir`: - -``` -src/ - content/ - es/ - index.md - about.md - program.md - pt/ - index.md - about.md - program.md -``` - -Each locale must mirror the same set of content IDs. Missing locale variants produce warnings (or errors with `strictMissingLocales: true`). - -### Frontmatter Schema - -Every `.md` file must include these **required fields**: - -```yaml +# 3. Create content +mkdir -p src/content/en +cat > src/content/en/index.md <<'EOF' --- -title: 'About Us' -slug: 'about' # URL segment — becomes /{locale}/about -id: 'about' # groups translations: same id across locales -public: true # false → excluded from routes, sitemap, manifest -description: 'Short description' -canonical: '/es/about' # optional, defaults to /{locale}/{slug} -robots: 'index, follow' -keywords: - - flatwave - - about -# SEO extras -og: - title: 'Custom OG Title' -twitter: - card: 'summary_large_image' -# JSON-LD structured data -jsonLd: - '@context': 'https://schema.org' - '@type': 'WebPage' -# Navigation hints -menu: 'main' -menu_position: 2 -# Any extra keys are preserved in attributes ---- -Markdown body here. GitHub-flavoured Markdown. No MDX in v1. -``` - -**All extra frontmatter keys** not in the baseline list are preserved in `attributes` and accessible via React hooks and the virtual module. - +title: 'Welcome' +slug: '' +id: 'home' +public: true +description: 'My first Flatwave page' --- +# Hello Flatwave! 🌊 -## Features +This is **pure Markdown** — no MDX, no custom components needed. +EOF -### Automatic Route Generation - -Every public `.md` file becomes a locale-prefixed route: - -| File | Route | -| --------------------------- | ------------- | -| `src/content/es/index.md` | `/es/` | -| `src/content/es/about.md` | `/es/about` | -| `src/content/pt/program.md` | `/pt/program` | - -The home page is detected when `slug` is `index` or empty (`/`). +# 4. Run dev server +npm run dev +``` -At build time, the plugin emits one `{locale}/{slug}/index.html` per route, making the output compatible with any static host (Nginx, Netlify, Vercel, S3, GitHub Pages). +Open `http://localhost:5173/en/` — your page is live with hot reload! 🎉 --- -### Virtual Module API - -Import the virtual module anywhere in your app: +## 🎯 Two Ways to Use It -```ts -import { - getContent, - getAllContent, - getRoutes, - getAlternatives, - getLocales, - getDefaultLocale, -} from 'virtual:flatwave/content'; - -// Get one content entry -const aboutEs = getContent('about', 'es'); +### Mode 1: Composable (Recommended for Existing React Apps) -// Get all routes for a locale -const esRoutes = getRoutes('es'); +Use the **virtual module hooks** + **components** in your existing React Router setup: -// Get alternative locale paths for a language switcher -const alternatives = getAlternatives('about', 'es'); -// → { pt: '/pt/about' } +```tsx +// src/pages/[id].tsx +import { getContent, getAlternatives } from 'virtual:flatwave/content'; +import { FlatwaveMDPageComponent } from '@kamansoft/vite-plugin-flatwave-react/react'; +import Layout from '../components/Layout'; -// Get all configured locales -const locales = getLocales(); // ['es', 'pt'] +export default function Page({ params }: { params: { id: string } }) { + const { id } = params; + const locale = import.meta.env.VITE_CURRENT_LOCALE || 'en'; -// Get the default locale -const defaultLocale = getDefaultLocale(); // 'es' -``` + const content = getContent(id, locale); + const alternatives = getAlternatives(id, locale); -**TypeScript declarations** are available via `virtual.d.ts` — add this to your `tsconfig.json`: + if (!content) return
404 - Not Found
; -```json -{ - "compilerOptions": { - "types": ["@kamansoft/vite-plugin-flatwave-react/virtual"] - } + return ( + + + + ); } ``` ---- - -### React Hooks - -The `@kamansoft/vite-plugin-flatwave-react/react` sub-export provides `useMemo`-wrapped React hooks for ergonomic use in components: +**React hooks** for use anywhere in your components: ```tsx import { - useFlatwaveContent, - useFlatwaveRoutes, - useFlatwaveAlternatives, - useFlatwaveLocales, + useFlatwaveContent, // Get single content entry + useFlatwaveRoutes, // Get all routes (optionally filtered by locale) + useFlatwaveAlternatives, // Get locale alternatives for language switcher + useFlatwaveLocales, // Get all configured locales } from '@kamansoft/vite-plugin-flatwave-react/react'; -function PageComponent({ contentId, locale }: { contentId: string; locale: string }) { - const content = useFlatwaveContent(contentId, locale); - const routes = useFlatwaveRoutes(locale); - const alternatives = useFlatwaveAlternatives(contentId, locale); +function BlogPost({ id, locale }) { + const post = useFlatwaveContent(id, locale); + const alternatives = useFlatwaveAlternatives(id, locale); const locales = useFlatwaveLocales(); - if (!content) return

Content not found

; + if (!post) return
Loading...
; return (
-

{content.frontmatter.title as string}

-

{content.body}

+

{post.frontmatter.title}

+
); } ``` -| Hook | Returns | -| -------------------------------------- | ------------------------------------------------ | -| `useFlatwaveContent(id, locale?)` | One content entry or `undefined` | -| `useFlatwaveRoutes(locale?)` | All routes, optionally filtered by locale | -| `useFlatwaveAlternatives(id, locale?)` | `{ locale: path }` map (current locale excluded) | -| `useFlatwaveLocales()` | All configured locale strings | -| `useFlatwaveLocale(locale?)` | Pass-through locale value | +### Mode 2: Integrated (Zero-Config Routing + i18n) ---- - -### Static Site Generation (SSG) - -SSG is **enabled by default**. The plugin renders every public route to a static HTML file at build time using `react-dom/server`: +Let Flatwave handle **routing, language detection, and rendering** automatically: -```ts -flatwaveContent({ - // ... - ssg: { - enabled: true, // default: true - compileMarkdown: { - allowRawHtml: false, // set true to allow raw HTML in markdown - remarkPlugins: [], // add custom remark plugins - rehypePlugins: [], // add custom rehype plugins - }, - }, -}); -``` +```tsx +// src/App.tsx +import { + FlatwaveLanguageRouter, + FlatwaveMDPageComponent, + useFlatwaveRoutes, + useFlatwaveContent, +} from '@kamansoft/vite-plugin-flatwave-react/react'; -Disable SSG and only use the virtual module + React client-side routing: +export function App() { + const routes = useFlatwaveRoutes(); -```ts -ssg: { - enabled: false; + return ( + { + const content = useFlatwaveContent(route.contentId, lang); + return ( + + ); + }} + /> + ); } ``` ---- - -### SSG Hook Phases +**That's it.** You get: -Inject custom behaviour at any point in the rendering pipeline without modifying the plugin core: - -```ts -flatwaveContent({ - // ... - ssg: { - enabled: true, - hooks: { - // Runs before rendering — mutate/augment the render context - beforeRender: async (context) => { - return { ...context, myData: await fetchData(context.route.path) }; - }, - - // Transform markdown before it is compiled to HTML - transformMarkdown: async (markdown, context) => { - return markdown + `\n\n---\n\nBuilt with Flatwave v1.0`; - }, - - // Transform the final HTML after template rendering - transformHtml: async (html, context) => { - const beacon = ``; - return html.replace('', beacon + ''); - }, - - // Side effects after render — logging, auditing, etc. - afterRender: async (html, context) => { - console.log(`[SSG] rendered ${context.route.path} (${html.length} bytes)`); - }, - - // Error recovery — return fallback HTML instead of crashing - onError: async (error, context) => { - return `

Error rendering ${context.route.path}: ${error.message}

`; - }, - }, - }, -}); -``` - -| Hook phase | Signature | Use case | -| ------------------- | -------------------- | ------------------------------------------------ | -| `beforeRender` | `(ctx) → ctx` | Inject auth tokens, locale overrides, async data | -| `transformMarkdown` | `(md, ctx) → md` | Pre-process Markdown before compilation | -| `transformHtml` | `(html, ctx) → html` | Inject analytics, CSP headers, minification | -| `afterRender` | `(html, ctx) → void` | Logging, audit events, side effects | -| `onError` | `(err, ctx) → html` | Return safe fallback HTML on render error | +- Auto locale detection from browser language +- Locale-prefixed routes (`/en/about`, `/es/about`) +- Language switcher component built-in +- SEO meta tags from frontmatter --- -### Custom Render Strategy - -Replace the default `react-dom/server` renderer with your own: - -```ts -import { flatwaveContent } from '@kamansoft/vite-plugin-flatwave-react'; -import type { RenderStrategy, RenderContext } from '@kamansoft/vite-plugin-flatwave-react/ssg'; - -class MyServerRenderer implements RenderStrategy { - async render(context: RenderContext): Promise { - // Custom rendering: micro-frontends, async data, alternative SSR frameworks - return `
${context.contentEntry.body}
`; - } -} +## 📁 Content Structure -export default defineConfig({ - plugins: [ - flatwaveContent({ - // ... - ssg: { - enabled: true, - strategy: new MyServerRenderer(), - }, - }), - ], -}); +``` +src/ +└── content/ + ├── en/ + │ ├── index.md # → /en/ + │ ├── about.md # → /en/about + │ └── blog/ + │ └── hello.md # → /en/blog/hello + └── es/ + ├── index.md # → /es/ + ├── about.md # → /es/about + └── blog/ + └── hello.md # → /es/blog/hello ``` ---- - -### SEO and Meta Tags - -SEO metadata is derived automatically from frontmatter fields. For each route the plugin generates: - -- `` from `title` -- `<meta name="description">` from `description` -- `<meta name="robots">` from `robots` (default: `index, follow`) -- `<link rel="canonical">` from `canonical` (default: `/{locale}/{slug}`) -- `<link rel="alternate" hreflang="…">` for every locale translation -- `<meta property="og:*">` from the `og` object -- `<meta name="twitter:*">` from the `twitter` object -- `<meta property="og:image">` from `image` -- `<script type="application/ld+json">` from `jsonLd` - -All values are properly escaped. No configuration required — it works from frontmatter alone. +**Frontmatter (required fields):** +```yaml --- +title: 'About Us' # Page title → <title>, <h1>, og:title +slug: 'about' # URL segment → /{locale}/about +id: 'about' # Groups translations (same across locales) +public: true # false = hidden from routes, sitemap, manifest +description: 'Short desc' # meta description, og:description +canonical: '/en/about' # Optional, defaults to /{locale}/{slug} +robots: 'index, follow' # Default: index, follow + +# SEO Extras +og: + title: 'Custom OG Title' + image: '/images/og-about.png' +twitter: + card: 'summary_large_image' +jsonLd: + '@context': 'https://schema.org' + '@type': 'WebPage' -### Content Validation - -The plugin validates content at build time (also exposed as a standalone CLI). Validation catches: - -| Rule | Behaviour | -| ----------------------------------------- | -------------------------------------------------------- | -| Missing required fields | **Error** — build fails | -| Duplicate content IDs per locale | **Error** — build fails | -| Duplicate slugs per locale | **Error** — build fails | -| Duplicate menu positions | **Error** — build fails | -| Content ID missing in one or more locales | **Warning** (or error with `strictMissingLocales: true`) | -| No public routes generated | **Warning** | - -```ts -flatwaveContent({ - // ... - requiredFields: ['title', 'slug', 'id', 'public'], // default - strictMissingLocales: false, // default: false -}); -``` +# Navigation +menu: 'main' # 'main' | 'footer' | custom +menu_position: 2 # Sort order in menus +# Any extra keys → preserved in `attributes` +custom_field: 'value' --- - -### Standalone Validation CLI - -Run the same validation the plugin performs at build time — useful in CI pipelines before building the app: - -```bash -npx flatwave-validate \ - --content-dir src/content \ - --locales es,pt \ - --default-locale es \ - --strict-missing # optional: missing locale → error instead of warning - -# Exit code 0 → passed -# Exit code 1 → errors found +Your markdown content here... ``` -| Option | Description | -| --------------------- | --------------------------------------- | -| `--content-dir <dir>` | Path to the content directory | -| `--locales <list>` | Comma-separated locale identifiers | -| `--default-locale` | The primary locale | -| `--strict-missing` | Treat missing locale variants as errors | - --- -### Language Switcher +## ⚙️ Configuration -Use `getAlternatives()` (or `useFlatwaveAlternatives()`) to build a language switcher with zero configuration: +```typescript +flatwaveContent({ + // Required + contentDir: './src/content', // Where .md files live + locales: ['en', 'es', 'pt'], // All supported locales + defaultLocale: 'en', // Must be in locales[] -```tsx -import { getAlternatives } from 'virtual:flatwave/content'; + // Validation + strictMissingLocales: false, // true → missing locale = build error + requiredFields: ['title', 'slug', 'id', 'public'], -function LanguageSwitcher({ - contentId, - currentLocale, -}: { - contentId: string; - currentLocale: string; -}) { - const alternatives = getAlternatives(contentId, currentLocale); + // SSG (enabled by default) + ssg: { + enabled: true, + compileMarkdown: { + allowRawHtml: false, // Allow raw HTML in markdown + remarkPlugins: [], // Custom remark plugins + rehypePlugins: [], // Custom rehype plugins + }, + hooks: { + beforeRender: async (ctx) => { + /* inject data */ + }, + transformMarkdown: async (md, ctx) => { + /* pre-process */ + }, + transformHtml: async (html, ctx) => { + /* post-process */ + }, + afterRender: async (html, ctx) => { + /* side effects */ + }, + onError: async (err, ctx) => { + /* fallback HTML */ + }, + }, + strategy: new DefaultRenderStrategy(), // Or custom RenderStrategy + }, - return ( - <nav aria-label="Language switcher"> - {Object.entries(alternatives).map(([locale, path]) => ( - <a key={locale} href={path}> - {locale.toUpperCase()} - </a> - ))} - </nav> - ); -} -``` + // SEO + sitemap: { + hostname: 'https://mysite.com', // Required for sitemap.xml + }, -`getAlternatives('about', 'es')` returns `{ pt: '/pt/about' }` — all locales except the current one, each pre-computed to the correct route. + // Output + emitRouteManifest: true, // route-manifest.json + emitSitemap: true, // sitemap.xml + emitRobotsTxt: true, // robots.txt +}); +``` --- -### Hot Module Replacement +## 🔄 Migration from MDX / Next.js / Astro -In dev mode (`vite dev`), the plugin watches `.md` files. Any save to a Markdown file triggers a full content index rebuild and hot-reloads the virtual module, so your running app immediately reflects the updated content — no page reload required. +| Feature | MDX / Next.js / Astro | Flatwave | +| --------------- | --------------------- | --------------------------------------- | +| **Markdown** | Standard + JSX | ✅ Standard only | +| **Components** | Import in `.mdx` | ✅ Via virtual module + your components | +| **i18n** | Plugin/config heavy | ✅ Zero-config, locale-first | +| **Types** | Partial / manual | ✅ Full TypeScript from virtual module | +| **SSG** | Framework-dependent | ✅ `react-dom/server` — deploy anywhere | +| **Bundle size** | Includes runtime | ✅ **Zero runtime dependencies** | +| **Validation** | Manual / runtime | ✅ Build-time, fail-fast | --- -## Docker-Based Development - -The `docker/` folder provides a ready-to-use Compose stack. This is the recommended approach to avoid Node.js version conflicts with your host system: - -```bash -# Dev server with hot-reload — http://localhost:8080 -docker compose -f docker/docker-compose.yml up dev - -# Production build -docker compose -f docker/docker-compose.yml up build +## 📚 Documentation -# Serve the built static site via nginx — http://localhost:4173 -docker compose -f docker/docker-compose.yml up static -``` - -See [docs/DEVELOPMENT.md](./docs/DEVELOPMENT.md#docker-development-environment) for full Docker details. +| Guide | Description | +| -------------------------------------------------------- | ---------------------------------------------------------------- | +| 📐 [Architecture](./docs/Architecture.md) | System design, module breakdown, Mermaid diagrams, type system | +| 🛠️ [Development](./docs/DEVELOPMENT.md) | Coding standards, Docker, Husky, Git workflow, local npm linking | +| 🚀 [CI/CD & Release](./docs/ci-cd-release-automation.md) | Semantic-release, OIDC publishing, GitHub Actions pipeline | +| 🔧 [API Reference](./docs/API.md) | Complete TypeScript API for virtual module, hooks, SSG, config | --- -## Using the Plugin Before npm Publication +## 🤝 Contributing -If you want to use an unreleased local build of the plugin in another React project, reference it via a `file:` path dependency: +We welcome contributions! See [CONTRIBUTING.md](./CONTRIBUTING.md). -```json -// your-react-project/package.json -{ - "dependencies": { - "@kamansoft/vite-plugin-flatwave-react": "file:../vite-plugin-flatwave-react/packages/vite-plugin-flatwave-react" - } -} -``` +**Quick checklist for PRs:** -```bash -# 1. Build the plugin first -cd vite-plugin-flatwave-react && npm run build:plugin - -# 2. Install in your project (copies dist/ at install time) -cd your-react-project && npm install -``` - -After any plugin code change, re-run `npm run build:plugin` and `npm install` in your project. - -For `npm link` instructions and more detail, see [docs/DEVELOPMENT.md](./docs/DEVELOPMENT.md#installing-the-package-for-local-development). - ---- - -## Development Commands - -Run these from the **monorepo root**: - -| Command | What it does | -| ------------------------------------------------------- | -------------------------------------------------------- | -| `npm run build:plugin` | Compile `packages/vite-plugin-flatwave-react` → `dist/` | -| `npm run build:example` | Build `examples/basic-react-site` | -| `npm run build` | Both of the above | -| `npm run dev -w @flatwave/example-basic-react-site` | Dev server on port 8080 | -| `npm run preview -w @flatwave/example-basic-react-site` | Preview build on port 4173 | -| `npm run lint` | ESLint across all packages | -| `npm run format` | Prettier writes all files | -| `npm run format:check` | Prettier check (CI mode) | -| `npm run type-check` | TypeScript strict check | -| `npm run test` | Vitest unit + integration | -| `npm run test:e2e` | End-to-end build + serve + assert | -| `npm run validate` | Full CI gate (format + lint + type-check + build + test) | -| `npm run validate:example` | Run `flatwave-validate` CLI against example content | +- [ ] Conventional Commit title (`feat:`, `fix:`, `chore:`, etc.) +- [ ] `npm run validate` passes (format + lint + type-check + build + test) +- [ ] Tests added for new features --- -## Releases and Versioning - -Releases are **fully automated** via [semantic-release](https://github.com/semantic-release/semantic-release). Every PR merged into `main` with a `feat:` or `fix:` title triggers a new npm publish. No tokens stored — uses npm OIDC trusted publishing. +## 📄 License -| PR title starts with | Version bump | -| ------------------------------------- | ----------------------- | -| `feat:` | minor (`1.1.0 → 1.2.0`) | -| `fix:` | patch (`1.2.0 → 1.2.1`) | -| `feat!:` or `BREAKING CHANGE:` footer | major (`1.2.1 → 2.0.0`) | -| `chore:`, `docs:`, `ci:`, etc. | none | +[MIT](./LICENSE) © [KamanaSoft](https://github.com/kamansoft) --- -## Documentation +## 💬 Community & Support -| Document | Description | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- | -| [docs/Architecture.md](./docs/Architecture.md) | System architecture, module breakdown, mermaid diagrams, type system, and glossary | -| [docs/DEVELOPMENT.md](./docs/DEVELOPMENT.md) | Coding standards (SOLID, DRY, TypeScript), linting, Husky, Git workflow, Docker, npm link | -| [docs/ci-cd-release-automation.md](./docs/ci-cd-release-automation.md) | Detailed CI/CD pipeline, semantic-release configuration, OIDC publishing setup | -| [docs/Vite-Plugin-Architecture-for-Markdown-Driven-i18n-Aware-Static-Content-Builders.md](./docs/Vite-Plugin-Architecture-for-Markdown-Driven-i18n-Aware-Static-Content-Builders.md) | Original architecture design reference | +- 🐛 [Issue Tracker](https://github.com/kamansoft/vite-plugin-flatwave-react/issues) — Bug reports & feature requests +- 💡 [Discussions](https://github.com/kamansoft/vite-plugin-flatwave-react/discussions) — Questions, ideas, showcases +- 💬 [Discord](https://discord.gg/vite) — Real-time chat with the Vite community --- -## Contributing - -Contributions are welcome! Please read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening a PR. - -All pull requests must: - -- Use a [Conventional Commits](https://www.conventionalcommits.org/) PR title -- Pass `npm run validate` (format + lint + type-check + build + test) +_Built with ❤️ for React developers who love Markdown and static sites._ -**[→ Read the contribution guide](./CONTRIBUTING.md)** +_If this project helps you, please consider giving it a ⭐ on GitHub!_