Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: "Changelog + Version"

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

# On every push to main: bump cli/package.json (create-page badge) and
# prepend an OpenAI-written Keep-a-Changelog section. Commits directly
# with [changelog][skip ci] so tests and this workflow do not loop.

on:
push:
branches: [main]
workflow_dispatch:

concurrency:
group: changelog-main
cancel-in-progress: false

jobs:
changelog:
name: Update changelog & version
runs-on: ubuntu-latest
timeout-minutes: 10
if: ${{ github.event_name == 'workflow_dispatch' || !contains(github.event.head_commit.message, '[changelog]') }}
permissions:
contents: write

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# Needed so the bot commit triggers deploy hooks that listen to main.
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"

- name: Generate changelog + bump version
id: release
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_MODEL: gpt-4o-mini
BEFORE_SHA: ${{ github.event.before }}
AFTER_SHA: ${{ github.sha }}
run: node scripts/update-changelog.mjs

- name: Commit CHANGELOG.md and cli/package.json
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add CHANGELOG.md cli/package.json
if git diff --staged --quiet; then
echo "No changelog/version changes to commit."
exit 0
fi
git commit -m "docs: release v${{ steps.release.outputs.version }} [changelog][skip ci]"
git push
6 changes: 6 additions & 0 deletions .github/workflows/test-tier3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:

layer1:
name: Layer 1 — Template Unit Tests
if: ${{ github.event_name == 'workflow_dispatch' || (!contains(github.event.head_commit.message, '[changelog]') && !contains(github.event.head_commit.message, '[skip ci]')) }}
runs-on: ubuntu-latest
timeout-minutes: 15

Expand Down Expand Up @@ -141,6 +142,11 @@ jobs:
steps:
- name: Check all jobs passed
run: |
# Bot changelog commits skip the matrix; treat that as a no-op pass.
if [ "${{ needs.layer1.result }}" = "skipped" ]; then
echo "⏭️ Tier 3 skipped (changelog / skip-ci commit)."
exit 0
fi
if [ "${{ needs.layer1.result }}" != "success" ] || [ "${{ needs.layer2.result }}" != "success" ]; then
echo "❌ Release gate FAILED. Not all jobs passed."
exit 1
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Changelog

User-facing changes to FlutterInit (wizard, CLI, scaffolds, and docs that affect builders).
The version on [/create](https://flutterinit.com/create) tracks `cli/package.json` and advances on every push to `main`.

## [1.1.0] - 2026-09-21

Extended UI is now a first-class product story: public update + guide, clearer naming across the wizard and scaffolds, and the create-page version set to **1.1.0**.

### Added
- Blog update and guide for Extended UI (`App*` widgets + optional shadcn_ui)
- Skills lock entry for related agent skills

### Changed
- Product version on `/create` bumped to `1.1.0` via `cli/package.json`
- Renamed scaffold UI surface from FlutterInit-prefixed widgets to the `App*` kit naming
- Wizard copy and schema labels aligned with Extended UI / App kit wording
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Please follow these naming standards for your branches:
- `docs/doc-updates` (Improvements to markdown)
- `perf/optimization` (Performance enhancements)

## Changelog & versioning

Product version lives in `cli/package.json` and is shown on `/create`. On every push to `main`, GitHub Actions bumps that version and prepends an entry to `CHANGELOG.md` (OpenAI-written, committed with `[changelog][skip ci]`).

Do **not** hand-edit version bumps for routine merges — the workflow owns them. Large product stories still belong in `content/blog/updates/` as MDX announcements.

## Development Workflow

We provide a specialized dev loop for template creation that provides "Hot Reload" for your scaffolds.
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,11 @@ FlutterInit ships a built-in blog at [flutterinit.com/blogs](https://flutterinit

| Kind | Purpose |
|------|---------|
| **Updates** | Release notes, announcements, and changelogs |
| **Updates** | Release notes, announcements, and major product stories |
| **Guides** | Deep-dive technical guides for every supported stack combination |

The living product changelog lives at [flutterinit.com/changelog](https://flutterinit.com/changelog) (source: [`CHANGELOG.md`](CHANGELOG.md)). The version badge on [/create](https://flutterinit.com/create) tracks [`cli/package.json`](cli/package.json) and is bumped automatically on every push to `main`.

Every guide shows the exact `stackConfig` it covers (Architecture · State · Backend · Navigation), a "when to choose this stack" recommendation, an interactive file tree of the generated output, and a Table of Contents sidebar.

Blogs content lives under `content/blog/` as `.mdx` files. The file path is the URL slug — no CMS or database required.
Expand Down
140 changes: 140 additions & 0 deletions app/changelog/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import type { Metadata } from "next"
import Link from "next/link"
import Image from "next/image"
import { readFile } from "node:fs/promises"
import path from "node:path"
import { MDXRemote } from "next-mdx-remote/rsc"
import remarkGfm from "remark-gfm"
import rehypeSlug from "rehype-slug"
import { mdxComponents } from "@/app/blogs/components/MDXComponents"
import cliPackage from "@/cli/package.json"
import {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"

export const metadata: Metadata = {
title: "Changelog | FlutterInit",
description:
"Release notes for FlutterInit — wizard, CLI, and scaffold changes. The version on /create advances with every push to main.",
alternates: {
canonical: "https://flutterinit.com/changelog",
},
openGraph: {
title: "Changelog | FlutterInit",
description:
"Release notes for FlutterInit — wizard, CLI, and scaffold changes.",
type: "website",
url: "https://flutterinit.com/changelog",
},
}

const mdxOptions = {
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeSlug],
}

/** Drop the top H1 so the page owns the title. */
function bodyWithoutTitle(markdown: string): string {
return markdown.replace(/^#\s+Changelog\s*\r?\n+/, "").trimStart()
}

// Module-scope read keeps this route prerenderable under Cache Components.
const changelogSource = bodyWithoutTitle(
await readFile(path.join(process.cwd(), "CHANGELOG.md"), "utf8"),
)

export default function ChangelogPage() {
const version = cliPackage.version

return (
<div className="min-h-screen bg-white">
<div className="sticky top-0 z-40 border-b border-zinc-100 bg-white/90 backdrop-blur-md">
<div className="mx-auto flex h-14 max-w-3xl items-center justify-between px-6 md:px-8">
<Link href="/" className="flex items-center gap-2.5">
<Image
src="/logo.svg"
alt="FlutterInit"
width={28}
height={28}
className="h-7 w-7"
/>
<span className="text-sm font-semibold tracking-tight text-zinc-900">
FlutterInit
</span>
</Link>
<nav className="flex items-center gap-3">
<Link
href="/blogs"
className="text-xs font-medium text-zinc-500 transition-colors hover:text-zinc-900"
>
Blog
</Link>
<Link
href="/create"
className="rounded-xl bg-zinc-950 px-4 py-2 text-xs font-semibold text-white transition-colors hover:bg-zinc-800"
>
Generate Project →
</Link>
</nav>
</div>
</div>

<div className="mx-auto max-w-3xl px-6 py-8 md:px-8">
<div className="mb-8">
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/">Home</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage className="font-medium text-zinc-800">
Changelog
</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</div>

<header className="mb-10">
<div className="mb-4 flex flex-wrap items-center gap-3">
<h1 className="text-3xl font-bold tracking-tight text-zinc-900 sm:text-4xl">
Changelog
</h1>
<span className="rounded-md border border-zinc-200 bg-zinc-50 px-2.5 py-1 font-mono text-[11px] font-semibold text-zinc-700">
v{version}
</span>
</div>
<p className="max-w-2xl text-lg leading-relaxed text-zinc-500">
What changed in FlutterInit for builders. The same version appears on{" "}
<Link href="/create" className="font-medium text-zinc-800 underline-offset-4 hover:underline">
/create
</Link>
{" "}and advances automatically on every push to{" "}
<code className="rounded bg-zinc-100 px-1.5 py-0.5 font-mono text-[13px] text-zinc-700">
main
</code>
.
</p>
</header>

<div className="mb-8 h-px bg-zinc-100" />

<article className="prose-custom">
<MDXRemote
source={changelogSource}
components={mdxComponents}
options={{ mdxOptions }}
/>
</article>
</div>
</div>
)
}
6 changes: 6 additions & 0 deletions app/components/landing/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ export function Footer() {
</div>

<div className="flex items-center gap-4">
<Link
href="/changelog"
className="text-sm text-zinc-500 hover:text-zinc-900 transition-colors font-medium"
>
Changelog
</Link>
<Link
href="/blogs"
className="text-sm text-zinc-500 hover:text-zinc-900 transition-colors font-medium"
Expand Down
20 changes: 10 additions & 10 deletions app/components/wizard/PackageInfoPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const PACKAGE_INFO: Record<string, {
},
theme_shadcn: {
title: "shadcn_ui",
description: "Adds the shadcn_ui package plus ShadApp* wrappers and a ShadThemeData bridge. Pick MaterialApp, CupertinoApp, or ShadApp as the default root.",
description: "Adds the shadcn_ui package plus ShadApp wrappers and a ShadThemeData bridge. Pick MaterialApp, CupertinoApp, or ShadApp as the default root.",
packageName: "shadcn_ui",
url: "https://mariuti.com/flutter-shadcn-ui/",
},
Expand All @@ -136,15 +136,15 @@ const PACKAGE_INFO: Record<string, {
},
default_app_material: {
title: "MaterialApp",
description: "Root widget is MaterialApp. shadcn_ui is included and wrapped around it; generated screens use App* widgets by default.",
description: "Root widget is MaterialApp. shadcn_ui is included and wrapped around it; generated screens use App widgets by default.",
},
default_app_cupertino: {
title: "CupertinoApp",
description: "Root widget is CupertinoApp. shadcn_ui is included and wrapped around it; generated screens use App* widgets by default.",
description: "Root widget is CupertinoApp. shadcn_ui is included and wrapped around it; generated screens use widgets by default.",
},
default_app_shad: {
title: "ShadApp",
description: "Uses ShadApp as the theme host and generates feature screens with ShadApp* wrappers by default.",
description: "Uses ShadApp as the theme host and generates feature screens with ShadApp wrappers by default.",
},
appearance_light: {
title: "Light mode",
Expand All @@ -160,29 +160,29 @@ const PACKAGE_INFO: Record<string, {
},
platform_style_adaptive: {
title: "Adaptive platform style",
description: "App* components render Material on Android and Cupertino on iOS/macOS at runtime. Override per widget with the platform parameter or wrap a subtree in AppPlatformScope.",
description: "App components render Material on Android and Cupertino on iOS/macOS at runtime. Override per widget with the platform parameter or wrap a subtree in AppPlatformScope.",
},
platform_style_material: {
title: "Material platform style",
description: "Force every App* component to use Material widgets on all platforms.",
description: "Force every App component to use Material widgets on all platforms.",
},
platform_style_cupertino: {
title: "Cupertino platform style",
description: "Force every App* component to use Cupertino widgets on all platforms. Colors still come from your Material seed ColorScheme so both kits stay in sync.",
description: "Force every App component to use Cupertino widgets on all platforms. Colors still come from your Material seed ColorScheme so both kits stay in sync.",
},
shadcn_ui: {
title: "shadcn/ui for Flutter",
packageName: "shadcn_ui",
description: "Adds the shadcn_ui package plus ShadApp* wrappers and a ShadThemeData bridge built from your design tokens. Requires Flutter SDK >= 3.41.",
description: "Adds the shadcn_ui package plus ShadApp wrappers and a ShadThemeData bridge built from your design tokens. Requires Flutter SDK >= 3.41.",
url: "https://mariuti.com/flutter-shadcn-ui/",
},
ui_kit_app: {
title: "App kit (native)",
description: "Generated feature screens (login, signup, home, onboarding) use the App* adaptive widget kit.",
description: "Generated feature screens (login, signup, home, onboarding) use the App adaptive widget kit.",
},
ui_kit_shadcn: {
title: "shadcn/ui kit",
description: "Generated feature screens use ShadApp* wrappers that mirror the App* API so you can swap kits without rewriting screens.",
description: "Generated feature screens use ShadApp wrappers that mirror the App API so you can swap kits without rewriting screens.",
},
localization_en: {
title: "English Localization",
Expand Down
8 changes: 4 additions & 4 deletions app/components/wizard/steps/ThemeStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const themeChoiceOptions: Array<{
{
value: "shadcn",
label: "shadcn_ui",
description: "shadcn/ui package plus ShadApp* wrappers.",
description: "shadcn/ui package plus ShadApp wrappers.",
},
]

Expand All @@ -96,19 +96,19 @@ const defaultAppOptions: Array<{
value: "material",
radioValue: "default_app_material",
label: "MaterialApp",
description: "Root app is MaterialApp; screens use App* widgets.",
description: "Root app is MaterialApp; screens use App widgets.",
},
{
value: "cupertino",
radioValue: "default_app_cupertino",
label: "CupertinoApp",
description: "Root app is CupertinoApp; screens use App* widgets.",
description: "Root app is CupertinoApp; screens use App widgets.",
},
{
value: "shad",
radioValue: "default_app_shad",
label: "ShadApp",
description: "Root wraps with ShadApp; screens use ShadApp* widgets.",
description: "Root wraps with ShadApp; screens use ShadApp widgets.",
},
]

Expand Down
4 changes: 2 additions & 2 deletions app/lib/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@ export const platformStyleOptions = [
] as const satisfies Array<{ value: PlatformStyle; label: string; description: string }>

export const uiKitOptions = [
{ value: "app", label: "App kit (native)", description: "Generated screens use App* adaptive widgets." },
{ value: "shadcn", label: "shadcn/ui", description: "Generated screens use ShadApp* wrappers." },
{ value: "app", label: "App kit (native)", description: "Generated screens use App adaptive widgets." },
{ value: "shadcn", label: "shadcn/ui", description: "Generated screens use ShadApp wrappers." },
] as const satisfies Array<{ value: UiKit; label: string; description: string }>

const firebaseSchema = z.object({
Expand Down
4 changes: 2 additions & 2 deletions app/lib/generator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ type TemplateContext = ScaffoldConfig & {
}>
/** Opt-in shadcn_ui component layer */
usesShadcn: boolean
/** Feature screens use ShadApp* when true */
/** Feature screens use ShadApp when true */
shadcnDefault: boolean
/** Adaptive / material / cupertino platform style for App* widgets */
/** Adaptive / material / cupertino platform style for App widgets */
platformStyle: "adaptive" | "material" | "cupertino"
}
}
Expand Down
Loading
Loading