mirror of
https://github.com/jimeh/commonflow.org.git
synced 2026-02-19 05:46:40 +00:00
Compare commits
25 Commits
0a74d4eacd
...
1eab53b7ba
| Author | SHA1 | Date | |
|---|---|---|---|
|
1eab53b7ba
|
|||
|
4ff9b012ad
|
|||
|
8205cb3690
|
|||
|
d2efcb01ba
|
|||
|
9f1af55602
|
|||
|
88a8ba2f28
|
|||
|
e86b0de9fa
|
|||
|
230e76b2d5
|
|||
|
a7325d2331
|
|||
|
20b1507c2b
|
|||
|
da9171686d
|
|||
|
8c91e2028a
|
|||
|
f47ea792aa
|
|||
|
d55ead82d7
|
|||
|
7d06d18ccb
|
|||
|
4722094f0c
|
|||
|
b22cf35953
|
|||
|
1828ae6353
|
|||
|
7c5c7691c3
|
|||
|
208219ca2c
|
|||
|
f1fa264ed7
|
|||
|
4fadbd111a
|
|||
|
de472c82a2
|
|||
|
f5818933c7
|
|||
|
69ea77d236
|
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
||||
docs/
|
||||
.astro/
|
||||
node_modules/
|
||||
bun.lock
|
||||
31
CLAUDE.md
31
CLAUDE.md
@@ -27,6 +27,16 @@ bun run build
|
||||
# Preview built site
|
||||
bun run preview
|
||||
|
||||
# Type checking
|
||||
bun run check
|
||||
|
||||
# Linting
|
||||
bun run lint
|
||||
|
||||
# Formatting
|
||||
bun run format
|
||||
bun run format:check
|
||||
|
||||
# Update specs from upstream (fetches from github.com/jimeh/common-flow)
|
||||
bun run update
|
||||
```
|
||||
@@ -37,6 +47,7 @@ The site is built to `docs/` for GitHub Pages hosting.
|
||||
|
||||
- **Astro 5.x** static site generator
|
||||
- **Tailwind CSS 4.x** for styling with dark mode support
|
||||
- **astro-icon** with Heroicons and Simple Icons for icons
|
||||
- **Content Collections** for spec markdown files
|
||||
- **TypeScript** throughout
|
||||
- **Bun** as JavaScript runtime and package manager (managed via mise)
|
||||
@@ -45,9 +56,25 @@ The site is built to `docs/` for GitHub Pages hosting.
|
||||
|
||||
- `src/config.ts` - Site configuration with version list
|
||||
- `src/content.config.ts` - Astro content collection definition
|
||||
- `src/layouts/Default.astro` - Main layout with sidebar
|
||||
- `src/components/` - Sidebar, MenuToggle, ThemeToggle components
|
||||
- `src/layouts/BaseLayout.astro` - Base layout with head, meta tags, theme scripts
|
||||
- `src/layouts/SpecLayout.astro` - Spec page layout composing all sections
|
||||
- `src/components/` - UI components:
|
||||
- `Header.astro` - Site header with navigation
|
||||
- `Footer.astro` - Site footer
|
||||
- `Hero.astro` - Landing page hero section
|
||||
- `AboutSection.astro` - About Common-Flow section
|
||||
- `FAQSection.astro` - FAQ section
|
||||
- `SectionHeader.astro` - Reusable section header (title + subtitle)
|
||||
- `SpecSection.astro` - Spec section with terminology and specification
|
||||
- `SpecSidebar.astro` - Spec page table of contents sidebar
|
||||
- `TocLink.astro` - Reusable TOC link component
|
||||
- `ThemeToggle.astro` - Dark/light mode toggle
|
||||
- `VersionSelector.astro` - Spec version dropdown
|
||||
- `src/scripts/activeSectionTracker.ts` - Shared scroll-based active section tracking
|
||||
- `src/pages/index.astro` - Landing page
|
||||
- `src/pages/404.astro` - 404 error page
|
||||
- `src/pages/spec/[version].astro` - Dynamic route for spec versions
|
||||
- `src/utils/parseSpecContent.ts` - Markdown parsing utilities
|
||||
- `src/content/spec/*.md` - Versioned spec documents
|
||||
- `public/spec/*.svg` - SVG diagrams for each version
|
||||
- `scripts/update-specs.ts` - Fetches specs from GitHub
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { defineConfig } from "astro/config";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import sitemap from "@astrojs/sitemap";
|
||||
import icon from "astro-icon";
|
||||
|
||||
export default defineConfig({
|
||||
site: "https://commonflow.org",
|
||||
outDir: "./docs",
|
||||
integrations: [sitemap()],
|
||||
integrations: [sitemap(), icon()],
|
||||
vite: {
|
||||
plugins: [tailwindcss()],
|
||||
},
|
||||
|
||||
545
bun.lock
545
bun.lock
@@ -5,26 +5,47 @@
|
||||
"": {
|
||||
"name": "commonflow-org",
|
||||
"dependencies": {
|
||||
"@astrojs/sitemap": "^3.2.1",
|
||||
"astro": "^5.1.1",
|
||||
"@astrojs/sitemap": "^3.6.1",
|
||||
"@fontsource-variable/bricolage-grotesque": "^5.2.10",
|
||||
"@fontsource-variable/dm-sans": "^5.2.8",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
"@iconify-json/heroicons": "^1.2.3",
|
||||
"@iconify-json/simple-icons": "^1.2.65",
|
||||
"astro": "^5.16.8",
|
||||
"astro-icon": "^1.1.5",
|
||||
"rehype-stringify": "^10.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-rehype": "^11.1.2",
|
||||
"unified": "^11.0.5",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tailwindcss/vite": "^4.0.0",
|
||||
"tailwindcss": "^4.0.0",
|
||||
"typescript": "^5.7.2",
|
||||
"@astrojs/check": "^0.9.6",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-astro": "^1.5.0",
|
||||
"prettier": "^3.7.4",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.52.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
|
||||
|
||||
"@antfu/utils": ["@antfu/utils@8.1.1", "", {}, "sha512-Mex9nXf9vR6AhcXmMrlz/HVgYYZpVGJ6YlPgwl7UnaFpnshXs6EK/oa5Gpf3CzENMjkvEx2tQtntGnb7UtSTOQ=="],
|
||||
|
||||
"@astrojs/check": ["@astrojs/check@0.9.6", "", { "dependencies": { "@astrojs/language-server": "^2.16.1", "chokidar": "^4.0.1", "kleur": "^4.1.5", "yargs": "^17.7.2" }, "peerDependencies": { "typescript": "^5.0.0" }, "bin": { "astro-check": "bin/astro-check.js" } }, "sha512-jlaEu5SxvSgmfGIFfNgcn5/f+29H61NJzEMfAZ82Xopr4XBchXB1GVlcJsE+elUlsYSbXlptZLX+JMG3b/wZEA=="],
|
||||
|
||||
"@astrojs/compiler": ["@astrojs/compiler@2.13.0", "", {}, "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw=="],
|
||||
|
||||
"@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.5", "", {}, "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA=="],
|
||||
|
||||
"@astrojs/language-server": ["@astrojs/language-server@2.16.2", "", { "dependencies": { "@astrojs/compiler": "^2.10.3", "@astrojs/yaml2ts": "^0.2.2", "@jridgewell/sourcemap-codec": "^1.4.15", "@volar/kit": "~2.4.23", "@volar/language-core": "~2.4.23", "@volar/language-server": "~2.4.23", "@volar/language-service": "~2.4.23", "fast-glob": "^3.2.12", "muggle-string": "^0.4.1", "volar-service-css": "0.0.67", "volar-service-emmet": "0.0.67", "volar-service-html": "0.0.67", "volar-service-prettier": "0.0.67", "volar-service-typescript": "0.0.67", "volar-service-typescript-twoslash-queries": "0.0.67", "volar-service-yaml": "0.0.67", "vscode-html-languageservice": "^5.5.2", "vscode-uri": "^3.1.0" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "bin/nodeServer.js" } }, "sha512-J3hVx/mFi3FwEzKf8ExYXQNERogD6RXswtbU+TyrxoXRBiQoBO5ooo7/lRWJ+rlUKUd7+rziMPI9jYB7TRlh0w=="],
|
||||
|
||||
"@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.10", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.5", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.19.0", "smol-toml": "^1.5.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A=="],
|
||||
|
||||
"@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
|
||||
@@ -33,6 +54,8 @@
|
||||
|
||||
"@astrojs/telemetry": ["@astrojs/telemetry@3.3.0", "", { "dependencies": { "ci-info": "^4.2.0", "debug": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", "is-docker": "^3.0.0", "is-wsl": "^3.1.0", "which-pm-runs": "^1.1.0" } }, "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ=="],
|
||||
|
||||
"@astrojs/yaml2ts": ["@astrojs/yaml2ts@0.2.2", "", { "dependencies": { "yaml": "^2.5.0" } }, "sha512-GOfvSr5Nqy2z5XiwqTouBBpy5FyI6DEe+/g/Mk5am9SjILN1S5fOEvYK0GuWHg98yS/dobP4m8qyqw/URW35fQ=="],
|
||||
|
||||
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
|
||||
|
||||
"@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
|
||||
@@ -43,6 +66,20 @@
|
||||
|
||||
"@capsizecss/unpack": ["@capsizecss/unpack@4.0.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA=="],
|
||||
|
||||
"@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="],
|
||||
|
||||
"@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="],
|
||||
|
||||
"@emmetio/css-parser": ["@emmetio/css-parser@0.4.1", "", { "dependencies": { "@emmetio/stream-reader": "^2.2.0", "@emmetio/stream-reader-utils": "^0.1.0" } }, "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ=="],
|
||||
|
||||
"@emmetio/html-matcher": ["@emmetio/html-matcher@1.3.0", "", { "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ=="],
|
||||
|
||||
"@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="],
|
||||
|
||||
"@emmetio/stream-reader": ["@emmetio/stream-reader@2.2.0", "", {}, "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="],
|
||||
|
||||
"@emmetio/stream-reader-utils": ["@emmetio/stream-reader-utils@0.1.0", "", {}, "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
|
||||
@@ -97,6 +134,48 @@
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
|
||||
|
||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
|
||||
|
||||
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
|
||||
|
||||
"@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="],
|
||||
|
||||
"@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
|
||||
|
||||
"@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
|
||||
|
||||
"@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="],
|
||||
|
||||
"@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="],
|
||||
|
||||
"@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
|
||||
|
||||
"@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
|
||||
|
||||
"@fontsource-variable/bricolage-grotesque": ["@fontsource-variable/bricolage-grotesque@5.2.10", "", {}, "sha512-5EDsCqgGpKVcJWE4sg9ydli+t5WM97mISYw5lla/Ev4z71FwXh1oN0YUU8xjkRW9+wBCGD9R+ntAvI8G4bUFJg=="],
|
||||
|
||||
"@fontsource-variable/dm-sans": ["@fontsource-variable/dm-sans@5.2.8", "", {}, "sha512-AxkvMTvNWgfrmlyjiV05vlHYJa+nRQCf1EfvIrQAPBpFJW0O9VTz7oAFr9S3lvbWdmnFoBk7yFqQL86u64nl2g=="],
|
||||
|
||||
"@fontsource-variable/jetbrains-mono": ["@fontsource-variable/jetbrains-mono@5.2.8", "", {}, "sha512-WBA9elru6Jdp5df2mES55wuOO0WIrn3kpXnI4+W2ek5u3ZgLS9XS4gmIlcQhiZOWEKl95meYdvK7xI+ETLCq/Q=="],
|
||||
|
||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||
|
||||
"@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="],
|
||||
|
||||
"@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="],
|
||||
|
||||
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
||||
|
||||
"@iconify-json/heroicons": ["@iconify-json/heroicons@1.2.3", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-n+vmCEgTesRsOpp5AB5ILB6srsgsYK+bieoQBNlafvoEhjVXLq8nIGN4B0v/s4DUfa0dOrjwE/cKJgIKdJXOEg=="],
|
||||
|
||||
"@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.65", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-v/O0UeqrDz6ASuRVE5g2Puo5aWyej4M/CxX6WYDBARgswwxK0mp3VQbGgPFEAAUU9QN02IjTgjMuO021gpWf2w=="],
|
||||
|
||||
"@iconify/tools": ["@iconify/tools@4.2.0", "", { "dependencies": { "@iconify/types": "^2.0.0", "@iconify/utils": "^2.3.0", "cheerio": "^1.1.2", "domhandler": "^5.0.3", "extract-zip": "^2.0.1", "local-pkg": "^1.1.2", "pathe": "^2.0.3", "svgo": "^3.3.2", "tar": "^7.5.2" } }, "sha512-WRxPva/ipxYkqZd1+CkEAQmd86dQmrwH0vwK89gmp2Kh2WyyVw57XbPng0NehP3x4V1LzLsXUneP1uMfTMZmUA=="],
|
||||
|
||||
"@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="],
|
||||
|
||||
"@iconify/utils": ["@iconify/utils@2.3.0", "", { "dependencies": { "@antfu/install-pkg": "^1.0.0", "@antfu/utils": "^8.1.0", "@iconify/types": "^2.0.0", "debug": "^4.4.0", "globals": "^15.14.0", "kolorist": "^1.8.0", "local-pkg": "^1.0.0", "mlly": "^1.7.4" } }, "sha512-GmQ78prtwYW6EtzXRU1rY+KwOKfz32PD7iJh6Iyqw68GiKuoZ2A6pRtzWONz5VQJbp50mEjXh/7NkumtrAgRKA=="],
|
||||
|
||||
"@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="],
|
||||
|
||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="],
|
||||
@@ -147,6 +226,8 @@
|
||||
|
||||
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="],
|
||||
|
||||
"@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
|
||||
@@ -157,8 +238,16 @@
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
||||
|
||||
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
||||
|
||||
"@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="],
|
||||
|
||||
"@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="],
|
||||
|
||||
"@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.1", "", { "os": "android", "cpu": "arm" }, "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg=="],
|
||||
@@ -257,12 +346,16 @@
|
||||
|
||||
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="],
|
||||
|
||||
"@trysound/sax": ["@trysound/sax@0.2.0", "", {}, "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="],
|
||||
|
||||
"@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="],
|
||||
|
||||
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
||||
|
||||
"@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="],
|
||||
|
||||
"@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="],
|
||||
|
||||
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
|
||||
|
||||
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
|
||||
@@ -275,15 +368,59 @@
|
||||
|
||||
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
|
||||
|
||||
"@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
|
||||
|
||||
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.52.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.52.0", "@typescript-eslint/type-utils": "8.52.0", "@typescript-eslint/utils": "8.52.0", "@typescript-eslint/visitor-keys": "8.52.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.52.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-okqtOgqu2qmZJ5iN4TWlgfF171dZmx2FzdOv2K/ixL2LZWDStL8+JgQerI2sa8eAEfoydG9+0V96m7V+P8yE1Q=="],
|
||||
|
||||
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.52.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.52.0", "@typescript-eslint/types": "8.52.0", "@typescript-eslint/typescript-estree": "8.52.0", "@typescript-eslint/visitor-keys": "8.52.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-iIACsx8pxRnguSYhHiMn2PvhvfpopO9FXHyn1mG5txZIsAaB6F0KwbFnUQN3KCiG3Jcuad/Cao2FAs1Wp7vAyg=="],
|
||||
|
||||
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.52.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.52.0", "@typescript-eslint/types": "^8.52.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-xD0MfdSdEmeFa3OmVqonHi+Cciab96ls1UhIF/qX/O/gPu5KXD0bY9lu33jj04fjzrXHcuvjBcBC+D3SNSadaw=="],
|
||||
|
||||
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.52.0", "", { "dependencies": { "@typescript-eslint/types": "8.52.0", "@typescript-eslint/visitor-keys": "8.52.0" } }, "sha512-ixxqmmCcc1Nf8S0mS0TkJ/3LKcC8mruYJPOU6Ia2F/zUUR4pApW7LzrpU3JmtePbRUTes9bEqRc1Gg4iyRnDzA=="],
|
||||
|
||||
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.52.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-jl+8fzr/SdzdxWJznq5nvoI7qn2tNYV/ZBAEcaFMVXf+K6jmXvAFrgo/+5rxgnL152f//pDEAYAhhBAZGrVfwg=="],
|
||||
|
||||
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.52.0", "", { "dependencies": { "@typescript-eslint/types": "8.52.0", "@typescript-eslint/typescript-estree": "8.52.0", "@typescript-eslint/utils": "8.52.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-JD3wKBRWglYRQkAtsyGz1AewDu3mTc7NtRjR/ceTyGoPqmdS5oCdx/oZMWD5Zuqmo6/MpsYs0wp6axNt88/2EQ=="],
|
||||
|
||||
"@typescript-eslint/types": ["@typescript-eslint/types@8.52.0", "", {}, "sha512-LWQV1V4q9V4cT4H5JCIx3481iIFxH1UkVk+ZkGGAV1ZGcjGI9IoFOfg3O6ywz8QqCDEp7Inlg6kovMofsNRaGg=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.52.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.52.0", "@typescript-eslint/tsconfig-utils": "8.52.0", "@typescript-eslint/types": "8.52.0", "@typescript-eslint/visitor-keys": "8.52.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-XP3LClsCc0FsTK5/frGjolyADTh3QmsLp6nKd476xNI9CsSsLnmn4f0jrzNoAulmxlmNIpeXuHYeEQv61Q6qeQ=="],
|
||||
|
||||
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.52.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.52.0", "@typescript-eslint/types": "8.52.0", "@typescript-eslint/typescript-estree": "8.52.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-wYndVMWkweqHpEpwPhwqE2lnD2DxC6WVLupU/DOt/0/v+/+iQbbzO3jOHjmBMnhu0DgLULvOaU4h4pwHYi2oRQ=="],
|
||||
|
||||
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.52.0", "", { "dependencies": { "@typescript-eslint/types": "8.52.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ink3/Zofus34nmBsPjow63FP5M7IGff0RKAgqR6+CFpdk22M7aLwC9gOcLGYqr7MczLPzZVERW9hRog3O4n1sQ=="],
|
||||
|
||||
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="],
|
||||
|
||||
"@volar/kit": ["@volar/kit@2.4.27", "", { "dependencies": { "@volar/language-service": "2.4.27", "@volar/typescript": "2.4.27", "typesafe-path": "^0.2.2", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "typescript": "*" } }, "sha512-ilZoQDMLzqmSsImJRWx4YiZ4FcvvPrPnFVmL6hSsIWB6Bn3qc7k88J9yP32dagrs5Y8EXIlvvD/mAFaiuEOACQ=="],
|
||||
|
||||
"@volar/language-core": ["@volar/language-core@2.4.27", "", { "dependencies": { "@volar/source-map": "2.4.27" } }, "sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ=="],
|
||||
|
||||
"@volar/language-server": ["@volar/language-server@2.4.27", "", { "dependencies": { "@volar/language-core": "2.4.27", "@volar/language-service": "2.4.27", "@volar/typescript": "2.4.27", "path-browserify": "^1.0.1", "request-light": "^0.7.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-SymGNkErcHg8GjiG65iQN8sLkhqu1pwKhFySmxeBuYq5xFYagKBW36eiNITXQTdvT0tutI1GXcXdq/FdE/IyjA=="],
|
||||
|
||||
"@volar/language-service": ["@volar/language-service@2.4.27", "", { "dependencies": { "@volar/language-core": "2.4.27", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-SxKZ8yLhpWa7Y5e/RDxtNfm7j7xsXp/uf2urijXEffRNpPSmVdfzQrFFy5d7l8PNpZy+bHg+yakmqBPjQN+MOw=="],
|
||||
|
||||
"@volar/source-map": ["@volar/source-map@2.4.27", "", {}, "sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg=="],
|
||||
|
||||
"@volar/typescript": ["@volar/typescript@2.4.27", "", { "dependencies": { "@volar/language-core": "2.4.27", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg=="],
|
||||
|
||||
"@vscode/emmet-helper": ["@vscode/emmet-helper@2.11.0", "", { "dependencies": { "emmet": "^2.4.3", "jsonc-parser": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.15.1", "vscode-uri": "^3.0.8" } }, "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw=="],
|
||||
|
||||
"@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="],
|
||||
|
||||
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
|
||||
|
||||
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
|
||||
|
||||
"ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="],
|
||||
|
||||
"ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="],
|
||||
|
||||
"ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||
|
||||
@@ -297,21 +434,37 @@
|
||||
|
||||
"astro": ["astro@5.16.8", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.5", "@astrojs/markdown-remark": "6.3.10", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^4.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.1.1", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.6.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.4.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.20.0", "smol-toml": "^1.6.0", "svgo": "^4.0.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.7.1", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.3", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.25.1", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-gzZE+epuCrNuxOa8/F1dzkllDOFvxWhGeobQKeBRIAef5sUpUKMHZo/8clse+02rYnKJCgwXBgjW4uTu9mqUUw=="],
|
||||
|
||||
"astro-eslint-parser": ["astro-eslint-parser@1.2.2", "", { "dependencies": { "@astrojs/compiler": "^2.0.0", "@typescript-eslint/scope-manager": "^7.0.0 || ^8.0.0", "@typescript-eslint/types": "^7.0.0 || ^8.0.0", "astrojs-compiler-sync": "^1.0.0", "debug": "^4.3.4", "entities": "^6.0.0", "eslint-scope": "^8.0.1", "eslint-visitor-keys": "^4.0.0", "espree": "^10.0.0", "fast-glob": "^3.3.3", "is-glob": "^4.0.3", "semver": "^7.3.8" } }, "sha512-JepyLROIad6f44uyqMF6HKE2QbunNzp3mYKRcPoDGt0QkxXmH222FAFC64WTyQu2Kg8NNEXHTN/sWuUId9sSxw=="],
|
||||
|
||||
"astro-icon": ["astro-icon@1.1.5", "", { "dependencies": { "@iconify/tools": "^4.0.5", "@iconify/types": "^2.0.0", "@iconify/utils": "^2.1.30" } }, "sha512-CJYS5nWOw9jz4RpGWmzNQY7D0y2ZZacH7atL2K9DeJXJVaz7/5WrxeyIxO8KASk1jCM96Q4LjRx/F3R+InjJrw=="],
|
||||
|
||||
"astrojs-compiler-sync": ["astrojs-compiler-sync@1.1.1", "", { "dependencies": { "synckit": "^0.11.0" }, "peerDependencies": { "@astrojs/compiler": ">=0.27.0" } }, "sha512-0mKvB9sDQRIZPsEJadw6OaFbGJ92cJPPR++ICca9XEyiUAZqgVuk25jNmzHPT0KF80rI94trSZrUR5iHFXGGOQ=="],
|
||||
|
||||
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
|
||||
|
||||
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"base-64": ["base-64@1.0.0", "", {}, "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg=="],
|
||||
|
||||
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
|
||||
|
||||
"boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
|
||||
|
||||
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
|
||||
|
||||
"camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
|
||||
|
||||
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
|
||||
|
||||
"character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="],
|
||||
|
||||
@@ -319,24 +472,42 @@
|
||||
|
||||
"character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="],
|
||||
|
||||
"cheerio": ["cheerio@1.1.2", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.12.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg=="],
|
||||
|
||||
"cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="],
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||
|
||||
"ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="],
|
||||
|
||||
"cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
|
||||
|
||||
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
|
||||
|
||||
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="],
|
||||
|
||||
"commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="],
|
||||
|
||||
"common-ancestor-path": ["common-ancestor-path@1.0.1", "", {}, "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="],
|
||||
|
||||
"cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
|
||||
|
||||
"cookie-es": ["cookie-es@1.2.2", "", {}, "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"crossws": ["crossws@0.3.5", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA=="],
|
||||
|
||||
"css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
|
||||
@@ -353,6 +524,8 @@
|
||||
|
||||
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
|
||||
|
||||
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
|
||||
|
||||
"defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="],
|
||||
|
||||
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
|
||||
@@ -381,7 +554,13 @@
|
||||
|
||||
"dset": ["dset@3.1.4", "", {}, "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
"emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="],
|
||||
|
||||
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
|
||||
"encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="],
|
||||
|
||||
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
||||
|
||||
"enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="],
|
||||
|
||||
@@ -391,16 +570,66 @@
|
||||
|
||||
"esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
"escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
|
||||
|
||||
"eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="],
|
||||
|
||||
"eslint-compat-utils": ["eslint-compat-utils@0.6.5", "", { "dependencies": { "semver": "^7.5.4" }, "peerDependencies": { "eslint": ">=6.0.0" } }, "sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ=="],
|
||||
|
||||
"eslint-plugin-astro": ["eslint-plugin-astro@1.5.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@jridgewell/sourcemap-codec": "^1.4.14", "@typescript-eslint/types": "^7.7.1 || ^8", "astro-eslint-parser": "^1.0.2", "eslint-compat-utils": "^0.6.0", "globals": "^16.0.0", "postcss": "^8.4.14", "postcss-selector-parser": "^7.0.0" }, "peerDependencies": { "eslint": ">=8.57.0" } }, "sha512-IWy4kY3DKTJxd7g652zIWpBGFuxw7NIIt16kyqc8BlhnIKvI8yGJj+Maua0DiNYED3F/D8AmzoTTTA6A95WX9g=="],
|
||||
|
||||
"eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
|
||||
|
||||
"eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
|
||||
|
||||
"espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
|
||||
|
||||
"esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="],
|
||||
|
||||
"esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="],
|
||||
|
||||
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
||||
|
||||
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
|
||||
|
||||
"exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="],
|
||||
|
||||
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
||||
|
||||
"extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
||||
|
||||
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
||||
|
||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||
|
||||
"fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
|
||||
|
||||
"fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
|
||||
|
||||
"fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
||||
|
||||
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
||||
|
||||
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
|
||||
|
||||
"flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="],
|
||||
|
||||
"fontace": ["fontace@0.4.0", "", { "dependencies": { "fontkitten": "^1.0.0" } }, "sha512-moThBCItUe2bjZip5PF/iZClpKHGLwMvR79Kp8XpGRBrvoRSnySN4VcILdv3/MJzbhvUA5WeiUXF5o538m5fvg=="],
|
||||
@@ -409,14 +638,24 @@
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
|
||||
"get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="],
|
||||
|
||||
"get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
||||
|
||||
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||
|
||||
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
||||
|
||||
"globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="],
|
||||
|
||||
"graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
|
||||
|
||||
"h3": ["h3@1.15.4", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.5", "defu": "^6.1.4", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.2", "radix3": "^1.1.2", "ufo": "^1.6.1", "uncrypto": "^0.1.3" } }, "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ=="],
|
||||
|
||||
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
|
||||
|
||||
"hast-util-from-html": ["hast-util-from-html@2.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "devlop": "^1.1.0", "hast-util-from-parse5": "^8.0.0", "parse5": "^7.0.0", "vfile": "^6.0.0", "vfile-message": "^4.0.0" } }, "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw=="],
|
||||
|
||||
"hast-util-from-parse5": ["hast-util-from-parse5@8.0.3", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "devlop": "^1.0.0", "hastscript": "^9.0.0", "property-information": "^7.0.0", "vfile": "^6.0.0", "vfile-location": "^5.0.0", "web-namespaces": "^2.0.0" } }, "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg=="],
|
||||
@@ -441,27 +680,59 @@
|
||||
|
||||
"html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="],
|
||||
|
||||
"htmlparser2": ["htmlparser2@10.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.1", "entities": "^6.0.0" } }, "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g=="],
|
||||
|
||||
"http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],
|
||||
|
||||
"ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="],
|
||||
|
||||
"import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="],
|
||||
|
||||
"import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="],
|
||||
|
||||
"imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="],
|
||||
|
||||
"iron-webcrypto": ["iron-webcrypto@1.2.1", "", {}, "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg=="],
|
||||
|
||||
"is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="],
|
||||
|
||||
"is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
|
||||
|
||||
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||
|
||||
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
||||
|
||||
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
||||
|
||||
"kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
||||
|
||||
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
||||
|
||||
"json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="],
|
||||
|
||||
"jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="],
|
||||
|
||||
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
||||
|
||||
"kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
|
||||
|
||||
"kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="],
|
||||
|
||||
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
||||
|
||||
"lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="],
|
||||
|
||||
@@ -487,6 +758,14 @@
|
||||
|
||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
|
||||
|
||||
"local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="],
|
||||
|
||||
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
||||
|
||||
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
|
||||
|
||||
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
@@ -525,6 +804,8 @@
|
||||
|
||||
"mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="],
|
||||
|
||||
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
||||
|
||||
"micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="],
|
||||
|
||||
"micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="],
|
||||
@@ -581,12 +862,26 @@
|
||||
|
||||
"micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="],
|
||||
|
||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||
|
||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||
|
||||
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||
|
||||
"minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="],
|
||||
|
||||
"mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="],
|
||||
|
||||
"mrmime": ["mrmime@2.0.1", "", {}, "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
||||
|
||||
"neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="],
|
||||
|
||||
"nlcst-to-string": ["nlcst-to-string@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0" } }, "sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA=="],
|
||||
@@ -603,38 +898,76 @@
|
||||
|
||||
"ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="],
|
||||
|
||||
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||
|
||||
"oniguruma-parser": ["oniguruma-parser@0.12.1", "", {}, "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w=="],
|
||||
|
||||
"oniguruma-to-es": ["oniguruma-to-es@4.3.4", "", { "dependencies": { "oniguruma-parser": "^0.12.1", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
|
||||
"p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="],
|
||||
|
||||
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
||||
|
||||
"p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="],
|
||||
|
||||
"p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="],
|
||||
|
||||
"package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="],
|
||||
|
||||
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
|
||||
|
||||
"parse-latin": ["parse-latin@7.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "@types/unist": "^3.0.0", "nlcst-to-string": "^4.0.0", "unist-util-modify-children": "^4.0.0", "unist-util-visit-children": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ=="],
|
||||
|
||||
"parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="],
|
||||
|
||||
"parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="],
|
||||
|
||||
"parse5-parser-stream": ["parse5-parser-stream@7.1.2", "", { "dependencies": { "parse5": "^7.0.0" } }, "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow=="],
|
||||
|
||||
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
|
||||
|
||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
||||
|
||||
"pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="],
|
||||
|
||||
"piccolore": ["piccolore@0.1.3", "", {}, "sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw=="],
|
||||
|
||||
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
||||
|
||||
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
||||
|
||||
"pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="],
|
||||
|
||||
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
|
||||
|
||||
"postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="],
|
||||
|
||||
"prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="],
|
||||
|
||||
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
|
||||
|
||||
"prettier-plugin-astro": ["prettier-plugin-astro@0.14.1", "", { "dependencies": { "@astrojs/compiler": "^2.9.1", "prettier": "^3.0.0", "sass-formatter": "^0.7.6" } }, "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw=="],
|
||||
|
||||
"prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="],
|
||||
|
||||
"prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="],
|
||||
|
||||
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
|
||||
|
||||
"pump": ["pump@3.0.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA=="],
|
||||
|
||||
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
|
||||
|
||||
"quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="],
|
||||
|
||||
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
||||
|
||||
"radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
@@ -663,6 +996,14 @@
|
||||
|
||||
"remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="],
|
||||
|
||||
"request-light": ["request-light@0.7.0", "", {}, "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="],
|
||||
|
||||
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
|
||||
|
||||
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||
|
||||
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
|
||||
|
||||
"retext": ["retext@9.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "retext-latin": "^4.0.0", "retext-stringify": "^4.0.0", "unified": "^11.0.0" } }, "sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA=="],
|
||||
|
||||
"retext-latin": ["retext-latin@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "parse-latin": "^7.0.0", "unified": "^11.0.0" } }, "sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA=="],
|
||||
@@ -671,14 +1012,28 @@
|
||||
|
||||
"retext-stringify": ["retext-stringify@4.0.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unified": "^11.0.0" } }, "sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA=="],
|
||||
|
||||
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
||||
|
||||
"rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="],
|
||||
|
||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||
|
||||
"s.color": ["s.color@0.0.15", "", {}, "sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
"sass-formatter": ["sass-formatter@0.7.9", "", { "dependencies": { "suf-log": "^2.5.3" } }, "sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw=="],
|
||||
|
||||
"sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="],
|
||||
|
||||
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
|
||||
|
||||
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
|
||||
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||
|
||||
"shiki": ["shiki@3.21.0", "", { "dependencies": { "@shikijs/core": "3.21.0", "@shikijs/engine-javascript": "3.21.0", "@shikijs/engine-oniguruma": "3.21.0", "@shikijs/langs": "3.21.0", "@shikijs/themes": "3.21.0", "@shikijs/types": "3.21.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-N65B/3bqL/TI2crrXr+4UivctrAGEjmsib5rPMMPpFp1xAx/w03v8WZ9RDDFYteXoEgY7qZ4HGgl5KBIu1153w=="],
|
||||
|
||||
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
|
||||
@@ -693,42 +1048,66 @@
|
||||
|
||||
"stream-replace-string": ["stream-replace-string@2.0.0", "", {}, "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w=="],
|
||||
|
||||
"string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
"stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
|
||||
|
||||
"strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||
|
||||
"suf-log": ["suf-log@2.5.3", "", { "dependencies": { "s.color": "0.0.15" } }, "sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow=="],
|
||||
|
||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
|
||||
"svgo": ["svgo@4.0.0", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^5.1.0", "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "^1.4.1" }, "bin": "./bin/svgo.js" }, "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw=="],
|
||||
|
||||
"synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.18", "", {}, "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw=="],
|
||||
|
||||
"tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="],
|
||||
|
||||
"tar": ["tar@7.5.2", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg=="],
|
||||
|
||||
"tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
|
||||
|
||||
"tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
|
||||
|
||||
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
|
||||
|
||||
"trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="],
|
||||
|
||||
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
|
||||
|
||||
"tsconfck": ["tsconfck@3.1.6", "", { "peerDependencies": { "typescript": "^5.0.0" }, "optionalPeers": ["typescript"], "bin": { "tsconfck": "bin/tsconfck.js" } }, "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
||||
|
||||
"type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="],
|
||||
|
||||
"typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="],
|
||||
|
||||
"typescript-eslint": ["typescript-eslint@8.52.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.52.0", "@typescript-eslint/parser": "8.52.0", "@typescript-eslint/typescript-estree": "8.52.0", "@typescript-eslint/utils": "8.52.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-atlQQJ2YkO4pfTVQmQ+wvYQwexPDOIgo+RaVcD7gHgzy/IQA+XTyuxNM9M9TVXvttkF7koBHmcwisKdOAf2EcA=="],
|
||||
|
||||
"ufo": ["ufo@1.6.2", "", {}, "sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q=="],
|
||||
|
||||
"ultrahtml": ["ultrahtml@1.6.0", "", {}, "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw=="],
|
||||
|
||||
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
||||
|
||||
"undici": ["undici@7.18.2", "", {}, "sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw=="],
|
||||
|
||||
"unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="],
|
||||
|
||||
"unifont": ["unifont@0.7.1", "", { "dependencies": { "css-tree": "^3.1.0", "ofetch": "^1.5.1", "ohash": "^2.0.11" } }, "sha512-0lg9M1cMYvXof8//wZBq6EDEfbwv4++t7+dYpXeS2ypaLuZJmUFYEwTm412/1ED/Wfo/wyzSu6kNZEr9hgRNfg=="],
|
||||
@@ -753,6 +1132,8 @@
|
||||
|
||||
"unstorage": ["unstorage@1.17.3", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q=="],
|
||||
|
||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
||||
|
||||
"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
|
||||
|
||||
"vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="],
|
||||
@@ -765,18 +1146,74 @@
|
||||
|
||||
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
|
||||
|
||||
"volar-service-css": ["volar-service-css@0.0.67", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-zV7C6enn9T9tuvQ6iSUyYEs34iPXR69Pf9YYWpbFYPWzVs22w96BtE8p04XYXbmjU6unt5oFt+iLL77bMB5fhA=="],
|
||||
|
||||
"volar-service-emmet": ["volar-service-emmet@0.0.67", "", { "dependencies": { "@emmetio/css-parser": "^0.4.1", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-UDBL5x7KptmuJZNCCXMlCndMhFult/tj+9jXq3FH1ZGS1E4M/1U5hC06pg1c6e4kn+vnR6bqmvX0vIhL4f98+A=="],
|
||||
|
||||
"volar-service-html": ["volar-service-html@0.0.67", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-ljREMF79JbcjNvObiv69HK2HCl5UT7WTD10zi6CRFUHMbPfiF2UZ42HGLsEGSzaHGZz6H4IFjSS/qfENRLUviQ=="],
|
||||
|
||||
"volar-service-prettier": ["volar-service-prettier@0.0.67", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-B4KnPJPNWFTkEDa6Fn08i5PpO6T1CecmLLTFZoXz2eI4Fxwba/3nDaaVSsEP7e/vEe+U5YqV9fBzayJT71G5xg=="],
|
||||
|
||||
"volar-service-typescript": ["volar-service-typescript@0.0.67", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-rfQBy36Rm1PU9vLWHk8BYJ4r2j/CI024vocJcH4Nb6K2RTc2Irmw6UOVY5DdGiPRV5r+e10wLMK5njj/EcL8sA=="],
|
||||
|
||||
"volar-service-typescript-twoslash-queries": ["volar-service-typescript-twoslash-queries@0.0.67", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-LD2R7WivDYp1SPgZrxx/0222xVTitDjm36oKo5+bfYG5kEgnw+BOPVHdwmvpJKg/RfssfxDI1ouwD4XkEDEfbA=="],
|
||||
|
||||
"volar-service-yaml": ["volar-service-yaml@0.0.67", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.19.2" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-jkdP/RF6wPIXEE3Ktnd81oJPn7aAvnVSiaqQHThC2Hrvo6xd9pEcqtbBUI+YfqVgvcMtXAkbtNO61K2GPhAiuA=="],
|
||||
|
||||
"vscode-css-languageservice": ["vscode-css-languageservice@6.3.9", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-1tLWfp+TDM5ZuVWht3jmaY5y7O6aZmpeXLoHl5bv1QtRsRKt4xYGRMmdJa5Pqx/FTkgRbsna9R+Gn2xE+evVuA=="],
|
||||
|
||||
"vscode-html-languageservice": ["vscode-html-languageservice@5.6.1", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-5Mrqy5CLfFZUgkyhNZLA1Ye5g12Cb/v6VM7SxUzZUaRKWMDz4md+y26PrfRTSU0/eQAl3XpO9m2og+GGtDMuaA=="],
|
||||
|
||||
"vscode-json-languageservice": ["vscode-json-languageservice@4.1.8", "", { "dependencies": { "jsonc-parser": "^3.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2" } }, "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg=="],
|
||||
|
||||
"vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="],
|
||||
|
||||
"vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="],
|
||||
|
||||
"vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="],
|
||||
|
||||
"vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="],
|
||||
|
||||
"vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="],
|
||||
|
||||
"vscode-nls": ["vscode-nls@5.2.0", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="],
|
||||
|
||||
"vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
|
||||
|
||||
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
|
||||
|
||||
"whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
|
||||
|
||||
"whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
|
||||
"which-pm-runs": ["which-pm-runs@1.1.0", "", {}, "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA=="],
|
||||
|
||||
"widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="],
|
||||
|
||||
"word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="],
|
||||
|
||||
"wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="],
|
||||
|
||||
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||
|
||||
"xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
|
||||
|
||||
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
||||
|
||||
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||
|
||||
"yaml": ["yaml@2.7.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ=="],
|
||||
|
||||
"yaml-language-server": ["yaml-language-server@1.19.2", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "lodash": "4.17.21", "prettier": "^3.5.0", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.7.1" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-9F3myNmJzUN/679jycdMxqtydPSDRAarSj3wPiF7pchEPnO9Dg07Oc+gIYLqXR4L+g+FSEVXXv2+mr54StLFOg=="],
|
||||
|
||||
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
||||
|
||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||
|
||||
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
|
||||
|
||||
"yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="],
|
||||
|
||||
"yocto-spinner": ["yocto-spinner@0.2.3", "", { "dependencies": { "yoctocolors": "^2.1.1" } }, "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ=="],
|
||||
@@ -791,6 +1228,14 @@
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
||||
|
||||
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
||||
|
||||
"@iconify/tools/svgo": ["svgo@3.3.2", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0" }, "bin": "./bin/svgo" }, "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw=="],
|
||||
|
||||
"@iconify/utils/globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="],
|
||||
|
||||
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
|
||||
@@ -805,20 +1250,84 @@
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
|
||||
|
||||
"ajv-draft-04/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"boxen/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
|
||||
|
||||
"csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
|
||||
|
||||
"dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
|
||||
|
||||
"ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||
"eslint-plugin-astro/postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
|
||||
|
||||
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
|
||||
"p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
||||
|
||||
"prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
|
||||
|
||||
"vscode-json-languageservice/jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="],
|
||||
|
||||
"widest-line/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||
|
||||
"wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="],
|
||||
|
||||
"wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
|
||||
"yaml-language-server/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
||||
|
||||
"yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="],
|
||||
|
||||
"@iconify/tools/svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="],
|
||||
|
||||
"@iconify/tools/svgo/css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="],
|
||||
|
||||
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
|
||||
|
||||
"ajv-draft-04/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"boxen/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
"boxen/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
|
||||
"csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
|
||||
|
||||
"ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
|
||||
"p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="],
|
||||
|
||||
"widest-line/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
"widest-line/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
||||
|
||||
"wrap-ansi/string-width/emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="],
|
||||
|
||||
"wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
"yaml-language-server/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||
|
||||
"@iconify/tools/svgo/css-tree/mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="],
|
||||
|
||||
"boxen/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
"widest-line/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="canonical" href="https://commonflow.org/404/"><title>Page Not Found | Git Common Flow</title><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Fonts --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"><!-- Prevent flash of wrong theme --><script>
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="canonical" href="https://commonflow.org/404/"><title>Page Not Found | Git Common-Flow</title><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Page Not Found | Git Common-Flow"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/404/"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Page Not Found | Git Common-Flow"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><!-- Favicon --><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/favicon.svg" type="image/svg+xml"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- Prevent flash of wrong theme --><script>
|
||||
(function () {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
const mode = localStorage.getItem("theme");
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
if (mode === "dark" || (mode !== "light" && prefersDark)) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script><link rel="stylesheet" href="/_astro/index.DViPM5fQ.css"></head> <body class="min-h-screen flex flex-col items-center justify-center p-8"> <div class="text-center"> <h1 class="text-[8rem] sm:text-[12rem] font-display font-bold leading-none
|
||||
text-[var(--color-border-strong)]
|
||||
dark:text-[var(--color-dark-border-strong)]">
|
||||
</script><link rel="stylesheet" href="/_astro/index.DF_wxGza.css"></head> <body class="min-h-screen"> <div class="flex flex-col items-center justify-center min-h-screen p-8"> <div class="text-center"> <h1 class="text-[8rem] sm:text-[12rem] font-display font-bold leading-none
|
||||
text-gray-300 dark:text-neutral-700">
|
||||
404
|
||||
</h1> <p class="text-xl mb-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]">
|
||||
</h1> <p class="text-xl mb-2 text-gray-600 dark:text-neutral-400">
|
||||
Page not found
|
||||
</p> <p class="text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]">
|
||||
</p> <p class="text-gray-500 dark:text-neutral-500">
|
||||
The page you're looking for doesn't exist.
|
||||
</p> <a href="/" class="inline-block mt-8 btn btn-primary">
|
||||
</p> <a href="/" class="inline-flex items-center justify-center gap-2 mt-8
|
||||
px-5 py-2.5 text-sm font-medium rounded-lg
|
||||
transition-all cursor-pointer
|
||||
bg-sky-600 text-white
|
||||
hover:bg-sky-500 hover:-translate-y-0.5 hover:shadow-md">
|
||||
Go to homepage
|
||||
</a> </div> </body></html>
|
||||
</a> </div> </div> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme"),t=window.matchMedia("(prefers-color-scheme: dark)").matches;e==="dark"||e!=="light"&&t?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
@@ -0,0 +1 @@
|
||||
import{i as o}from"./activeSectionTracker.CGlk-3e6.js";function a(){const e=document.getElementById("site-header"),d=document.getElementById("hero"),r=document.getElementById("mobile-menu-btn"),t=document.getElementById("mobile-nav");if(!e||!d)return;const i=64;function n(){e&&(window.scrollY>=i?(e.classList.remove("translate-y-[-100%]","border-transparent"),e.classList.add("border-gray-200","dark:border-neutral-800")):(e.classList.add("translate-y-[-100%]","border-transparent"),e.classList.remove("border-gray-200","dark:border-neutral-800")))}window.addEventListener("scroll",n,{passive:!0}),n(),r&&t&&(r.addEventListener("click",()=>{t.classList.toggle("hidden")}),t.querySelectorAll("a").forEach(s=>{s.addEventListener("click",()=>{t.classList.add("hidden")})})),o({linkSelector:"[data-nav-link]",defaultToFirst:!1})}a();document.addEventListener("astro:after-swap",a);
|
||||
@@ -0,0 +1 @@
|
||||
import{i as v}from"./activeSectionTracker.CGlk-3e6.js";function s(){v({linkSelector:"[data-sidebar-link]"});const t=document.getElementById("spec-toc-toggle"),e=document.getElementById("spec-toc-drawer"),r=e?.querySelector("[data-toc-backdrop]"),d=e?.querySelector("[data-toc-close]"),i=e?.querySelectorAll("[data-toc-link]");function a(){e?.classList.remove("hidden"),document.body.style.overflow="hidden"}function c(){e?.classList.add("hidden"),document.body.style.overflow=""}t?.addEventListener("click",a),r?.addEventListener("click",c),d?.addEventListener("click",c),i?.forEach(o=>{o.addEventListener("click",c)});const n=document.getElementById("spec");n&&t&&new IntersectionObserver(([l])=>{t.classList.toggle("hidden",!l.isIntersecting)},{threshold:0}).observe(n)}s();document.addEventListener("astro:after-swap",s);
|
||||
1
docs/_astro/activeSectionTracker.CGlk-3e6.js
Normal file
1
docs/_astro/activeSectionTracker.CGlk-3e6.js
Normal file
@@ -0,0 +1 @@
|
||||
function m(l){const{linkSelector:a,sectionIdAttr:o="data-section-id",headerOffset:f=100,defaultToFirst:u=!0}=l,s=document.querySelectorAll(a),i=[],r=new Set;s.forEach(n=>{const t=n.getAttribute(o);if(t&&!r.has(t)){r.add(t);const e=document.getElementById(t);e&&i.push({id:t,element:e})}});function d(){let n=u?i[0]?.id:null;for(const{id:t,element:e}of i)e.getBoundingClientRect().top<=f&&(n=t);s.forEach(t=>{const e=t.getAttribute(o);t.classList.toggle("active",e===n)})}let c=!1;window.addEventListener("scroll",()=>{c||(requestAnimationFrame(()=>{d(),c=!1}),c=!0)}),d()}export{m as i};
|
||||
Binary file not shown.
BIN
docs/_astro/bricolage-grotesque-latin-wght-normal.DLoelf7F.woff2
Normal file
BIN
docs/_astro/bricolage-grotesque-latin-wght-normal.DLoelf7F.woff2
Normal file
Binary file not shown.
Binary file not shown.
BIN
docs/_astro/dm-sans-latin-ext-wght-normal.BOFOeGcA.woff2
Normal file
BIN
docs/_astro/dm-sans-latin-ext-wght-normal.BOFOeGcA.woff2
Normal file
Binary file not shown.
BIN
docs/_astro/dm-sans-latin-wght-normal.Xz1IZZA0.woff2
Normal file
BIN
docs/_astro/dm-sans-latin-wght-normal.Xz1IZZA0.woff2
Normal file
Binary file not shown.
1
docs/_astro/index.DF_wxGza.css
Normal file
1
docs/_astro/index.DF_wxGza.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
docs/_astro/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2
Normal file
BIN
docs/_astro/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2
Normal file
Binary file not shown.
BIN
docs/_astro/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2
Normal file
BIN
docs/_astro/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2
Normal file
Binary file not shown.
BIN
docs/_astro/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2
Normal file
BIN
docs/_astro/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2
Normal file
Binary file not shown.
BIN
docs/_astro/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2
Normal file
BIN
docs/_astro/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2
Normal file
Binary file not shown.
BIN
docs/_astro/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2
Normal file
BIN
docs/_astro/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2
Normal file
Binary file not shown.
BIN
docs/apple-touch-icon.png
Normal file
BIN
docs/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
docs/favicon.ico
Normal file
BIN
docs/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
17
docs/favicon.svg
Normal file
17
docs/favicon.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Main horizontal line -->
|
||||
<path d="M 4 10 L 28 10" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
|
||||
<!-- Branch line: down from left, curve, up to right -->
|
||||
<path d="M 8 10 L 8 16 Q 8 22 16 22 Q 24 22 24 16 L 24 10"
|
||||
fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
|
||||
<!-- Left dot on main line -->
|
||||
<circle cx="8" cy="10" r="3" fill="currentColor"/>
|
||||
|
||||
<!-- Right dot on main line -->
|
||||
<circle cx="24" cy="10" r="3" fill="currentColor"/>
|
||||
|
||||
<!-- Middle dot on branch -->
|
||||
<circle cx="16" cy="22" r="3" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 625 B |
360
docs/index.html
360
docs/index.html
File diff suppressed because one or more lines are too long
@@ -1,169 +1,178 @@
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Git Common-Flow 1.0.0-rc.1"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/1.0.0-rc.1"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Common-Flow 1.0.0-rc.1"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><title>Git Common-Flow 1.0.0-rc.1</title><!-- Fonts - distinctive choices --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><!-- Theme initialization - prevent flash --><script>
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="canonical" href="https://commonflow.org/spec/1.0.0-rc.1/"><title>Git Common-Flow 1.0.0-rc.1 | Git Common-Flow</title><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Git Common-Flow 1.0.0-rc.1 | Git Common-Flow"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/spec/1.0.0-rc.1/"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Common-Flow 1.0.0-rc.1 | Git Common-Flow"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><!-- Favicon --><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/favicon.svg" type="image/svg+xml"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- Prevent flash of wrong theme --><script>
|
||||
(function () {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
const mode = localStorage.getItem("theme");
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
if (mode === "dark" || (mode !== "light" && prefersDark)) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script><link rel="stylesheet" href="/_astro/index.DViPM5fQ.css">
|
||||
<style>select[data-astro-cid-wyud3ywt] option[data-astro-cid-wyud3ywt]{background-color:var(--color-bg-primary);color:var(--color-text-primary)}.dark select[data-astro-cid-wyud3ywt] option[data-astro-cid-wyud3ywt]{background-color:var(--color-dark-bg-primary);color:var(--color-dark-text-primary)}.header-title[data-astro-cid-3ef6ksr2]{color:var(--color-text-primary)}.dark .header-title[data-astro-cid-3ef6ksr2]{color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-x2lc2h5w] p:last-child{margin-bottom:0}.spec-content[data-astro-cid-x2lc2h5w] a{color:var(--color-accent)}.spec-content[data-astro-cid-x2lc2h5w] a:hover{color:var(--color-accent-light)}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar{width:4px}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-track{background:transparent}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.dark #spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-thumb{background:var(--color-dark-border)}.spec-content[data-astro-cid-6lwcykzv]{max-width:var(--content-max-width)}.spec-content[data-astro-cid-6lwcykzv] h2{font-family:var(--font-display);font-size:1.75rem;font-weight:700;margin-top:3rem;margin-bottom:1.5rem;padding-bottom:.75rem;border-bottom:1px solid var(--color-border);color:var(--color-text-primary);scroll-margin-top:calc(var(--header-height) + 2rem)}.dark .spec-content[data-astro-cid-6lwcykzv] h2{border-bottom-color:var(--color-dark-border);color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-6lwcykzv] h2:first-child{margin-top:0}.spec-content[data-astro-cid-6lwcykzv] h3{font-family:var(--font-display);font-size:1.25rem;font-weight:600;margin-top:2rem;margin-bottom:1rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] h3{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] p{margin-bottom:1.25rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] p{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] strong{color:var(--color-text-primary);font-weight:600}.dark .spec-content[data-astro-cid-6lwcykzv] strong{color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-6lwcykzv] ul{margin-bottom:1.25rem;padding-left:1.5rem}.spec-content[data-astro-cid-6lwcykzv] ol{margin-bottom:1.25rem;padding-left:2.5rem;counter-reset:item;list-style:none}.spec-content[data-astro-cid-6lwcykzv] ol>li{counter-increment:item;position:relative}.spec-content[data-astro-cid-6lwcykzv] ol>li:before{content:counters(item,".") ".";position:absolute;left:-2.5rem;width:2rem;text-align:right;font-weight:500;color:var(--color-text-muted)}.dark .spec-content[data-astro-cid-6lwcykzv] ol>li:before{color:var(--color-dark-text-muted)}.spec-content[data-astro-cid-6lwcykzv] li{margin-bottom:.5rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] li{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] a{color:var(--color-accent);text-decoration:none;transition:color .15s ease}.spec-content[data-astro-cid-6lwcykzv] a:hover{color:var(--color-accent-light)}.spec-content[data-astro-cid-6lwcykzv] blockquote{border-left:3px solid var(--color-accent);padding-left:1.5rem;margin:1.5rem 0;color:var(--color-text-muted);font-style:italic}.dark .spec-content[data-astro-cid-6lwcykzv] blockquote{color:var(--color-dark-text-muted)}.spec-content[data-astro-cid-6lwcykzv] img{max-width:100%;height:auto;border-radius:8px;margin:2rem 0}.faq-section[data-astro-cid-hqz3ghsx]{background-color:var(--color-bg-secondary)}.dark .faq-section[data-astro-cid-hqz3ghsx]{background-color:var(--color-dark-bg-secondary)}.spec-content[data-astro-cid-hqz3ghsx] p:last-child{margin-bottom:0}.spec-content[data-astro-cid-hqz3ghsx] ul,.spec-content[data-astro-cid-hqz3ghsx] ol{margin-top:1rem}.spec-content[data-astro-cid-hqz3ghsx] li{color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-hqz3ghsx] li{color:var(--color-dark-text-secondary)}
|
||||
</style></head> <body class="min-h-screen"> <header id="site-header" class="fixed top-0 inset-x-0 z-50 glass border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300" data-astro-cid-3ef6ksr2> <div class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between" data-astro-cid-3ef6ksr2> <!-- Logo / Title --> <a href="#hero" class="header-title flex items-center gap-3 no-underline
|
||||
hover:text-[var(--color-accent)] transition-colors" data-astro-cid-3ef6ksr2> <span class="font-display font-bold text-lg tracking-tight" data-astro-cid-3ef6ksr2>
|
||||
</script><link rel="stylesheet" href="/_astro/index.DF_wxGza.css"></head> <body class="min-h-screen"> <header id="site-header" class="fixed top-0 inset-x-0 z-50 border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300
|
||||
backdrop-blur-xl bg-gray-50/85 dark:bg-neutral-950/85"> <div class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between"> <!-- Logo / Title + Version --> <div class="flex items-center gap-3"> <a href="#hero" class="flex items-center gap-3 no-underline
|
||||
text-gray-950 dark:text-neutral-50
|
||||
hover:text-sky-600 transition-colors"> <span class="font-display font-bold text-lg tracking-tight">
|
||||
Git Common-Flow
|
||||
</span> </a> <!-- Desktop Navigation --> <nav class="hidden md:flex items-center gap-1" data-astro-cid-3ef6ksr2> <a href="#about" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>About</a> <a href="#spec" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>Spec</a> <a href="#faq" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>FAQ</a> </nav> <!-- Right side: Version, Theme, GitHub --> <div class="flex items-center gap-3" data-astro-cid-3ef6ksr2> <div class="version-selector relative" data-astro-cid-wyud3ywt> <select data-version-select class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors" data-astro-cid-wyud3ywt> <option value="1.0.0-rc.5" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.5 </option><option value="1.0.0-rc.4" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.4 </option><option value="1.0.0-rc.3" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.3 </option><option value="1.0.0-rc.2" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.2 </option><option value="1.0.0-rc.1" selected data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.1 </option> </select> <!-- Dropdown arrow --> <svg class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-wyud3ywt> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-wyud3ywt></path> </svg> </div> <script type="module">function t(){document.querySelectorAll("[data-version-select]").forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("change",n=>{const a=n.target.value;window.location.href=`/spec/${a}`}))})}t();document.addEventListener("astro:after-swap",t);</script> <button data-theme-toggle type="button" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200" aria-label="Toggle dark mode"> <!-- Sun icon (shown in dark mode) --> <svg data-sun-icon class="hidden w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <!-- Moon icon (shown in light mode) --> <svg data-moon-icon class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path> </svg> </button> <script type="module">function n(){const c=document.querySelectorAll("[data-theme-toggle]");function o(){const e=localStorage.getItem("theme");return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function r(e){document.querySelectorAll("[data-sun-icon]").forEach(t=>{t.classList.toggle("hidden",!e)}),document.querySelectorAll("[data-moon-icon]").forEach(t=>{t.classList.toggle("hidden",e)})}function a(e){localStorage.setItem("theme",e),document.documentElement.classList.toggle("dark",e==="dark"),r(e==="dark")}const d=o();a(d),c.forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("click",()=>{const t=document.documentElement.classList.contains("dark");a(t?"light":"dark")}))}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",e=>{localStorage.getItem("theme")||a(e.matches?"dark":"light")})}n();document.addEventListener("astro:after-swap",n);</script> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors" aria-label="View on GitHub" data-astro-cid-3ef6ksr2> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" data-astro-cid-3ef6ksr2></path> </svg> </a> <!-- Mobile menu button --> <button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]" aria-label="Toggle menu" data-astro-cid-3ef6ksr2> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-3ef6ksr2></path> </svg> </button> </div> </div> <!-- Mobile Navigation --> <nav id="mobile-nav" class="md:hidden hidden border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-3ef6ksr2> <div class="px-4 py-3 space-y-1" data-astro-cid-3ef6ksr2> <a href="#about" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
About
|
||||
</a> <a href="#spec" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
Spec
|
||||
</a> <a href="#faq" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
FAQ
|
||||
</a> </div> </nav> </header> <script type="module">function d(){const e=document.getElementById("site-header"),o=document.getElementById("hero"),s=document.getElementById("mobile-menu-btn"),r=document.getElementById("mobile-nav");if(!e||!o)return;new IntersectionObserver(([t])=>{t.isIntersecting?(e.classList.add("translate-y-[-100%]"),e.classList.remove("border-[var(--color-border)]"),e.classList.remove("dark:border-[var(--color-dark-border)]")):(e.classList.remove("translate-y-[-100%]"),e.classList.add("border-[var(--color-border)]"),e.classList.add("dark:border-[var(--color-dark-border)]"))},{threshold:0,rootMargin:"-64px 0px 0px 0px"}).observe(o),s&&r&&(s.addEventListener("click",()=>{r.classList.toggle("hidden")}),r.querySelectorAll("a").forEach(t=>{t.addEventListener("click",()=>{r.classList.add("hidden")})}))}d();document.addEventListener("astro:after-swap",d);</script> <main> <section id="hero" class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 py-16 overflow-hidden"> <!-- Background gradient/texture --> <div class="absolute inset-0 bg-gradient-to-b from-[var(--color-bg-secondary)]
|
||||
to-[var(--color-bg-primary)]
|
||||
dark:from-[var(--color-dark-bg-secondary)]
|
||||
dark:to-[var(--color-dark-bg-primary)]"></div> <!-- Subtle grid pattern --> <div class="absolute inset-0 opacity-[0.03] dark:opacity-[0.05]" style="background-image: linear-gradient(var(--color-text-primary) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--color-text-primary) 1px, transparent 1px);
|
||||
background-size: 60px 60px;"></div> <!-- Top bar with version & theme --> <div class="absolute top-0 inset-x-0 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"> <div class="flex items-center gap-3"> <div class="version-selector relative" data-astro-cid-wyud3ywt> <select data-version-select class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors" data-astro-cid-wyud3ywt> <option value="1.0.0-rc.5" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.5 </option><option value="1.0.0-rc.4" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.4 </option><option value="1.0.0-rc.3" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.3 </option><option value="1.0.0-rc.2" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.2 </option><option value="1.0.0-rc.1" selected data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.1 </option> </select> <!-- Dropdown arrow --> <svg class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-wyud3ywt> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-wyud3ywt></path> </svg> </div> </div> <div class="flex items-center gap-2"> <button data-theme-toggle type="button" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200" aria-label="Toggle dark mode"> <!-- Sun icon (shown in dark mode) --> <svg data-sun-icon class="hidden w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <!-- Moon icon (shown in light mode) --> <svg data-moon-icon class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path> </svg> </button> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-white/50 dark:hover:bg-white/10
|
||||
transition-colors" aria-label="View on GitHub"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path> </svg> </a> </div> </div> <!-- Main content --> <div class="relative z-10 w-full max-w-4xl mx-auto text-center"> <!-- Title --> <h1 class="animate-fade-in-up mb-4
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]">
|
||||
</span> </a> <div class="hidden md:block"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.1</span> <svg width="1em" height="1em" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <symbol id="ai:heroicons:chevron-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m19.5 8.25l-7.5 7.5l-7.5-7.5"/></symbol><use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.1 </a> </div> </div> <script type="module">function c(){document.querySelectorAll("[data-version-selector]").forEach(e=>{if(e.dataset.initialized)return;e.dataset.initialized="true";const t=e.querySelector("[data-version-trigger]"),a=e.querySelector("[data-version-dropdown]"),n=e.querySelector("[data-arrow-icon]");if(!t||!a)return;const l=()=>{a.dataset.open="true",t.setAttribute("aria-expanded","true"),n&&(n.style.transform="rotate(180deg)")},o=()=>{delete a.dataset.open,t.setAttribute("aria-expanded","false"),n&&(n.style.transform="")};t.addEventListener("click",r=>{r.stopPropagation();const u=a.dataset.open==="true";document.querySelectorAll("[data-version-dropdown][data-open]").forEach(s=>{delete s.dataset.open;const i=s.previousElementSibling;i?.setAttribute("aria-expanded","false");const d=i?.querySelector("[data-arrow-icon]");d&&(d.style.transform="")}),u?o():l()}),document.addEventListener("click",r=>{e.contains(r.target)||o()}),document.addEventListener("keydown",r=>{r.key==="Escape"&&a.dataset.open==="true"&&(o(),t.focus())})})}c();document.addEventListener("astro:after-swap",c);</script> </div> </div> <!-- Desktop Navigation --> <nav class="hidden md:flex items-center gap-1"> <a href="#about" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="about"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:information-circle"> <symbol id="ai:heroicons:information-circle" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m11.25 11.25l.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9-3.75h.008v.008H12z"/></symbol><use href="#ai:heroicons:information-circle"></use> </svg> About </a><a href="#spec" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="spec"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:document-text"> <symbol id="ai:heroicons:document-text" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9"/></symbol><use href="#ai:heroicons:document-text"></use> </svg> Spec </a><a href="#faq" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="faq"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:question-mark-circle"> <symbol id="ai:heroicons:question-mark-circle" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/></symbol><use href="#ai:heroicons:question-mark-circle"></use> </svg> FAQ </a> </nav> <!-- Right side: Theme, GitHub --> <div class="flex items-center gap-3"> <div class="relative group"> <button data-theme-toggle type="button" class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle theme"> <svg width="1em" height="1em" data-theme-icon="light" class="hidden w-5 h-5" data-icon="heroicons:sun"> <symbol id="ai:heroicons:sun" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0a3.75 3.75 0 0 1 7.5 0"/></symbol><use href="#ai:heroicons:sun"></use> </svg> <svg width="1em" height="1em" data-theme-icon="dark" class="hidden w-5 h-5" data-icon="heroicons:moon"> <symbol id="ai:heroicons:moon" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21.752 15.002A9.7 9.7 0 0 1 18 15.75A9.75 9.75 0 0 1 8.25 6c0-1.33.266-2.597.748-3.752A9.75 9.75 0 0 0 3 11.25A9.75 9.75 0 0 0 12.75 21a9.75 9.75 0 0 0 9.002-5.998"/></symbol><use href="#ai:heroicons:moon"></use> </svg> <svg width="1em" height="1em" data-theme-icon="auto" class="hidden w-5 h-5" data-icon="heroicons:computer-desktop"> <symbol id="ai:heroicons:computer-desktop" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25m18 0A2.25 2.25 0 0 0 18.75 3H5.25A2.25 2.25 0 0 0 3 5.25m18 0V12a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 12V5.25"/></symbol><use href="#ai:heroicons:computer-desktop"></use> </svg> </button> <!-- Tooltip --> <div class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"> <span data-tooltip-text="light" class="hidden">Light</span> <span data-tooltip-text="dark" class="hidden">Dark</span> <span data-tooltip-text="auto" class="hidden">System</span> </div> </div> <script type="module">function r(){const c=document.querySelectorAll("[data-theme-toggle]");function n(){const e=localStorage.getItem("theme");return e==="dark"||e==="light"||e==="auto"?e:"auto"}function i(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function d(e){return e==="auto"?i():e}function s(e){document.querySelectorAll("[data-theme-icon]").forEach(t=>{const a=t.dataset.themeIcon;t.classList.toggle("hidden",a!==e)}),document.querySelectorAll("[data-tooltip-text]").forEach(t=>{const a=t.dataset.tooltipText;t.classList.toggle("hidden",a!==e)})}function o(e){d(e)==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark"),s(e)}function u(e){localStorage.setItem("theme",e),o(e)}function l(){const e=n();return e==="light"?"dark":e==="dark"?"auto":"light"}const f=n();o(f),c.forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("click",()=>{u(l())}))}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{n()==="auto"&&o("auto")})}r();document.addEventListener("astro:after-swap",r);</script> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="View on GitHub"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="simple-icons:github"> <symbol id="ai:simple-icons:github" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></symbol><use href="#ai:simple-icons:github"></use> </svg> </a> <!-- Mobile menu button --> <button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle menu"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:bars-3"> <symbol id="ai:heroicons:bars-3" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"/></symbol><use href="#ai:heroicons:bars-3"></use> </svg> </button> </div> </div> <!-- Mobile Navigation --> <nav id="mobile-nav" class="md:hidden hidden border-t border-gray-200 dark:border-neutral-800"> <div class="px-4 py-3 space-y-1 text-center"> <div class="py-2 flex justify-center"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.1</span> <svg width="1em" height="1em" viewBox="0 0 24 24" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.1 </a> </div> </div> </div> <a href="#about" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="about"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:information-circle"> <use href="#ai:heroicons:information-circle"></use> </svg> About </a><a href="#spec" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="spec"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:document-text"> <use href="#ai:heroicons:document-text"></use> </svg> Spec </a><a href="#faq" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="faq"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:question-mark-circle"> <use href="#ai:heroicons:question-mark-circle"></use> </svg> FAQ </a> </div> </nav> </header> <script type="module" src="/_astro/Header.astro_astro_type_script_index_0_lang.ClIJVJFM.js"></script> <main> <section id="hero" class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 pt-16 pb-24 overflow-hidden"> <!-- Background gradient/texture --> <div class="absolute inset-0 bg-gradient-to-b
|
||||
from-gray-100 to-gray-50
|
||||
dark:from-neutral-900 dark:to-neutral-950"></div> <!-- Subtle grid pattern with fade --> <div class="absolute inset-0 opacity-[0.06] dark:opacity-[0.12]
|
||||
bg-[linear-gradient(theme(colors.gray.950)_1px,transparent_1px),linear-gradient(90deg,theme(colors.gray.950)_1px,transparent_1px)]
|
||||
dark:bg-[linear-gradient(theme(colors.neutral.600)_1px,transparent_1px),linear-gradient(90deg,theme(colors.neutral.600)_1px,transparent_1px)]
|
||||
bg-[size:60px_60px] bg-center
|
||||
[-webkit-mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]
|
||||
[mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]"></div> <!-- Top bar with version & theme --> <div class="absolute top-0 inset-x-0 z-20 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"> <div class="flex items-center gap-3"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.1</span> <svg width="1em" height="1em" viewBox="0 0 24 24" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.1 </a> </div> </div> </div> <div class="flex items-center gap-2"> <div class="relative group"> <button data-theme-toggle type="button" class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle theme"> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="light" class="hidden w-5 h-5" data-icon="heroicons:sun"> <use href="#ai:heroicons:sun"></use> </svg> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="dark" class="hidden w-5 h-5" data-icon="heroicons:moon"> <use href="#ai:heroicons:moon"></use> </svg> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="auto" class="hidden w-5 h-5" data-icon="heroicons:computer-desktop"> <use href="#ai:heroicons:computer-desktop"></use> </svg> </button> <!-- Tooltip --> <div class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"> <span data-tooltip-text="light" class="hidden">Light</span> <span data-tooltip-text="dark" class="hidden">Dark</span> <span data-tooltip-text="auto" class="hidden">System</span> </div> </div> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-white/50 dark:hover:bg-neutral-800/50" aria-label="View on GitHub"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-5 h-5" data-icon="simple-icons:github"> <use href="#ai:simple-icons:github"></use> </svg> </a> </div> </div> <!-- Main content --> <div class="relative z-10 w-full max-w-4xl mx-auto text-center"> <!-- Title --> <h1 class="animate-fade-in-up mb-4
|
||||
text-gray-950 dark:text-neutral-50">
|
||||
Git Common-Flow
|
||||
</h1> <!-- Tagline --> <p class="animate-fade-in-up delay-100
|
||||
text-lg sm:text-xl max-w-2xl mx-auto mb-8
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]">
|
||||
text-gray-600 dark:text-neutral-400">
|
||||
A sensible git workflow for teams who ship
|
||||
</p> <!-- Version badge --> <div class="animate-fade-in-up delay-200 mb-10"> <span class="version-badge">v1.0.0-rc.1</span> </div> <!-- SVG Diagram --> <div class="animate-fade-in-up delay-300
|
||||
</p> <!-- Version badge --> <div class="animate-fade-in-up delay-200 mb-10"> <span class="inline-flex items-center px-3 py-1 font-mono text-xs font-medium
|
||||
rounded-full border
|
||||
bg-gray-100 border-gray-200 text-gray-500
|
||||
dark:bg-neutral-800/50 dark:border-neutral-700 dark:text-neutral-400">
|
||||
v1.0.0-rc.1 </span> </div> <!-- SVG Diagram --> <div class="animate-fade-in-up delay-300
|
||||
relative mx-auto mb-12 p-4 sm:p-8
|
||||
bg-white dark:bg-[var(--color-dark-bg-secondary)]
|
||||
bg-white dark:bg-neutral-900
|
||||
rounded-2xl shadow-lg dark:shadow-none
|
||||
border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"> <img src="/spec/1.0.0-rc.1.svg" alt="Git Common-Flow diagram" class="w-full h-auto max-w-3xl mx-auto
|
||||
border border-gray-200 dark:border-neutral-800"> <img src="/spec/1.0.0-rc.1.svg" alt="Git Common-Flow diagram" class="w-full h-auto max-w-3xl mx-auto
|
||||
dark:invert dark:hue-rotate-180 dark:contrast-90"> </div> <!-- Navigation links --> <nav class="animate-fade-in-up delay-400
|
||||
flex flex-wrap items-center justify-center gap-4"> <a href="#about" class="btn btn-ghost">About</a> <a href="#spec" class="btn btn-primary">Read the Spec</a> <a href="#faq" class="btn btn-ghost">FAQ</a> </nav> </div> <!-- Scroll indicator --> <a href="#about" class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
flex flex-wrap items-center justify-center gap-4"> <a href="#about" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50">
|
||||
About
|
||||
</a> <a href="#spec" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
bg-sky-600 text-white
|
||||
hover:bg-sky-500 hover:-translate-y-0.5 hover:shadow-md">
|
||||
Read the Spec
|
||||
</a> <a href="#faq" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50">
|
||||
FAQ
|
||||
</a> </nav> </div> <!-- Scroll indicator --> <a href="#about" class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
animate-fade-in delay-700
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-accent)] transition-colors" aria-label="Scroll to content"> <svg class="w-6 h-6 animate-bounce-subtle" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"></path> </svg> </a> </section> <section id="about" class="py-20 sm:py-28" data-astro-cid-x2lc2h5w> <div class="section-container" data-astro-cid-x2lc2h5w> <div class="max-w-3xl mx-auto" data-astro-cid-x2lc2h5w> <!-- Section header --> <div class="mb-12 text-center" data-astro-cid-x2lc2h5w> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-x2lc2h5w>About Common-Flow</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w>
|
||||
A practical git workflow that combines the best of GitHub Flow with
|
||||
versioned releases
|
||||
</p> </div> <!-- Introduction --> <div class="prose-spec mb-12" data-astro-cid-x2lc2h5w> <div class="spec-content" data-astro-cid-x2lc2h5w></div> </div> <!-- Summary as feature cards --> <div class="mb-16" data-astro-cid-x2lc2h5w> <h3 class="text-xl font-display font-semibold mb-6
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]" data-astro-cid-x2lc2h5w>
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-sky-600 transition-colors" aria-label="Scroll to content"> <svg width="1em" height="1em" class="w-6 h-6 animate-bounce-subtle" data-icon="heroicons:arrow-down"> <symbol id="ai:heroicons:arrow-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3"/></symbol><use href="#ai:heroicons:arrow-down"></use> </svg> </a> </section> <section id="about" class="py-20 sm:py-28"> <div class="section-container"> <div class="max-w-3xl mx-auto"> <div class="mb-12 text-center"> <h2 class="text-3xl sm:text-4xl mb-4">About Common-Flow</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> A practical git workflow that combines the best of GitHub Flow with versioned releases </p> </div> <!-- Introduction --> <div class="prose-spec mb-12"></div> <!-- Summary as feature cards --> <div class="mb-16"> <h3 class="text-xl font-display font-semibold mb-6
|
||||
text-gray-950 dark:text-neutral-50">
|
||||
Key Principles
|
||||
</h3> <div class="spec-content prose-spec" data-astro-cid-x2lc2h5w><p>Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
</h3> <div class="prose-spec"><p>Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
the <a href="http://scottchacon.com/2011/08/31/github-flow.html">original variant</a>
|
||||
of <a href="https://guides.github.com/introduction/flow/">GitHub Flow</a>, while taking
|
||||
into account how a lot of open source projects use git.</p>
|
||||
<p>TL;DR: Common-Flow is basically GitHub Flow with the addition of versioned
|
||||
releases, maintenance releases for old versions, and without the requirement to
|
||||
deploy to production all the time.</p></div> </div> <!-- Author & License --> <div class="pt-8 border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-x2lc2h5w> <div class="grid sm:grid-cols-2 gap-8" data-astro-cid-x2lc2h5w> <div data-astro-cid-x2lc2h5w> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-x2lc2h5w>
|
||||
Author
|
||||
</h4> <div class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w><p>The Git Common-Flow specification is authored
|
||||
by <a href="http://jimeh.me">Jim Myhrberg</a>.</p>
|
||||
<p>If you'd like to leave feedback,
|
||||
please <a href="https://github.com/jimeh/common-flow/issues">open an issue on GitHub</a>.</p></div> </div> <div data-astro-cid-x2lc2h5w> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-x2lc2h5w>
|
||||
deploy to production all the time.</p></div> </div> <!-- Feedback & License --> <div class="pt-8 border-t border-gray-200 dark:border-neutral-800"> <div class="grid sm:grid-cols-2 gap-8"> <div> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Feedback
|
||||
</h4> <p class="text-gray-600 dark:text-neutral-400">
|
||||
Please <a href="https://github.com/jimeh/common-flow/issues" class="text-sky-600 hover:text-sky-400" target="_blank" rel="noopener noreferrer">open an issue on GitHub</a>.
|
||||
</p> </div> <div> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
License
|
||||
</h4> <div class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w><p><a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons - CC BY 3.0</a></p></div> </div> </div> </div> </div> </div> </section> <section id="spec" class="py-20 sm:py-28" data-astro-cid-6lwcykzv> <div class="section-container" data-astro-cid-6lwcykzv> <!-- Section header --> <div class="max-w-3xl mx-auto mb-12 text-center" data-astro-cid-6lwcykzv> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-6lwcykzv>The Specification</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-6lwcykzv>
|
||||
The complete Git Common-Flow specification
|
||||
</p> </div> <!-- Content with sidebar --> <div class="lg:flex lg:gap-8" data-astro-cid-6lwcykzv> <!-- Sidebar --> <div class="lg:w-64 lg:flex-shrink-0" data-astro-cid-6lwcykzv> <aside id="spec-sidebar" class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
</h4> <div class="text-gray-600 dark:text-neutral-400"><p><a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons - CC BY 3.0</a></p></div> </div> </div> </div> </div> </div> </section> <section id="spec" class="py-20 sm:py-28"> <div class="section-container"> <div class="mb-12 text-center max-w-3xl mx-auto"> <h2 class="text-3xl sm:text-4xl mb-4">The Specification</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> The complete Git Common-Flow specification </p> </div> <!-- Content with sidebar --> <div class="lg:flex lg:gap-8"> <!-- Sidebar --> <div class="lg:w-64 lg:flex-shrink-0"> <aside id="spec-sidebar" class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
lg:max-h-[calc(100vh-8rem)] lg:overflow-y-auto
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-lfaoh65k> <nav class="space-y-1 py-2" data-astro-cid-lfaoh65k> <div class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-lfaoh65k>
|
||||
On This Page
|
||||
</div> <a href="#summary" class="sidebar-link " data-sidebar-link data-section-id="summary" data-astro-cid-lfaoh65k> Summary </a><a href="#terminology" class="sidebar-link " data-sidebar-link data-section-id="terminology" data-astro-cid-lfaoh65k> Terminology </a><a href="#specification" class="sidebar-link " data-sidebar-link data-section-id="specification" data-astro-cid-lfaoh65k> Specification </a><a href="#spec-tldr" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-tldr" data-astro-cid-lfaoh65k> TL;DR </a><a href="#spec-the-master-branch" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-the-master-branch" data-astro-cid-lfaoh65k> The Master Branch </a><a href="#spec-change-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-change-branches" data-astro-cid-lfaoh65k> Change Branches </a><a href="#spec-pull-requests" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-pull-requests" data-astro-cid-lfaoh65k> Pull Requests </a><a href="#spec-versioning" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-versioning" data-astro-cid-lfaoh65k> Versioning </a><a href="#spec-releases" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-releases" data-astro-cid-lfaoh65k> Releases </a><a href="#spec-short-term-release-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-short-term-release-branches" data-astro-cid-lfaoh65k> Short-Term Release Branches </a><a href="#spec-long-term-release-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-long-term-release-branches" data-astro-cid-lfaoh65k> Long-term Release Branches </a><a href="#spec-bug-fixes-rollback" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-bug-fixes-rollback" data-astro-cid-lfaoh65k> Bug Fixes & Rollback </a><a href="#spec-git-best-practices" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-git-best-practices" data-astro-cid-lfaoh65k> Git Best Practices </a> </nav> </aside> <!-- Mobile floating button --> <button id="spec-toc-toggle" class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-gray-200 dark:border-neutral-800"> <nav class="space-y-1 py-2"> <div class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Table of Contents
|
||||
</div> <a href="#terminology" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-sidebar-link data-section-id="terminology"> <span>Terminology</span> </a><a href="#specification" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-sidebar-link data-section-id="specification"> <span>Specification</span> </a><a href="#spec-the-master-branch" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-the-master-branch"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 1. </span> <span>The Master Branch</span> </a><a href="#spec-changes" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-changes"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 2. </span> <span>Changes</span> </a><a href="#spec-git-best-practices" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-git-best-practices"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 3. </span> <span>Git Best Practices</span> </a><a href="#spec-versioning" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-versioning"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 4. </span> <span>Versioning</span> </a><a href="#spec-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-releases"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 5. </span> <span>Releases</span> </a><a href="#spec-bug-fixes-rollback" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-bug-fixes-rollback"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 6. </span> <span>Bug Fixes & Rollback</span> </a><a href="#spec-maintenance-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-maintenance-releases"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 7. </span> <span>Maintenance Releases</span> </a> </nav> </aside> <!-- Mobile floating button --> <button id="spec-toc-toggle" class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
w-12 h-12 rounded-full shadow-lg
|
||||
bg-[var(--color-accent)] text-white
|
||||
bg-sky-600 text-white
|
||||
flex items-center justify-center
|
||||
hover:bg-[var(--color-accent-light)]
|
||||
transition-all duration-200" aria-label="Jump to section" data-astro-cid-lfaoh65k> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-lfaoh65k> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" data-astro-cid-lfaoh65k></path> </svg> </button> <!-- Mobile TOC drawer --> <div id="spec-toc-drawer" class="lg:hidden fixed inset-0 z-50 hidden" data-toc-drawer data-astro-cid-lfaoh65k> <!-- Backdrop --> <div class="absolute inset-0 bg-black/50" data-toc-backdrop data-astro-cid-lfaoh65k></div> <!-- Drawer --> <div class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-[var(--color-bg-primary)] dark:bg-[var(--color-dark-bg-primary)]
|
||||
rounded-t-2xl shadow-xl p-6" data-astro-cid-lfaoh65k> <div class="flex items-center justify-between mb-4" data-astro-cid-lfaoh65k> <span class="text-sm font-semibold uppercase tracking-wider
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-lfaoh65k>
|
||||
hover:bg-sky-500
|
||||
transition-all duration-200" aria-label="Jump to section"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:bars-3-bottom-left"> <symbol id="ai:heroicons:bars-3-bottom-left" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12"/></symbol><use href="#ai:heroicons:bars-3-bottom-left"></use> </svg> </button> <!-- Mobile TOC drawer --> <div id="spec-toc-drawer" class="lg:hidden fixed inset-0 z-50 hidden" data-toc-drawer> <!-- Backdrop --> <div class="absolute inset-0 bg-black/50" data-toc-backdrop></div> <!-- Drawer --> <div class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-gray-50 dark:bg-neutral-950
|
||||
rounded-t-2xl shadow-xl p-6"> <div class="flex items-center justify-between mb-4"> <span class="text-sm font-semibold uppercase tracking-wider
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Jump to Section
|
||||
</span> <button class="p-2 rounded-lg hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]" data-toc-close aria-label="Close" data-astro-cid-lfaoh65k> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-lfaoh65k> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" data-astro-cid-lfaoh65k></path> </svg> </button> </div> <nav class="space-y-1" data-astro-cid-lfaoh65k> <a href="#summary" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Summary </a><a href="#terminology" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Terminology </a><a href="#specification" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Specification </a><a href="#spec-tldr" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> TL;DR </a><a href="#spec-the-master-branch" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> The Master Branch </a><a href="#spec-change-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Change Branches </a><a href="#spec-pull-requests" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Pull Requests </a><a href="#spec-versioning" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Versioning </a><a href="#spec-releases" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Releases </a><a href="#spec-short-term-release-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Short-Term Release Branches </a><a href="#spec-long-term-release-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Long-term Release Branches </a><a href="#spec-bug-fixes-rollback" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Bug Fixes & Rollback </a><a href="#spec-git-best-practices" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Git Best Practices </a> </nav> </div> </div> <script type="module">function l(){const r=document.querySelectorAll("[data-sidebar-link]"),d=new Map;r.forEach(e=>{const t=e.getAttribute("data-section-id");if(t){const o=document.getElementById(t);o&&d.set(t,o)}});const g=new IntersectionObserver(e=>{e.forEach(t=>{if(t.isIntersecting){const o=t.target.getAttribute("id");r.forEach(a=>{const E=a.getAttribute("data-section-id");a.classList.toggle("active",E===o)})}})},{rootMargin:"-20% 0% -60% 0%",threshold:0});d.forEach(e=>g.observe(e));const n=document.getElementById("spec-toc-toggle"),c=document.getElementById("spec-toc-drawer"),u=c?.querySelector("[data-toc-backdrop]"),b=c?.querySelector("[data-toc-close]"),v=c?.querySelectorAll("[data-toc-link]");function f(){c?.classList.remove("hidden"),document.body.style.overflow="hidden"}function s(){c?.classList.add("hidden"),document.body.style.overflow=""}n?.addEventListener("click",f),u?.addEventListener("click",s),b?.addEventListener("click",s),v?.forEach(e=>{e.addEventListener("click",s)});const i=document.getElementById("spec");i&&n&&new IntersectionObserver(([t])=>{n.classList.toggle("hidden",!t.isIntersecting)},{threshold:0}).observe(i)}l();document.addEventListener("astro:after-swap",l);</script> </div> <!-- Main content --> <div class="flex-1 min-w-0" data-astro-cid-6lwcykzv> <article class="prose-spec spec-content" data-astro-cid-6lwcykzv> <!-- Terminology --> <section id="terminology" data-astro-cid-6lwcykzv> <h2 data-astro-cid-6lwcykzv>Terminology</h2> <ul>
|
||||
</span> <button class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800" data-toc-close aria-label="Close"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:x-mark"> <symbol id="ai:heroicons:x-mark" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M6 18L18 6M6 6l12 12"/></symbol><use href="#ai:heroicons:x-mark"></use> </svg> </button> </div> <nav class="space-y-1"> <a href="#terminology" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-toc-link> <span>Terminology</span> </a><a href="#specification" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-toc-link> <span>Specification</span> </a><a href="#spec-the-master-branch" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 1. </span> <span>The Master Branch</span> </a><a href="#spec-changes" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 2. </span> <span>Changes</span> </a><a href="#spec-git-best-practices" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 3. </span> <span>Git Best Practices</span> </a><a href="#spec-versioning" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 4. </span> <span>Versioning</span> </a><a href="#spec-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 5. </span> <span>Releases</span> </a><a href="#spec-bug-fixes-rollback" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 6. </span> <span>Bug Fixes & Rollback</span> </a><a href="#spec-maintenance-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 7. </span> <span>Maintenance Releases</span> </a> </nav> </div> </div> <script type="module" src="/_astro/SpecSidebar.astro_astro_type_script_index_0_lang.BQBj5HuJ.js"></script> </div> <!-- Main content --> <div class="flex-1 min-w-0"> <article class="prose-spec"> <!-- Terminology --> <section id="terminology"> <h2>Terminology</h2> <ul>
|
||||
<li><strong>Master Branch</strong> - Must always have passing tests, is considered bleeding
|
||||
edge, and must be named <code>master</code>.</li>
|
||||
<li><strong>Change Branches</strong> - Any branch that introduces changes like a new feature, a
|
||||
@@ -185,11 +194,11 @@ and a git tag named according to the new version string placed on said commit.</
|
||||
<li><strong>Maintenance Release</strong> - Just like a regular release, except the version bump
|
||||
commit and release tag are on a maintenance branch instead of the master
|
||||
branch.</li>
|
||||
</ul> </section> <!-- Main specification --> <section id="specification" data-astro-cid-6lwcykzv> <h2 data-astro-cid-6lwcykzv>Git Common-Flow Specification</h2> <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
</ul> </section> <!-- Main specification --> <section id="specification"> <h2>Specification</h2> <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in <a href="https://tools.ietf.org/html/rfc2119">RFC 2119</a>.</p>
|
||||
<ol>
|
||||
<li>The Master Branch
|
||||
<li id="spec-the-master-branch">The Master Branch
|
||||
<ol>
|
||||
<li>A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".</li>
|
||||
@@ -201,7 +210,7 @@ release/production" state to reduce the friction of creating a new
|
||||
release.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Changes
|
||||
<li id="spec-changes">Changes
|
||||
<ol>
|
||||
<li>Changes MUST be performed on a separate branch that SHOULD be referred to
|
||||
as a "change branch". All change branches MUST have descriptive names. It
|
||||
@@ -230,7 +239,7 @@ others, it is RECOMMENDED you do this by creating a pull request and
|
||||
discuss the changes with others there.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Git Best Practices
|
||||
<li id="spec-git-best-practices">Git Best Practices
|
||||
<ol>
|
||||
<li>All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
@@ -251,7 +260,7 @@ allows one to revert a merge by reverting a single merge commit, and creates
|
||||
a merge commit to mark the integration of the branch with master.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Versioning
|
||||
<li id="spec-versioning">Versioning
|
||||
<ol>
|
||||
<li>The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
@@ -264,7 +273,7 @@ but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Releases
|
||||
<li id="spec-releases">Releases
|
||||
<ol>
|
||||
<li>To create a new release, you MUST create a "version bump" commit directly
|
||||
on the master branch which changes the hard-coded version value of the
|
||||
@@ -285,7 +294,7 @@ of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Bug Fixes & Rollback
|
||||
<li id="spec-bug-fixes-rollback">Bug Fixes & Rollback
|
||||
<ol>
|
||||
<li>You MUST NOT under any circumstances force push to the master branch.</li>
|
||||
<li>If a change branch which has been merged in to the master branch is found
|
||||
@@ -298,7 +307,7 @@ merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Maintenance Releases
|
||||
<li id="spec-maintenance-releases">Maintenance Releases
|
||||
<ol>
|
||||
<li>Any branch that has a name starting with "stable-" SHOULD be referred to
|
||||
as a "maintenance branch".</li>
|
||||
@@ -325,17 +334,10 @@ into the master branch, that work should have happened against the master
|
||||
branch in the first place.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol> </section> </article> </div> </div> </div> </section> <section id="faq" class="faq-section py-20 sm:py-28" data-astro-cid-hqz3ghsx> <div class="section-container" data-astro-cid-hqz3ghsx> <div class="max-w-3xl mx-auto" data-astro-cid-hqz3ghsx> <!-- Section header --> <div class="mb-12 text-center" data-astro-cid-hqz3ghsx> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-hqz3ghsx>FAQ</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-hqz3ghsx>
|
||||
Common questions about Git Common-Flow
|
||||
</p> </div> <!-- FAQ Items --> <div class="space-y-0" data-astro-cid-hqz3ghsx> </div> </div> </div> </section> <script type="module">function s(){const r=document.querySelectorAll("[data-faq-item]");r.forEach(t=>{const e=t.querySelector("[data-faq-trigger]"),o=t.querySelector("[data-faq-content]"),i=t.querySelector("[data-faq-icon]");!e||!o||!i||e.addEventListener("click",()=>{const c=e.getAttribute("aria-expanded")==="true";r.forEach(a=>{if(a!==t){const d=a.querySelector("[data-faq-trigger]"),l=a.querySelector("[data-faq-content]"),f=a.querySelector("[data-faq-icon]");d?.setAttribute("aria-expanded","false"),l?.classList.add("hidden"),f?.classList.remove("rotate-180")}}),e.setAttribute("aria-expanded",c?"false":"true"),o.classList.toggle("hidden",c),i.classList.toggle("rotate-180",!c)})});const n=r[0]?.querySelector("[data-faq-trigger]");n&&n.click()}s();document.addEventListener("astro:after-swap",s);</script> </main> <footer class="py-8 text-center text-sm
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"> <div class="section-container"> <p>
|
||||
Git Common-Flow is authored by
|
||||
<a href="https://jimeh.me/" class="hover:text-[var(--color-accent)]" target="_blank" rel="noopener noreferrer">
|
||||
Jim Myhrberg
|
||||
</a> </p> <p class="mt-2"> <a href="https://creativecommons.org/licenses/by/4.0/" class="hover:text-[var(--color-accent)]" target="_blank" rel="noopener noreferrer">
|
||||
CC BY 4.0
|
||||
</a> </p> </div> </footer> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme");e==="dark"||!e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
</ol> </section> </article> </div> </div> </div> </section> <section id="faq" class="py-20 sm:py-28"> <div class="section-container"> <div class="max-w-3xl mx-auto"> <div class="mb-12 text-center"> <h2 class="text-3xl sm:text-4xl mb-4">FAQ</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> Common questions about Git Common-Flow </p> </div> <!-- FAQ Items --> <div class="space-y-0"> </div> </div> </div> </section> <script type="module">function n(){document.querySelectorAll("[data-faq-item]").forEach(r=>{const t=r.querySelector("[data-faq-trigger]"),a=r.querySelector("[data-faq-content]"),s=r.querySelector("[data-faq-icon]");!t||!a||!s||t.addEventListener("click",()=>{const e=t.getAttribute("aria-expanded")==="true";t.setAttribute("aria-expanded",e?"false":"true"),a.classList.toggle("grid-rows-[1fr]",!e),a.classList.toggle("grid-rows-[0fr]",e),s.classList.toggle("rotate-180",!e)})})}n();document.addEventListener("astro:after-swap",n);</script> </main> <footer class="pt-12 pb-6 my-28 text-sm
|
||||
text-gray-500 dark:text-neutral-500
|
||||
border-t border-gray-200 dark:border-neutral-800"> <div class="section-container flex flex-col sm:flex-row
|
||||
sm:justify-between sm:items-center gap-2"> <p>
|
||||
License:
|
||||
<a href="https://creativecommons.org/licenses/by/4.0/" class="hover:text-sky-600" target="_blank" rel="noopener noreferrer"> CC BY 4.0 </a> </p> <p> Git Common-Flow by
|
||||
<a href="https://jimeh.me/" class="hover:text-sky-600" target="_blank" rel="noopener noreferrer"> Jim Myhrberg </a> </p> </div> </footer> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme"),t=window.matchMedia("(prefers-color-scheme: dark)").matches;e==="dark"||e!=="light"&&t?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
@@ -1,169 +1,178 @@
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Git Common-Flow 1.0.0-rc.2"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/1.0.0-rc.2"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Common-Flow 1.0.0-rc.2"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><title>Git Common-Flow 1.0.0-rc.2</title><!-- Fonts - distinctive choices --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><!-- Theme initialization - prevent flash --><script>
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="canonical" href="https://commonflow.org/spec/1.0.0-rc.2/"><title>Git Common-Flow 1.0.0-rc.2 | Git Common-Flow</title><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Git Common-Flow 1.0.0-rc.2 | Git Common-Flow"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/spec/1.0.0-rc.2/"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Common-Flow 1.0.0-rc.2 | Git Common-Flow"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><!-- Favicon --><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/favicon.svg" type="image/svg+xml"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- Prevent flash of wrong theme --><script>
|
||||
(function () {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
const mode = localStorage.getItem("theme");
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
if (mode === "dark" || (mode !== "light" && prefersDark)) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script><link rel="stylesheet" href="/_astro/index.DViPM5fQ.css">
|
||||
<style>select[data-astro-cid-wyud3ywt] option[data-astro-cid-wyud3ywt]{background-color:var(--color-bg-primary);color:var(--color-text-primary)}.dark select[data-astro-cid-wyud3ywt] option[data-astro-cid-wyud3ywt]{background-color:var(--color-dark-bg-primary);color:var(--color-dark-text-primary)}.header-title[data-astro-cid-3ef6ksr2]{color:var(--color-text-primary)}.dark .header-title[data-astro-cid-3ef6ksr2]{color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-x2lc2h5w] p:last-child{margin-bottom:0}.spec-content[data-astro-cid-x2lc2h5w] a{color:var(--color-accent)}.spec-content[data-astro-cid-x2lc2h5w] a:hover{color:var(--color-accent-light)}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar{width:4px}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-track{background:transparent}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.dark #spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-thumb{background:var(--color-dark-border)}.spec-content[data-astro-cid-6lwcykzv]{max-width:var(--content-max-width)}.spec-content[data-astro-cid-6lwcykzv] h2{font-family:var(--font-display);font-size:1.75rem;font-weight:700;margin-top:3rem;margin-bottom:1.5rem;padding-bottom:.75rem;border-bottom:1px solid var(--color-border);color:var(--color-text-primary);scroll-margin-top:calc(var(--header-height) + 2rem)}.dark .spec-content[data-astro-cid-6lwcykzv] h2{border-bottom-color:var(--color-dark-border);color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-6lwcykzv] h2:first-child{margin-top:0}.spec-content[data-astro-cid-6lwcykzv] h3{font-family:var(--font-display);font-size:1.25rem;font-weight:600;margin-top:2rem;margin-bottom:1rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] h3{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] p{margin-bottom:1.25rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] p{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] strong{color:var(--color-text-primary);font-weight:600}.dark .spec-content[data-astro-cid-6lwcykzv] strong{color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-6lwcykzv] ul{margin-bottom:1.25rem;padding-left:1.5rem}.spec-content[data-astro-cid-6lwcykzv] ol{margin-bottom:1.25rem;padding-left:2.5rem;counter-reset:item;list-style:none}.spec-content[data-astro-cid-6lwcykzv] ol>li{counter-increment:item;position:relative}.spec-content[data-astro-cid-6lwcykzv] ol>li:before{content:counters(item,".") ".";position:absolute;left:-2.5rem;width:2rem;text-align:right;font-weight:500;color:var(--color-text-muted)}.dark .spec-content[data-astro-cid-6lwcykzv] ol>li:before{color:var(--color-dark-text-muted)}.spec-content[data-astro-cid-6lwcykzv] li{margin-bottom:.5rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] li{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] a{color:var(--color-accent);text-decoration:none;transition:color .15s ease}.spec-content[data-astro-cid-6lwcykzv] a:hover{color:var(--color-accent-light)}.spec-content[data-astro-cid-6lwcykzv] blockquote{border-left:3px solid var(--color-accent);padding-left:1.5rem;margin:1.5rem 0;color:var(--color-text-muted);font-style:italic}.dark .spec-content[data-astro-cid-6lwcykzv] blockquote{color:var(--color-dark-text-muted)}.spec-content[data-astro-cid-6lwcykzv] img{max-width:100%;height:auto;border-radius:8px;margin:2rem 0}.faq-section[data-astro-cid-hqz3ghsx]{background-color:var(--color-bg-secondary)}.dark .faq-section[data-astro-cid-hqz3ghsx]{background-color:var(--color-dark-bg-secondary)}.spec-content[data-astro-cid-hqz3ghsx] p:last-child{margin-bottom:0}.spec-content[data-astro-cid-hqz3ghsx] ul,.spec-content[data-astro-cid-hqz3ghsx] ol{margin-top:1rem}.spec-content[data-astro-cid-hqz3ghsx] li{color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-hqz3ghsx] li{color:var(--color-dark-text-secondary)}
|
||||
</style></head> <body class="min-h-screen"> <header id="site-header" class="fixed top-0 inset-x-0 z-50 glass border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300" data-astro-cid-3ef6ksr2> <div class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between" data-astro-cid-3ef6ksr2> <!-- Logo / Title --> <a href="#hero" class="header-title flex items-center gap-3 no-underline
|
||||
hover:text-[var(--color-accent)] transition-colors" data-astro-cid-3ef6ksr2> <span class="font-display font-bold text-lg tracking-tight" data-astro-cid-3ef6ksr2>
|
||||
</script><link rel="stylesheet" href="/_astro/index.DF_wxGza.css"></head> <body class="min-h-screen"> <header id="site-header" class="fixed top-0 inset-x-0 z-50 border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300
|
||||
backdrop-blur-xl bg-gray-50/85 dark:bg-neutral-950/85"> <div class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between"> <!-- Logo / Title + Version --> <div class="flex items-center gap-3"> <a href="#hero" class="flex items-center gap-3 no-underline
|
||||
text-gray-950 dark:text-neutral-50
|
||||
hover:text-sky-600 transition-colors"> <span class="font-display font-bold text-lg tracking-tight">
|
||||
Git Common-Flow
|
||||
</span> </a> <!-- Desktop Navigation --> <nav class="hidden md:flex items-center gap-1" data-astro-cid-3ef6ksr2> <a href="#about" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>About</a> <a href="#spec" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>Spec</a> <a href="#faq" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>FAQ</a> </nav> <!-- Right side: Version, Theme, GitHub --> <div class="flex items-center gap-3" data-astro-cid-3ef6ksr2> <div class="version-selector relative" data-astro-cid-wyud3ywt> <select data-version-select class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors" data-astro-cid-wyud3ywt> <option value="1.0.0-rc.5" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.5 </option><option value="1.0.0-rc.4" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.4 </option><option value="1.0.0-rc.3" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.3 </option><option value="1.0.0-rc.2" selected data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.2 </option><option value="1.0.0-rc.1" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.1 </option> </select> <!-- Dropdown arrow --> <svg class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-wyud3ywt> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-wyud3ywt></path> </svg> </div> <script type="module">function t(){document.querySelectorAll("[data-version-select]").forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("change",n=>{const a=n.target.value;window.location.href=`/spec/${a}`}))})}t();document.addEventListener("astro:after-swap",t);</script> <button data-theme-toggle type="button" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200" aria-label="Toggle dark mode"> <!-- Sun icon (shown in dark mode) --> <svg data-sun-icon class="hidden w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <!-- Moon icon (shown in light mode) --> <svg data-moon-icon class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path> </svg> </button> <script type="module">function n(){const c=document.querySelectorAll("[data-theme-toggle]");function o(){const e=localStorage.getItem("theme");return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function r(e){document.querySelectorAll("[data-sun-icon]").forEach(t=>{t.classList.toggle("hidden",!e)}),document.querySelectorAll("[data-moon-icon]").forEach(t=>{t.classList.toggle("hidden",e)})}function a(e){localStorage.setItem("theme",e),document.documentElement.classList.toggle("dark",e==="dark"),r(e==="dark")}const d=o();a(d),c.forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("click",()=>{const t=document.documentElement.classList.contains("dark");a(t?"light":"dark")}))}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",e=>{localStorage.getItem("theme")||a(e.matches?"dark":"light")})}n();document.addEventListener("astro:after-swap",n);</script> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors" aria-label="View on GitHub" data-astro-cid-3ef6ksr2> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" data-astro-cid-3ef6ksr2></path> </svg> </a> <!-- Mobile menu button --> <button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]" aria-label="Toggle menu" data-astro-cid-3ef6ksr2> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-3ef6ksr2></path> </svg> </button> </div> </div> <!-- Mobile Navigation --> <nav id="mobile-nav" class="md:hidden hidden border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-3ef6ksr2> <div class="px-4 py-3 space-y-1" data-astro-cid-3ef6ksr2> <a href="#about" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
About
|
||||
</a> <a href="#spec" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
Spec
|
||||
</a> <a href="#faq" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
FAQ
|
||||
</a> </div> </nav> </header> <script type="module">function d(){const e=document.getElementById("site-header"),o=document.getElementById("hero"),s=document.getElementById("mobile-menu-btn"),r=document.getElementById("mobile-nav");if(!e||!o)return;new IntersectionObserver(([t])=>{t.isIntersecting?(e.classList.add("translate-y-[-100%]"),e.classList.remove("border-[var(--color-border)]"),e.classList.remove("dark:border-[var(--color-dark-border)]")):(e.classList.remove("translate-y-[-100%]"),e.classList.add("border-[var(--color-border)]"),e.classList.add("dark:border-[var(--color-dark-border)]"))},{threshold:0,rootMargin:"-64px 0px 0px 0px"}).observe(o),s&&r&&(s.addEventListener("click",()=>{r.classList.toggle("hidden")}),r.querySelectorAll("a").forEach(t=>{t.addEventListener("click",()=>{r.classList.add("hidden")})}))}d();document.addEventListener("astro:after-swap",d);</script> <main> <section id="hero" class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 py-16 overflow-hidden"> <!-- Background gradient/texture --> <div class="absolute inset-0 bg-gradient-to-b from-[var(--color-bg-secondary)]
|
||||
to-[var(--color-bg-primary)]
|
||||
dark:from-[var(--color-dark-bg-secondary)]
|
||||
dark:to-[var(--color-dark-bg-primary)]"></div> <!-- Subtle grid pattern --> <div class="absolute inset-0 opacity-[0.03] dark:opacity-[0.05]" style="background-image: linear-gradient(var(--color-text-primary) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--color-text-primary) 1px, transparent 1px);
|
||||
background-size: 60px 60px;"></div> <!-- Top bar with version & theme --> <div class="absolute top-0 inset-x-0 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"> <div class="flex items-center gap-3"> <div class="version-selector relative" data-astro-cid-wyud3ywt> <select data-version-select class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors" data-astro-cid-wyud3ywt> <option value="1.0.0-rc.5" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.5 </option><option value="1.0.0-rc.4" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.4 </option><option value="1.0.0-rc.3" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.3 </option><option value="1.0.0-rc.2" selected data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.2 </option><option value="1.0.0-rc.1" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.1 </option> </select> <!-- Dropdown arrow --> <svg class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-wyud3ywt> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-wyud3ywt></path> </svg> </div> </div> <div class="flex items-center gap-2"> <button data-theme-toggle type="button" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200" aria-label="Toggle dark mode"> <!-- Sun icon (shown in dark mode) --> <svg data-sun-icon class="hidden w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <!-- Moon icon (shown in light mode) --> <svg data-moon-icon class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path> </svg> </button> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-white/50 dark:hover:bg-white/10
|
||||
transition-colors" aria-label="View on GitHub"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path> </svg> </a> </div> </div> <!-- Main content --> <div class="relative z-10 w-full max-w-4xl mx-auto text-center"> <!-- Title --> <h1 class="animate-fade-in-up mb-4
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]">
|
||||
</span> </a> <div class="hidden md:block"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.2</span> <svg width="1em" height="1em" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <symbol id="ai:heroicons:chevron-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m19.5 8.25l-7.5 7.5l-7.5-7.5"/></symbol><use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.1 </a> </div> </div> <script type="module">function c(){document.querySelectorAll("[data-version-selector]").forEach(e=>{if(e.dataset.initialized)return;e.dataset.initialized="true";const t=e.querySelector("[data-version-trigger]"),a=e.querySelector("[data-version-dropdown]"),n=e.querySelector("[data-arrow-icon]");if(!t||!a)return;const l=()=>{a.dataset.open="true",t.setAttribute("aria-expanded","true"),n&&(n.style.transform="rotate(180deg)")},o=()=>{delete a.dataset.open,t.setAttribute("aria-expanded","false"),n&&(n.style.transform="")};t.addEventListener("click",r=>{r.stopPropagation();const u=a.dataset.open==="true";document.querySelectorAll("[data-version-dropdown][data-open]").forEach(s=>{delete s.dataset.open;const i=s.previousElementSibling;i?.setAttribute("aria-expanded","false");const d=i?.querySelector("[data-arrow-icon]");d&&(d.style.transform="")}),u?o():l()}),document.addEventListener("click",r=>{e.contains(r.target)||o()}),document.addEventListener("keydown",r=>{r.key==="Escape"&&a.dataset.open==="true"&&(o(),t.focus())})})}c();document.addEventListener("astro:after-swap",c);</script> </div> </div> <!-- Desktop Navigation --> <nav class="hidden md:flex items-center gap-1"> <a href="#about" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="about"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:information-circle"> <symbol id="ai:heroicons:information-circle" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m11.25 11.25l.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9-3.75h.008v.008H12z"/></symbol><use href="#ai:heroicons:information-circle"></use> </svg> About </a><a href="#spec" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="spec"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:document-text"> <symbol id="ai:heroicons:document-text" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9"/></symbol><use href="#ai:heroicons:document-text"></use> </svg> Spec </a><a href="#faq" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="faq"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:question-mark-circle"> <symbol id="ai:heroicons:question-mark-circle" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/></symbol><use href="#ai:heroicons:question-mark-circle"></use> </svg> FAQ </a> </nav> <!-- Right side: Theme, GitHub --> <div class="flex items-center gap-3"> <div class="relative group"> <button data-theme-toggle type="button" class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle theme"> <svg width="1em" height="1em" data-theme-icon="light" class="hidden w-5 h-5" data-icon="heroicons:sun"> <symbol id="ai:heroicons:sun" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0a3.75 3.75 0 0 1 7.5 0"/></symbol><use href="#ai:heroicons:sun"></use> </svg> <svg width="1em" height="1em" data-theme-icon="dark" class="hidden w-5 h-5" data-icon="heroicons:moon"> <symbol id="ai:heroicons:moon" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21.752 15.002A9.7 9.7 0 0 1 18 15.75A9.75 9.75 0 0 1 8.25 6c0-1.33.266-2.597.748-3.752A9.75 9.75 0 0 0 3 11.25A9.75 9.75 0 0 0 12.75 21a9.75 9.75 0 0 0 9.002-5.998"/></symbol><use href="#ai:heroicons:moon"></use> </svg> <svg width="1em" height="1em" data-theme-icon="auto" class="hidden w-5 h-5" data-icon="heroicons:computer-desktop"> <symbol id="ai:heroicons:computer-desktop" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25m18 0A2.25 2.25 0 0 0 18.75 3H5.25A2.25 2.25 0 0 0 3 5.25m18 0V12a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 12V5.25"/></symbol><use href="#ai:heroicons:computer-desktop"></use> </svg> </button> <!-- Tooltip --> <div class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"> <span data-tooltip-text="light" class="hidden">Light</span> <span data-tooltip-text="dark" class="hidden">Dark</span> <span data-tooltip-text="auto" class="hidden">System</span> </div> </div> <script type="module">function r(){const c=document.querySelectorAll("[data-theme-toggle]");function n(){const e=localStorage.getItem("theme");return e==="dark"||e==="light"||e==="auto"?e:"auto"}function i(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function d(e){return e==="auto"?i():e}function s(e){document.querySelectorAll("[data-theme-icon]").forEach(t=>{const a=t.dataset.themeIcon;t.classList.toggle("hidden",a!==e)}),document.querySelectorAll("[data-tooltip-text]").forEach(t=>{const a=t.dataset.tooltipText;t.classList.toggle("hidden",a!==e)})}function o(e){d(e)==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark"),s(e)}function u(e){localStorage.setItem("theme",e),o(e)}function l(){const e=n();return e==="light"?"dark":e==="dark"?"auto":"light"}const f=n();o(f),c.forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("click",()=>{u(l())}))}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{n()==="auto"&&o("auto")})}r();document.addEventListener("astro:after-swap",r);</script> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="View on GitHub"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="simple-icons:github"> <symbol id="ai:simple-icons:github" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></symbol><use href="#ai:simple-icons:github"></use> </svg> </a> <!-- Mobile menu button --> <button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle menu"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:bars-3"> <symbol id="ai:heroicons:bars-3" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"/></symbol><use href="#ai:heroicons:bars-3"></use> </svg> </button> </div> </div> <!-- Mobile Navigation --> <nav id="mobile-nav" class="md:hidden hidden border-t border-gray-200 dark:border-neutral-800"> <div class="px-4 py-3 space-y-1 text-center"> <div class="py-2 flex justify-center"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.2</span> <svg width="1em" height="1em" viewBox="0 0 24 24" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.1 </a> </div> </div> </div> <a href="#about" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="about"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:information-circle"> <use href="#ai:heroicons:information-circle"></use> </svg> About </a><a href="#spec" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="spec"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:document-text"> <use href="#ai:heroicons:document-text"></use> </svg> Spec </a><a href="#faq" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="faq"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:question-mark-circle"> <use href="#ai:heroicons:question-mark-circle"></use> </svg> FAQ </a> </div> </nav> </header> <script type="module" src="/_astro/Header.astro_astro_type_script_index_0_lang.ClIJVJFM.js"></script> <main> <section id="hero" class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 pt-16 pb-24 overflow-hidden"> <!-- Background gradient/texture --> <div class="absolute inset-0 bg-gradient-to-b
|
||||
from-gray-100 to-gray-50
|
||||
dark:from-neutral-900 dark:to-neutral-950"></div> <!-- Subtle grid pattern with fade --> <div class="absolute inset-0 opacity-[0.06] dark:opacity-[0.12]
|
||||
bg-[linear-gradient(theme(colors.gray.950)_1px,transparent_1px),linear-gradient(90deg,theme(colors.gray.950)_1px,transparent_1px)]
|
||||
dark:bg-[linear-gradient(theme(colors.neutral.600)_1px,transparent_1px),linear-gradient(90deg,theme(colors.neutral.600)_1px,transparent_1px)]
|
||||
bg-[size:60px_60px] bg-center
|
||||
[-webkit-mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]
|
||||
[mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]"></div> <!-- Top bar with version & theme --> <div class="absolute top-0 inset-x-0 z-20 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"> <div class="flex items-center gap-3"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.2</span> <svg width="1em" height="1em" viewBox="0 0 24 24" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.1 </a> </div> </div> </div> <div class="flex items-center gap-2"> <div class="relative group"> <button data-theme-toggle type="button" class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle theme"> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="light" class="hidden w-5 h-5" data-icon="heroicons:sun"> <use href="#ai:heroicons:sun"></use> </svg> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="dark" class="hidden w-5 h-5" data-icon="heroicons:moon"> <use href="#ai:heroicons:moon"></use> </svg> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="auto" class="hidden w-5 h-5" data-icon="heroicons:computer-desktop"> <use href="#ai:heroicons:computer-desktop"></use> </svg> </button> <!-- Tooltip --> <div class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"> <span data-tooltip-text="light" class="hidden">Light</span> <span data-tooltip-text="dark" class="hidden">Dark</span> <span data-tooltip-text="auto" class="hidden">System</span> </div> </div> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-white/50 dark:hover:bg-neutral-800/50" aria-label="View on GitHub"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-5 h-5" data-icon="simple-icons:github"> <use href="#ai:simple-icons:github"></use> </svg> </a> </div> </div> <!-- Main content --> <div class="relative z-10 w-full max-w-4xl mx-auto text-center"> <!-- Title --> <h1 class="animate-fade-in-up mb-4
|
||||
text-gray-950 dark:text-neutral-50">
|
||||
Git Common-Flow
|
||||
</h1> <!-- Tagline --> <p class="animate-fade-in-up delay-100
|
||||
text-lg sm:text-xl max-w-2xl mx-auto mb-8
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]">
|
||||
text-gray-600 dark:text-neutral-400">
|
||||
A sensible git workflow for teams who ship
|
||||
</p> <!-- Version badge --> <div class="animate-fade-in-up delay-200 mb-10"> <span class="version-badge">v1.0.0-rc.2</span> </div> <!-- SVG Diagram --> <div class="animate-fade-in-up delay-300
|
||||
</p> <!-- Version badge --> <div class="animate-fade-in-up delay-200 mb-10"> <span class="inline-flex items-center px-3 py-1 font-mono text-xs font-medium
|
||||
rounded-full border
|
||||
bg-gray-100 border-gray-200 text-gray-500
|
||||
dark:bg-neutral-800/50 dark:border-neutral-700 dark:text-neutral-400">
|
||||
v1.0.0-rc.2 </span> </div> <!-- SVG Diagram --> <div class="animate-fade-in-up delay-300
|
||||
relative mx-auto mb-12 p-4 sm:p-8
|
||||
bg-white dark:bg-[var(--color-dark-bg-secondary)]
|
||||
bg-white dark:bg-neutral-900
|
||||
rounded-2xl shadow-lg dark:shadow-none
|
||||
border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"> <img src="/spec/1.0.0-rc.2.svg" alt="Git Common-Flow diagram" class="w-full h-auto max-w-3xl mx-auto
|
||||
border border-gray-200 dark:border-neutral-800"> <img src="/spec/1.0.0-rc.2.svg" alt="Git Common-Flow diagram" class="w-full h-auto max-w-3xl mx-auto
|
||||
dark:invert dark:hue-rotate-180 dark:contrast-90"> </div> <!-- Navigation links --> <nav class="animate-fade-in-up delay-400
|
||||
flex flex-wrap items-center justify-center gap-4"> <a href="#about" class="btn btn-ghost">About</a> <a href="#spec" class="btn btn-primary">Read the Spec</a> <a href="#faq" class="btn btn-ghost">FAQ</a> </nav> </div> <!-- Scroll indicator --> <a href="#about" class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
flex flex-wrap items-center justify-center gap-4"> <a href="#about" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50">
|
||||
About
|
||||
</a> <a href="#spec" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
bg-sky-600 text-white
|
||||
hover:bg-sky-500 hover:-translate-y-0.5 hover:shadow-md">
|
||||
Read the Spec
|
||||
</a> <a href="#faq" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50">
|
||||
FAQ
|
||||
</a> </nav> </div> <!-- Scroll indicator --> <a href="#about" class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
animate-fade-in delay-700
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-accent)] transition-colors" aria-label="Scroll to content"> <svg class="w-6 h-6 animate-bounce-subtle" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"></path> </svg> </a> </section> <section id="about" class="py-20 sm:py-28" data-astro-cid-x2lc2h5w> <div class="section-container" data-astro-cid-x2lc2h5w> <div class="max-w-3xl mx-auto" data-astro-cid-x2lc2h5w> <!-- Section header --> <div class="mb-12 text-center" data-astro-cid-x2lc2h5w> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-x2lc2h5w>About Common-Flow</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w>
|
||||
A practical git workflow that combines the best of GitHub Flow with
|
||||
versioned releases
|
||||
</p> </div> <!-- Introduction --> <div class="prose-spec mb-12" data-astro-cid-x2lc2h5w> <div class="spec-content" data-astro-cid-x2lc2h5w></div> </div> <!-- Summary as feature cards --> <div class="mb-16" data-astro-cid-x2lc2h5w> <h3 class="text-xl font-display font-semibold mb-6
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]" data-astro-cid-x2lc2h5w>
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-sky-600 transition-colors" aria-label="Scroll to content"> <svg width="1em" height="1em" class="w-6 h-6 animate-bounce-subtle" data-icon="heroicons:arrow-down"> <symbol id="ai:heroicons:arrow-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3"/></symbol><use href="#ai:heroicons:arrow-down"></use> </svg> </a> </section> <section id="about" class="py-20 sm:py-28"> <div class="section-container"> <div class="max-w-3xl mx-auto"> <div class="mb-12 text-center"> <h2 class="text-3xl sm:text-4xl mb-4">About Common-Flow</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> A practical git workflow that combines the best of GitHub Flow with versioned releases </p> </div> <!-- Introduction --> <div class="prose-spec mb-12"></div> <!-- Summary as feature cards --> <div class="mb-16"> <h3 class="text-xl font-display font-semibold mb-6
|
||||
text-gray-950 dark:text-neutral-50">
|
||||
Key Principles
|
||||
</h3> <div class="spec-content prose-spec" data-astro-cid-x2lc2h5w><p>Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
</h3> <div class="prose-spec"><p>Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
the <a href="http://scottchacon.com/2011/08/31/github-flow.html">original variant</a>
|
||||
of <a href="https://guides.github.com/introduction/flow/">GitHub Flow</a>, while taking
|
||||
into account how a lot of open source projects use git.</p>
|
||||
<p>TL;DR: Common-Flow is basically GitHub Flow with the addition of versioned
|
||||
releases, maintenance releases for old versions, and without the requirement to
|
||||
deploy to production all the time.</p></div> </div> <!-- Author & License --> <div class="pt-8 border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-x2lc2h5w> <div class="grid sm:grid-cols-2 gap-8" data-astro-cid-x2lc2h5w> <div data-astro-cid-x2lc2h5w> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-x2lc2h5w>
|
||||
Author
|
||||
</h4> <div class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w><p>The Git Common-Flow specification is authored
|
||||
by <a href="http://jimeh.me">Jim Myhrberg</a>.</p>
|
||||
<p>If you'd like to leave feedback,
|
||||
please <a href="https://github.com/jimeh/common-flow/issues">open an issue on GitHub</a>.</p></div> </div> <div data-astro-cid-x2lc2h5w> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-x2lc2h5w>
|
||||
deploy to production all the time.</p></div> </div> <!-- Feedback & License --> <div class="pt-8 border-t border-gray-200 dark:border-neutral-800"> <div class="grid sm:grid-cols-2 gap-8"> <div> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Feedback
|
||||
</h4> <p class="text-gray-600 dark:text-neutral-400">
|
||||
Please <a href="https://github.com/jimeh/common-flow/issues" class="text-sky-600 hover:text-sky-400" target="_blank" rel="noopener noreferrer">open an issue on GitHub</a>.
|
||||
</p> </div> <div> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
License
|
||||
</h4> <div class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w><p><a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons - CC BY 3.0</a></p></div> </div> </div> </div> </div> </div> </section> <section id="spec" class="py-20 sm:py-28" data-astro-cid-6lwcykzv> <div class="section-container" data-astro-cid-6lwcykzv> <!-- Section header --> <div class="max-w-3xl mx-auto mb-12 text-center" data-astro-cid-6lwcykzv> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-6lwcykzv>The Specification</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-6lwcykzv>
|
||||
The complete Git Common-Flow specification
|
||||
</p> </div> <!-- Content with sidebar --> <div class="lg:flex lg:gap-8" data-astro-cid-6lwcykzv> <!-- Sidebar --> <div class="lg:w-64 lg:flex-shrink-0" data-astro-cid-6lwcykzv> <aside id="spec-sidebar" class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
</h4> <div class="text-gray-600 dark:text-neutral-400"><p><a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons - CC BY 3.0</a></p></div> </div> </div> </div> </div> </div> </section> <section id="spec" class="py-20 sm:py-28"> <div class="section-container"> <div class="mb-12 text-center max-w-3xl mx-auto"> <h2 class="text-3xl sm:text-4xl mb-4">The Specification</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> The complete Git Common-Flow specification </p> </div> <!-- Content with sidebar --> <div class="lg:flex lg:gap-8"> <!-- Sidebar --> <div class="lg:w-64 lg:flex-shrink-0"> <aside id="spec-sidebar" class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
lg:max-h-[calc(100vh-8rem)] lg:overflow-y-auto
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-lfaoh65k> <nav class="space-y-1 py-2" data-astro-cid-lfaoh65k> <div class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-lfaoh65k>
|
||||
On This Page
|
||||
</div> <a href="#summary" class="sidebar-link " data-sidebar-link data-section-id="summary" data-astro-cid-lfaoh65k> Summary </a><a href="#terminology" class="sidebar-link " data-sidebar-link data-section-id="terminology" data-astro-cid-lfaoh65k> Terminology </a><a href="#specification" class="sidebar-link " data-sidebar-link data-section-id="specification" data-astro-cid-lfaoh65k> Specification </a><a href="#spec-tldr" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-tldr" data-astro-cid-lfaoh65k> TL;DR </a><a href="#spec-the-master-branch" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-the-master-branch" data-astro-cid-lfaoh65k> The Master Branch </a><a href="#spec-change-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-change-branches" data-astro-cid-lfaoh65k> Change Branches </a><a href="#spec-pull-requests" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-pull-requests" data-astro-cid-lfaoh65k> Pull Requests </a><a href="#spec-versioning" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-versioning" data-astro-cid-lfaoh65k> Versioning </a><a href="#spec-releases" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-releases" data-astro-cid-lfaoh65k> Releases </a><a href="#spec-short-term-release-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-short-term-release-branches" data-astro-cid-lfaoh65k> Short-Term Release Branches </a><a href="#spec-long-term-release-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-long-term-release-branches" data-astro-cid-lfaoh65k> Long-term Release Branches </a><a href="#spec-bug-fixes-rollback" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-bug-fixes-rollback" data-astro-cid-lfaoh65k> Bug Fixes & Rollback </a><a href="#spec-git-best-practices" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-git-best-practices" data-astro-cid-lfaoh65k> Git Best Practices </a> </nav> </aside> <!-- Mobile floating button --> <button id="spec-toc-toggle" class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-gray-200 dark:border-neutral-800"> <nav class="space-y-1 py-2"> <div class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Table of Contents
|
||||
</div> <a href="#terminology" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-sidebar-link data-section-id="terminology"> <span>Terminology</span> </a><a href="#specification" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-sidebar-link data-section-id="specification"> <span>Specification</span> </a><a href="#spec-the-master-branch" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-the-master-branch"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 1. </span> <span>The Master Branch</span> </a><a href="#spec-change-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-change-branches"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 2. </span> <span>Change Branches</span> </a><a href="#spec-pull-requests" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-pull-requests"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 3. </span> <span>Pull Requests</span> </a><a href="#spec-versioning" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-versioning"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 4. </span> <span>Versioning</span> </a><a href="#spec-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-releases"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 5. </span> <span>Releases</span> </a><a href="#spec-release-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-release-branches"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 6. </span> <span>Release Branches</span> </a><a href="#spec-bug-fixes-rollback" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-bug-fixes-rollback"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 7. </span> <span>Bug Fixes & Rollback</span> </a><a href="#spec-git-best-practices" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-git-best-practices"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 8. </span> <span>Git Best Practices</span> </a> </nav> </aside> <!-- Mobile floating button --> <button id="spec-toc-toggle" class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
w-12 h-12 rounded-full shadow-lg
|
||||
bg-[var(--color-accent)] text-white
|
||||
bg-sky-600 text-white
|
||||
flex items-center justify-center
|
||||
hover:bg-[var(--color-accent-light)]
|
||||
transition-all duration-200" aria-label="Jump to section" data-astro-cid-lfaoh65k> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-lfaoh65k> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" data-astro-cid-lfaoh65k></path> </svg> </button> <!-- Mobile TOC drawer --> <div id="spec-toc-drawer" class="lg:hidden fixed inset-0 z-50 hidden" data-toc-drawer data-astro-cid-lfaoh65k> <!-- Backdrop --> <div class="absolute inset-0 bg-black/50" data-toc-backdrop data-astro-cid-lfaoh65k></div> <!-- Drawer --> <div class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-[var(--color-bg-primary)] dark:bg-[var(--color-dark-bg-primary)]
|
||||
rounded-t-2xl shadow-xl p-6" data-astro-cid-lfaoh65k> <div class="flex items-center justify-between mb-4" data-astro-cid-lfaoh65k> <span class="text-sm font-semibold uppercase tracking-wider
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-lfaoh65k>
|
||||
hover:bg-sky-500
|
||||
transition-all duration-200" aria-label="Jump to section"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:bars-3-bottom-left"> <symbol id="ai:heroicons:bars-3-bottom-left" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12"/></symbol><use href="#ai:heroicons:bars-3-bottom-left"></use> </svg> </button> <!-- Mobile TOC drawer --> <div id="spec-toc-drawer" class="lg:hidden fixed inset-0 z-50 hidden" data-toc-drawer> <!-- Backdrop --> <div class="absolute inset-0 bg-black/50" data-toc-backdrop></div> <!-- Drawer --> <div class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-gray-50 dark:bg-neutral-950
|
||||
rounded-t-2xl shadow-xl p-6"> <div class="flex items-center justify-between mb-4"> <span class="text-sm font-semibold uppercase tracking-wider
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Jump to Section
|
||||
</span> <button class="p-2 rounded-lg hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]" data-toc-close aria-label="Close" data-astro-cid-lfaoh65k> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-lfaoh65k> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" data-astro-cid-lfaoh65k></path> </svg> </button> </div> <nav class="space-y-1" data-astro-cid-lfaoh65k> <a href="#summary" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Summary </a><a href="#terminology" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Terminology </a><a href="#specification" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Specification </a><a href="#spec-tldr" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> TL;DR </a><a href="#spec-the-master-branch" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> The Master Branch </a><a href="#spec-change-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Change Branches </a><a href="#spec-pull-requests" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Pull Requests </a><a href="#spec-versioning" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Versioning </a><a href="#spec-releases" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Releases </a><a href="#spec-short-term-release-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Short-Term Release Branches </a><a href="#spec-long-term-release-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Long-term Release Branches </a><a href="#spec-bug-fixes-rollback" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Bug Fixes & Rollback </a><a href="#spec-git-best-practices" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Git Best Practices </a> </nav> </div> </div> <script type="module">function l(){const r=document.querySelectorAll("[data-sidebar-link]"),d=new Map;r.forEach(e=>{const t=e.getAttribute("data-section-id");if(t){const o=document.getElementById(t);o&&d.set(t,o)}});const g=new IntersectionObserver(e=>{e.forEach(t=>{if(t.isIntersecting){const o=t.target.getAttribute("id");r.forEach(a=>{const E=a.getAttribute("data-section-id");a.classList.toggle("active",E===o)})}})},{rootMargin:"-20% 0% -60% 0%",threshold:0});d.forEach(e=>g.observe(e));const n=document.getElementById("spec-toc-toggle"),c=document.getElementById("spec-toc-drawer"),u=c?.querySelector("[data-toc-backdrop]"),b=c?.querySelector("[data-toc-close]"),v=c?.querySelectorAll("[data-toc-link]");function f(){c?.classList.remove("hidden"),document.body.style.overflow="hidden"}function s(){c?.classList.add("hidden"),document.body.style.overflow=""}n?.addEventListener("click",f),u?.addEventListener("click",s),b?.addEventListener("click",s),v?.forEach(e=>{e.addEventListener("click",s)});const i=document.getElementById("spec");i&&n&&new IntersectionObserver(([t])=>{n.classList.toggle("hidden",!t.isIntersecting)},{threshold:0}).observe(i)}l();document.addEventListener("astro:after-swap",l);</script> </div> <!-- Main content --> <div class="flex-1 min-w-0" data-astro-cid-6lwcykzv> <article class="prose-spec spec-content" data-astro-cid-6lwcykzv> <!-- Terminology --> <section id="terminology" data-astro-cid-6lwcykzv> <h2 data-astro-cid-6lwcykzv>Terminology</h2> <ul>
|
||||
</span> <button class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800" data-toc-close aria-label="Close"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:x-mark"> <symbol id="ai:heroicons:x-mark" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M6 18L18 6M6 6l12 12"/></symbol><use href="#ai:heroicons:x-mark"></use> </svg> </button> </div> <nav class="space-y-1"> <a href="#terminology" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-toc-link> <span>Terminology</span> </a><a href="#specification" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-toc-link> <span>Specification</span> </a><a href="#spec-the-master-branch" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 1. </span> <span>The Master Branch</span> </a><a href="#spec-change-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 2. </span> <span>Change Branches</span> </a><a href="#spec-pull-requests" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 3. </span> <span>Pull Requests</span> </a><a href="#spec-versioning" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 4. </span> <span>Versioning</span> </a><a href="#spec-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 5. </span> <span>Releases</span> </a><a href="#spec-release-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 6. </span> <span>Release Branches</span> </a><a href="#spec-bug-fixes-rollback" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 7. </span> <span>Bug Fixes & Rollback</span> </a><a href="#spec-git-best-practices" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 8. </span> <span>Git Best Practices</span> </a> </nav> </div> </div> <script type="module" src="/_astro/SpecSidebar.astro_astro_type_script_index_0_lang.BQBj5HuJ.js"></script> </div> <!-- Main content --> <div class="flex-1 min-w-0"> <article class="prose-spec"> <!-- Terminology --> <section id="terminology"> <h2>Terminology</h2> <ul>
|
||||
<li><strong>Master Branch</strong> - Must always have passing tests, is considered bleeding
|
||||
edge, and must be named <code>master</code>.</li>
|
||||
<li><strong>Change Branches</strong> - Any branch that introduces changes like a new feature, a
|
||||
@@ -180,11 +189,11 @@ its merge target, allowing others to review, discuss and approve the changes.</l
|
||||
to the new version string placed on said commit.</li>
|
||||
<li><strong>Release Branches</strong> - Used both for short-term preparations of a release, and
|
||||
also for long-term maintenance of older version.</li>
|
||||
</ul> </section> <!-- Main specification --> <section id="specification" data-astro-cid-6lwcykzv> <h2 data-astro-cid-6lwcykzv>Git Common-Flow Specification</h2> <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
</ul> </section> <!-- Main specification --> <section id="specification"> <h2>Specification</h2> <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in <a href="https://tools.ietf.org/html/rfc2119">RFC 2119</a>.</p>
|
||||
<ol>
|
||||
<li>The Master Branch
|
||||
<li id="spec-the-master-branch">The Master Branch
|
||||
<ol>
|
||||
<li>A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".</li>
|
||||
@@ -196,7 +205,7 @@ release/production" state to reduce any friction with creating a new
|
||||
release.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Change Branches
|
||||
<li id="spec-change-branches">Change Branches
|
||||
<ol>
|
||||
<li>Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches". All change
|
||||
@@ -218,7 +227,7 @@ the change branch to the remote server. This will require you to do a
|
||||
force push, and you SHOULD use the "--force-with-lease" git push option.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Pull Requests
|
||||
<li id="spec-pull-requests">Pull Requests
|
||||
<ol>
|
||||
<li>To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent) so others can review and approve your changes.</li>
|
||||
@@ -231,7 +240,7 @@ others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Versioning
|
||||
<li id="spec-versioning">Versioning
|
||||
<ol>
|
||||
<li>The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
@@ -244,7 +253,7 @@ but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Releases
|
||||
<li id="spec-releases">Releases
|
||||
<ol>
|
||||
<li>To create a new release, you MUST create a "version bump" commit which
|
||||
changes the hard-coded version string of the project. The version bump
|
||||
@@ -269,7 +278,7 @@ of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Release Branches
|
||||
<li id="spec-release-branches">Release Branches
|
||||
<ol>
|
||||
<li>Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".</li>
|
||||
@@ -321,7 +330,7 @@ release tag. The security fix release will then end up being version
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Bug Fixes & Rollback
|
||||
<li id="spec-bug-fixes-rollback">Bug Fixes & Rollback
|
||||
<ol>
|
||||
<li>You MUST NOT under any circumstances force push to the master branch.</li>
|
||||
<li>If a change branch which has been merged into the master branch is found
|
||||
@@ -334,7 +343,7 @@ merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Git Best Practices
|
||||
<li id="spec-git-best-practices">Git Best Practices
|
||||
<ol>
|
||||
<li>All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
@@ -359,17 +368,10 @@ and creates a merge commit to mark the integration of the branch with
|
||||
master.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol> </section> </article> </div> </div> </div> </section> <section id="faq" class="faq-section py-20 sm:py-28" data-astro-cid-hqz3ghsx> <div class="section-container" data-astro-cid-hqz3ghsx> <div class="max-w-3xl mx-auto" data-astro-cid-hqz3ghsx> <!-- Section header --> <div class="mb-12 text-center" data-astro-cid-hqz3ghsx> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-hqz3ghsx>FAQ</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-hqz3ghsx>
|
||||
Common questions about Git Common-Flow
|
||||
</p> </div> <!-- FAQ Items --> <div class="space-y-0" data-astro-cid-hqz3ghsx> </div> </div> </div> </section> <script type="module">function s(){const r=document.querySelectorAll("[data-faq-item]");r.forEach(t=>{const e=t.querySelector("[data-faq-trigger]"),o=t.querySelector("[data-faq-content]"),i=t.querySelector("[data-faq-icon]");!e||!o||!i||e.addEventListener("click",()=>{const c=e.getAttribute("aria-expanded")==="true";r.forEach(a=>{if(a!==t){const d=a.querySelector("[data-faq-trigger]"),l=a.querySelector("[data-faq-content]"),f=a.querySelector("[data-faq-icon]");d?.setAttribute("aria-expanded","false"),l?.classList.add("hidden"),f?.classList.remove("rotate-180")}}),e.setAttribute("aria-expanded",c?"false":"true"),o.classList.toggle("hidden",c),i.classList.toggle("rotate-180",!c)})});const n=r[0]?.querySelector("[data-faq-trigger]");n&&n.click()}s();document.addEventListener("astro:after-swap",s);</script> </main> <footer class="py-8 text-center text-sm
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"> <div class="section-container"> <p>
|
||||
Git Common-Flow is authored by
|
||||
<a href="https://jimeh.me/" class="hover:text-[var(--color-accent)]" target="_blank" rel="noopener noreferrer">
|
||||
Jim Myhrberg
|
||||
</a> </p> <p class="mt-2"> <a href="https://creativecommons.org/licenses/by/4.0/" class="hover:text-[var(--color-accent)]" target="_blank" rel="noopener noreferrer">
|
||||
CC BY 4.0
|
||||
</a> </p> </div> </footer> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme");e==="dark"||!e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
</ol> </section> </article> </div> </div> </div> </section> <section id="faq" class="py-20 sm:py-28"> <div class="section-container"> <div class="max-w-3xl mx-auto"> <div class="mb-12 text-center"> <h2 class="text-3xl sm:text-4xl mb-4">FAQ</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> Common questions about Git Common-Flow </p> </div> <!-- FAQ Items --> <div class="space-y-0"> </div> </div> </div> </section> <script type="module">function n(){document.querySelectorAll("[data-faq-item]").forEach(r=>{const t=r.querySelector("[data-faq-trigger]"),a=r.querySelector("[data-faq-content]"),s=r.querySelector("[data-faq-icon]");!t||!a||!s||t.addEventListener("click",()=>{const e=t.getAttribute("aria-expanded")==="true";t.setAttribute("aria-expanded",e?"false":"true"),a.classList.toggle("grid-rows-[1fr]",!e),a.classList.toggle("grid-rows-[0fr]",e),s.classList.toggle("rotate-180",!e)})})}n();document.addEventListener("astro:after-swap",n);</script> </main> <footer class="pt-12 pb-6 my-28 text-sm
|
||||
text-gray-500 dark:text-neutral-500
|
||||
border-t border-gray-200 dark:border-neutral-800"> <div class="section-container flex flex-col sm:flex-row
|
||||
sm:justify-between sm:items-center gap-2"> <p>
|
||||
License:
|
||||
<a href="https://creativecommons.org/licenses/by/4.0/" class="hover:text-sky-600" target="_blank" rel="noopener noreferrer"> CC BY 4.0 </a> </p> <p> Git Common-Flow by
|
||||
<a href="https://jimeh.me/" class="hover:text-sky-600" target="_blank" rel="noopener noreferrer"> Jim Myhrberg </a> </p> </div> </footer> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme"),t=window.matchMedia("(prefers-color-scheme: dark)").matches;e==="dark"||e!=="light"&&t?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
@@ -1,169 +1,178 @@
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Git Common-Flow 1.0.0-rc.3"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/1.0.0-rc.3"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Common-Flow 1.0.0-rc.3"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><title>Git Common-Flow 1.0.0-rc.3</title><!-- Fonts - distinctive choices --><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"><!-- Favicon --><link rel="icon" type="image/svg+xml" href="/favicon.svg"><!-- Theme initialization - prevent flash --><script>
|
||||
<!DOCTYPE html><html lang="en"> <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="canonical" href="https://commonflow.org/spec/1.0.0-rc.3/"><title>Git Common-Flow 1.0.0-rc.3 | Git Common-Flow</title><meta name="description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta name="author" content="Jim Myhrberg"><!-- Open Graph --><meta property="og:title" content="Git Common-Flow 1.0.0-rc.3 | Git Common-Flow"><meta property="og:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><meta property="og:type" content="website"><meta property="og:url" content="https://commonflow.org/spec/1.0.0-rc.3/"><!-- Twitter --><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Git Common-Flow 1.0.0-rc.3 | Git Common-Flow"><meta name="twitter:description" content="An attempt to gather a sensible selection of the most common usage patterns of git into a single and concise specification."><!-- Favicon --><link rel="icon" href="/favicon.ico" sizes="32x32"><link rel="icon" href="/favicon.svg" type="image/svg+xml"><link rel="apple-touch-icon" href="/apple-touch-icon.png"><!-- Prevent flash of wrong theme --><script>
|
||||
(function () {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
const mode = localStorage.getItem("theme");
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
if (mode === "dark" || (mode !== "light" && prefersDark)) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script><link rel="stylesheet" href="/_astro/index.DViPM5fQ.css">
|
||||
<style>select[data-astro-cid-wyud3ywt] option[data-astro-cid-wyud3ywt]{background-color:var(--color-bg-primary);color:var(--color-text-primary)}.dark select[data-astro-cid-wyud3ywt] option[data-astro-cid-wyud3ywt]{background-color:var(--color-dark-bg-primary);color:var(--color-dark-text-primary)}.header-title[data-astro-cid-3ef6ksr2]{color:var(--color-text-primary)}.dark .header-title[data-astro-cid-3ef6ksr2]{color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-x2lc2h5w] p:last-child{margin-bottom:0}.spec-content[data-astro-cid-x2lc2h5w] a{color:var(--color-accent)}.spec-content[data-astro-cid-x2lc2h5w] a:hover{color:var(--color-accent-light)}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar{width:4px}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-track{background:transparent}#spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:2px}.dark #spec-sidebar[data-astro-cid-lfaoh65k]::-webkit-scrollbar-thumb{background:var(--color-dark-border)}.spec-content[data-astro-cid-6lwcykzv]{max-width:var(--content-max-width)}.spec-content[data-astro-cid-6lwcykzv] h2{font-family:var(--font-display);font-size:1.75rem;font-weight:700;margin-top:3rem;margin-bottom:1.5rem;padding-bottom:.75rem;border-bottom:1px solid var(--color-border);color:var(--color-text-primary);scroll-margin-top:calc(var(--header-height) + 2rem)}.dark .spec-content[data-astro-cid-6lwcykzv] h2{border-bottom-color:var(--color-dark-border);color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-6lwcykzv] h2:first-child{margin-top:0}.spec-content[data-astro-cid-6lwcykzv] h3{font-family:var(--font-display);font-size:1.25rem;font-weight:600;margin-top:2rem;margin-bottom:1rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] h3{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] p{margin-bottom:1.25rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] p{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] strong{color:var(--color-text-primary);font-weight:600}.dark .spec-content[data-astro-cid-6lwcykzv] strong{color:var(--color-dark-text-primary)}.spec-content[data-astro-cid-6lwcykzv] ul{margin-bottom:1.25rem;padding-left:1.5rem}.spec-content[data-astro-cid-6lwcykzv] ol{margin-bottom:1.25rem;padding-left:2.5rem;counter-reset:item;list-style:none}.spec-content[data-astro-cid-6lwcykzv] ol>li{counter-increment:item;position:relative}.spec-content[data-astro-cid-6lwcykzv] ol>li:before{content:counters(item,".") ".";position:absolute;left:-2.5rem;width:2rem;text-align:right;font-weight:500;color:var(--color-text-muted)}.dark .spec-content[data-astro-cid-6lwcykzv] ol>li:before{color:var(--color-dark-text-muted)}.spec-content[data-astro-cid-6lwcykzv] li{margin-bottom:.5rem;color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-6lwcykzv] li{color:var(--color-dark-text-secondary)}.spec-content[data-astro-cid-6lwcykzv] a{color:var(--color-accent);text-decoration:none;transition:color .15s ease}.spec-content[data-astro-cid-6lwcykzv] a:hover{color:var(--color-accent-light)}.spec-content[data-astro-cid-6lwcykzv] blockquote{border-left:3px solid var(--color-accent);padding-left:1.5rem;margin:1.5rem 0;color:var(--color-text-muted);font-style:italic}.dark .spec-content[data-astro-cid-6lwcykzv] blockquote{color:var(--color-dark-text-muted)}.spec-content[data-astro-cid-6lwcykzv] img{max-width:100%;height:auto;border-radius:8px;margin:2rem 0}.faq-section[data-astro-cid-hqz3ghsx]{background-color:var(--color-bg-secondary)}.dark .faq-section[data-astro-cid-hqz3ghsx]{background-color:var(--color-dark-bg-secondary)}.spec-content[data-astro-cid-hqz3ghsx] p:last-child{margin-bottom:0}.spec-content[data-astro-cid-hqz3ghsx] ul,.spec-content[data-astro-cid-hqz3ghsx] ol{margin-top:1rem}.spec-content[data-astro-cid-hqz3ghsx] li{color:var(--color-text-secondary)}.dark .spec-content[data-astro-cid-hqz3ghsx] li{color:var(--color-dark-text-secondary)}
|
||||
</style></head> <body class="min-h-screen"> <header id="site-header" class="fixed top-0 inset-x-0 z-50 glass border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300" data-astro-cid-3ef6ksr2> <div class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between" data-astro-cid-3ef6ksr2> <!-- Logo / Title --> <a href="#hero" class="header-title flex items-center gap-3 no-underline
|
||||
hover:text-[var(--color-accent)] transition-colors" data-astro-cid-3ef6ksr2> <span class="font-display font-bold text-lg tracking-tight" data-astro-cid-3ef6ksr2>
|
||||
</script><link rel="stylesheet" href="/_astro/index.DF_wxGza.css"></head> <body class="min-h-screen"> <header id="site-header" class="fixed top-0 inset-x-0 z-50 border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300
|
||||
backdrop-blur-xl bg-gray-50/85 dark:bg-neutral-950/85"> <div class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between"> <!-- Logo / Title + Version --> <div class="flex items-center gap-3"> <a href="#hero" class="flex items-center gap-3 no-underline
|
||||
text-gray-950 dark:text-neutral-50
|
||||
hover:text-sky-600 transition-colors"> <span class="font-display font-bold text-lg tracking-tight">
|
||||
Git Common-Flow
|
||||
</span> </a> <!-- Desktop Navigation --> <nav class="hidden md:flex items-center gap-1" data-astro-cid-3ef6ksr2> <a href="#about" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>About</a> <a href="#spec" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>Spec</a> <a href="#faq" class="btn btn-ghost text-sm" data-astro-cid-3ef6ksr2>FAQ</a> </nav> <!-- Right side: Version, Theme, GitHub --> <div class="flex items-center gap-3" data-astro-cid-3ef6ksr2> <div class="version-selector relative" data-astro-cid-wyud3ywt> <select data-version-select class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors" data-astro-cid-wyud3ywt> <option value="1.0.0-rc.5" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.5 </option><option value="1.0.0-rc.4" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.4 </option><option value="1.0.0-rc.3" selected data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.3 </option><option value="1.0.0-rc.2" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.2 </option><option value="1.0.0-rc.1" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.1 </option> </select> <!-- Dropdown arrow --> <svg class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-wyud3ywt> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-wyud3ywt></path> </svg> </div> <script type="module">function t(){document.querySelectorAll("[data-version-select]").forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("change",n=>{const a=n.target.value;window.location.href=`/spec/${a}`}))})}t();document.addEventListener("astro:after-swap",t);</script> <button data-theme-toggle type="button" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200" aria-label="Toggle dark mode"> <!-- Sun icon (shown in dark mode) --> <svg data-sun-icon class="hidden w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <!-- Moon icon (shown in light mode) --> <svg data-moon-icon class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path> </svg> </button> <script type="module">function n(){const c=document.querySelectorAll("[data-theme-toggle]");function o(){const e=localStorage.getItem("theme");return e==="dark"||e==="light"?e:window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function r(e){document.querySelectorAll("[data-sun-icon]").forEach(t=>{t.classList.toggle("hidden",!e)}),document.querySelectorAll("[data-moon-icon]").forEach(t=>{t.classList.toggle("hidden",e)})}function a(e){localStorage.setItem("theme",e),document.documentElement.classList.toggle("dark",e==="dark"),r(e==="dark")}const d=o();a(d),c.forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("click",()=>{const t=document.documentElement.classList.contains("dark");a(t?"light":"dark")}))}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",e=>{localStorage.getItem("theme")||a(e.matches?"dark":"light")})}n();document.addEventListener("astro:after-swap",n);</script> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors" aria-label="View on GitHub" data-astro-cid-3ef6ksr2> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" data-astro-cid-3ef6ksr2></path> </svg> </a> <!-- Mobile menu button --> <button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]" aria-label="Toggle menu" data-astro-cid-3ef6ksr2> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-3ef6ksr2></path> </svg> </button> </div> </div> <!-- Mobile Navigation --> <nav id="mobile-nav" class="md:hidden hidden border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-3ef6ksr2> <div class="px-4 py-3 space-y-1" data-astro-cid-3ef6ksr2> <a href="#about" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
About
|
||||
</a> <a href="#spec" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
Spec
|
||||
</a> <a href="#faq" class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]" data-astro-cid-3ef6ksr2>
|
||||
FAQ
|
||||
</a> </div> </nav> </header> <script type="module">function d(){const e=document.getElementById("site-header"),o=document.getElementById("hero"),s=document.getElementById("mobile-menu-btn"),r=document.getElementById("mobile-nav");if(!e||!o)return;new IntersectionObserver(([t])=>{t.isIntersecting?(e.classList.add("translate-y-[-100%]"),e.classList.remove("border-[var(--color-border)]"),e.classList.remove("dark:border-[var(--color-dark-border)]")):(e.classList.remove("translate-y-[-100%]"),e.classList.add("border-[var(--color-border)]"),e.classList.add("dark:border-[var(--color-dark-border)]"))},{threshold:0,rootMargin:"-64px 0px 0px 0px"}).observe(o),s&&r&&(s.addEventListener("click",()=>{r.classList.toggle("hidden")}),r.querySelectorAll("a").forEach(t=>{t.addEventListener("click",()=>{r.classList.add("hidden")})}))}d();document.addEventListener("astro:after-swap",d);</script> <main> <section id="hero" class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 py-16 overflow-hidden"> <!-- Background gradient/texture --> <div class="absolute inset-0 bg-gradient-to-b from-[var(--color-bg-secondary)]
|
||||
to-[var(--color-bg-primary)]
|
||||
dark:from-[var(--color-dark-bg-secondary)]
|
||||
dark:to-[var(--color-dark-bg-primary)]"></div> <!-- Subtle grid pattern --> <div class="absolute inset-0 opacity-[0.03] dark:opacity-[0.05]" style="background-image: linear-gradient(var(--color-text-primary) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--color-text-primary) 1px, transparent 1px);
|
||||
background-size: 60px 60px;"></div> <!-- Top bar with version & theme --> <div class="absolute top-0 inset-x-0 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"> <div class="flex items-center gap-3"> <div class="version-selector relative" data-astro-cid-wyud3ywt> <select data-version-select class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors" data-astro-cid-wyud3ywt> <option value="1.0.0-rc.5" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.5 </option><option value="1.0.0-rc.4" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.4 </option><option value="1.0.0-rc.3" selected data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.3 </option><option value="1.0.0-rc.2" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.2 </option><option value="1.0.0-rc.1" data-astro-cid-wyud3ywt>
|
||||
v1.0.0-rc.1 </option> </select> <!-- Dropdown arrow --> <svg class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-wyud3ywt> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-wyud3ywt></path> </svg> </div> </div> <div class="flex items-center gap-2"> <button data-theme-toggle type="button" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200" aria-label="Toggle dark mode"> <!-- Sun icon (shown in dark mode) --> <svg data-sun-icon class="hidden w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <!-- Moon icon (shown in light mode) --> <svg data-moon-icon class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path> </svg> </button> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-white/50 dark:hover:bg-white/10
|
||||
transition-colors" aria-label="View on GitHub"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path> </svg> </a> </div> </div> <!-- Main content --> <div class="relative z-10 w-full max-w-4xl mx-auto text-center"> <!-- Title --> <h1 class="animate-fade-in-up mb-4
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]">
|
||||
</span> </a> <div class="hidden md:block"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.3</span> <svg width="1em" height="1em" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <symbol id="ai:heroicons:chevron-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m19.5 8.25l-7.5 7.5l-7.5-7.5"/></symbol><use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.1 </a> </div> </div> <script type="module">function c(){document.querySelectorAll("[data-version-selector]").forEach(e=>{if(e.dataset.initialized)return;e.dataset.initialized="true";const t=e.querySelector("[data-version-trigger]"),a=e.querySelector("[data-version-dropdown]"),n=e.querySelector("[data-arrow-icon]");if(!t||!a)return;const l=()=>{a.dataset.open="true",t.setAttribute("aria-expanded","true"),n&&(n.style.transform="rotate(180deg)")},o=()=>{delete a.dataset.open,t.setAttribute("aria-expanded","false"),n&&(n.style.transform="")};t.addEventListener("click",r=>{r.stopPropagation();const u=a.dataset.open==="true";document.querySelectorAll("[data-version-dropdown][data-open]").forEach(s=>{delete s.dataset.open;const i=s.previousElementSibling;i?.setAttribute("aria-expanded","false");const d=i?.querySelector("[data-arrow-icon]");d&&(d.style.transform="")}),u?o():l()}),document.addEventListener("click",r=>{e.contains(r.target)||o()}),document.addEventListener("keydown",r=>{r.key==="Escape"&&a.dataset.open==="true"&&(o(),t.focus())})})}c();document.addEventListener("astro:after-swap",c);</script> </div> </div> <!-- Desktop Navigation --> <nav class="hidden md:flex items-center gap-1"> <a href="#about" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="about"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:information-circle"> <symbol id="ai:heroicons:information-circle" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m11.25 11.25l.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9-3.75h.008v.008H12z"/></symbol><use href="#ai:heroicons:information-circle"></use> </svg> About </a><a href="#spec" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="spec"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:document-text"> <symbol id="ai:heroicons:document-text" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9"/></symbol><use href="#ai:heroicons:document-text"></use> </svg> Spec </a><a href="#faq" class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50" data-nav-link data-section-id="faq"> <svg width="1em" height="1em" class="w-4 h-4" data-icon="heroicons:question-mark-circle"> <symbol id="ai:heroicons:question-mark-circle" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9.879 7.519c1.172-1.025 3.071-1.025 4.243 0c1.171 1.025 1.171 2.687 0 3.712q-.308.268-.67.442c-.746.361-1.452.999-1.452 1.827v.75M21 12a9 9 0 1 1-18 0a9 9 0 0 1 18 0m-9 5.25h.008v.008H12z"/></symbol><use href="#ai:heroicons:question-mark-circle"></use> </svg> FAQ </a> </nav> <!-- Right side: Theme, GitHub --> <div class="flex items-center gap-3"> <div class="relative group"> <button data-theme-toggle type="button" class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle theme"> <svg width="1em" height="1em" data-theme-icon="light" class="hidden w-5 h-5" data-icon="heroicons:sun"> <symbol id="ai:heroicons:sun" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 1 1-7.5 0a3.75 3.75 0 0 1 7.5 0"/></symbol><use href="#ai:heroicons:sun"></use> </svg> <svg width="1em" height="1em" data-theme-icon="dark" class="hidden w-5 h-5" data-icon="heroicons:moon"> <symbol id="ai:heroicons:moon" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M21.752 15.002A9.7 9.7 0 0 1 18 15.75A9.75 9.75 0 0 1 8.25 6c0-1.33.266-2.597.748-3.752A9.75 9.75 0 0 0 3 11.25A9.75 9.75 0 0 0 12.75 21a9.75 9.75 0 0 0 9.002-5.998"/></symbol><use href="#ai:heroicons:moon"></use> </svg> <svg width="1em" height="1em" data-theme-icon="auto" class="hidden w-5 h-5" data-icon="heroicons:computer-desktop"> <symbol id="ai:heroicons:computer-desktop" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25m18 0A2.25 2.25 0 0 0 18.75 3H5.25A2.25 2.25 0 0 0 3 5.25m18 0V12a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 12V5.25"/></symbol><use href="#ai:heroicons:computer-desktop"></use> </svg> </button> <!-- Tooltip --> <div class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"> <span data-tooltip-text="light" class="hidden">Light</span> <span data-tooltip-text="dark" class="hidden">Dark</span> <span data-tooltip-text="auto" class="hidden">System</span> </div> </div> <script type="module">function r(){const c=document.querySelectorAll("[data-theme-toggle]");function n(){const e=localStorage.getItem("theme");return e==="dark"||e==="light"||e==="auto"?e:"auto"}function i(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function d(e){return e==="auto"?i():e}function s(e){document.querySelectorAll("[data-theme-icon]").forEach(t=>{const a=t.dataset.themeIcon;t.classList.toggle("hidden",a!==e)}),document.querySelectorAll("[data-tooltip-text]").forEach(t=>{const a=t.dataset.tooltipText;t.classList.toggle("hidden",a!==e)})}function o(e){d(e)==="dark"?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark"),s(e)}function u(e){localStorage.setItem("theme",e),o(e)}function l(){const e=n();return e==="light"?"dark":e==="dark"?"auto":"light"}const f=n();o(f),c.forEach(e=>{e.dataset.initialized||(e.dataset.initialized="true",e.addEventListener("click",()=>{u(l())}))}),window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",()=>{n()==="auto"&&o("auto")})}r();document.addEventListener("astro:after-swap",r);</script> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="View on GitHub"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="simple-icons:github"> <symbol id="ai:simple-icons:github" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></symbol><use href="#ai:simple-icons:github"></use> </svg> </a> <!-- Mobile menu button --> <button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle menu"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:bars-3"> <symbol id="ai:heroicons:bars-3" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"/></symbol><use href="#ai:heroicons:bars-3"></use> </svg> </button> </div> </div> <!-- Mobile Navigation --> <nav id="mobile-nav" class="md:hidden hidden border-t border-gray-200 dark:border-neutral-800"> <div class="px-4 py-3 space-y-1 text-center"> <div class="py-2 flex justify-center"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.3</span> <svg width="1em" height="1em" viewBox="0 0 24 24" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.1 </a> </div> </div> </div> <a href="#about" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="about"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:information-circle"> <use href="#ai:heroicons:information-circle"></use> </svg> About </a><a href="#spec" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="spec"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:document-text"> <use href="#ai:heroicons:document-text"></use> </svg> Spec </a><a href="#faq" class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600" data-nav-link data-section-id="faq"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-4 h-4" data-icon="heroicons:question-mark-circle"> <use href="#ai:heroicons:question-mark-circle"></use> </svg> FAQ </a> </div> </nav> </header> <script type="module" src="/_astro/Header.astro_astro_type_script_index_0_lang.ClIJVJFM.js"></script> <main> <section id="hero" class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 pt-16 pb-24 overflow-hidden"> <!-- Background gradient/texture --> <div class="absolute inset-0 bg-gradient-to-b
|
||||
from-gray-100 to-gray-50
|
||||
dark:from-neutral-900 dark:to-neutral-950"></div> <!-- Subtle grid pattern with fade --> <div class="absolute inset-0 opacity-[0.06] dark:opacity-[0.12]
|
||||
bg-[linear-gradient(theme(colors.gray.950)_1px,transparent_1px),linear-gradient(90deg,theme(colors.gray.950)_1px,transparent_1px)]
|
||||
dark:bg-[linear-gradient(theme(colors.neutral.600)_1px,transparent_1px),linear-gradient(90deg,theme(colors.neutral.600)_1px,transparent_1px)]
|
||||
bg-[size:60px_60px] bg-center
|
||||
[-webkit-mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]
|
||||
[mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]"></div> <!-- Top bar with version & theme --> <div class="absolute top-0 inset-x-0 z-20 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"> <div class="flex items-center gap-3"> <div class="relative" data-version-selector> <!-- Trigger button --> <button type="button" data-version-trigger aria-haspopup="listbox" aria-expanded="false" class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"> <span>v1.0.0-rc.3</span> <svg width="1em" height="1em" viewBox="0 0 24 24" data-arrow-icon="true" class="w-3.5 h-3.5 transition-transform duration-150" data-icon="heroicons:chevron-down"> <use href="#ai:heroicons:chevron-down"></use> </svg> </button> <!-- Dropdown menu --> <div data-version-dropdown role="listbox" aria-label="Select version" class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"> <a href="/spec/1.0.0-rc.5" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.5 </a><a href="/spec/1.0.0-rc.4" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.4 </a><a href="/spec/1.0.0-rc.3" role="option" aria-selected="true" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50 bg-sky-500/15 dark:bg-sky-500/20 text-sky-600 dark:text-sky-400">
|
||||
v1.0.0-rc.3 </a><a href="/spec/1.0.0-rc.2" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.2 </a><a href="/spec/1.0.0-rc.1" role="option" aria-selected="false" class="block px-3 py-2 font-mono text-sm rounded transition-colors text-gray-600 dark:text-neutral-400 hover:bg-gray-100 dark:hover:bg-neutral-800 hover:text-gray-950 dark:hover:text-neutral-50">
|
||||
v1.0.0-rc.1 </a> </div> </div> </div> <div class="flex items-center gap-2"> <div class="relative group"> <button data-theme-toggle type="button" class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800" aria-label="Toggle theme"> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="light" class="hidden w-5 h-5" data-icon="heroicons:sun"> <use href="#ai:heroicons:sun"></use> </svg> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="dark" class="hidden w-5 h-5" data-icon="heroicons:moon"> <use href="#ai:heroicons:moon"></use> </svg> <svg width="1em" height="1em" viewBox="0 0 24 24" data-theme-icon="auto" class="hidden w-5 h-5" data-icon="heroicons:computer-desktop"> <use href="#ai:heroicons:computer-desktop"></use> </svg> </button> <!-- Tooltip --> <div class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"> <span data-tooltip-text="light" class="hidden">Light</span> <span data-tooltip-text="dark" class="hidden">Dark</span> <span data-tooltip-text="auto" class="hidden">System</span> </div> </div> <a href="https://github.com/jimeh/common-flow" target="_blank" rel="noopener noreferrer" class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-white/50 dark:hover:bg-neutral-800/50" aria-label="View on GitHub"> <svg width="1em" height="1em" viewBox="0 0 24 24" class="w-5 h-5" data-icon="simple-icons:github"> <use href="#ai:simple-icons:github"></use> </svg> </a> </div> </div> <!-- Main content --> <div class="relative z-10 w-full max-w-4xl mx-auto text-center"> <!-- Title --> <h1 class="animate-fade-in-up mb-4
|
||||
text-gray-950 dark:text-neutral-50">
|
||||
Git Common-Flow
|
||||
</h1> <!-- Tagline --> <p class="animate-fade-in-up delay-100
|
||||
text-lg sm:text-xl max-w-2xl mx-auto mb-8
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]">
|
||||
text-gray-600 dark:text-neutral-400">
|
||||
A sensible git workflow for teams who ship
|
||||
</p> <!-- Version badge --> <div class="animate-fade-in-up delay-200 mb-10"> <span class="version-badge">v1.0.0-rc.3</span> </div> <!-- SVG Diagram --> <div class="animate-fade-in-up delay-300
|
||||
</p> <!-- Version badge --> <div class="animate-fade-in-up delay-200 mb-10"> <span class="inline-flex items-center px-3 py-1 font-mono text-xs font-medium
|
||||
rounded-full border
|
||||
bg-gray-100 border-gray-200 text-gray-500
|
||||
dark:bg-neutral-800/50 dark:border-neutral-700 dark:text-neutral-400">
|
||||
v1.0.0-rc.3 </span> </div> <!-- SVG Diagram --> <div class="animate-fade-in-up delay-300
|
||||
relative mx-auto mb-12 p-4 sm:p-8
|
||||
bg-white dark:bg-[var(--color-dark-bg-secondary)]
|
||||
bg-white dark:bg-neutral-900
|
||||
rounded-2xl shadow-lg dark:shadow-none
|
||||
border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"> <img src="/spec/1.0.0-rc.3.svg" alt="Git Common-Flow diagram" class="w-full h-auto max-w-3xl mx-auto
|
||||
border border-gray-200 dark:border-neutral-800"> <img src="/spec/1.0.0-rc.3.svg" alt="Git Common-Flow diagram" class="w-full h-auto max-w-3xl mx-auto
|
||||
dark:invert dark:hue-rotate-180 dark:contrast-90"> </div> <!-- Navigation links --> <nav class="animate-fade-in-up delay-400
|
||||
flex flex-wrap items-center justify-center gap-4"> <a href="#about" class="btn btn-ghost">About</a> <a href="#spec" class="btn btn-primary">Read the Spec</a> <a href="#faq" class="btn btn-ghost">FAQ</a> </nav> </div> <!-- Scroll indicator --> <a href="#about" class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
flex flex-wrap items-center justify-center gap-4"> <a href="#about" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50">
|
||||
About
|
||||
</a> <a href="#spec" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
bg-sky-600 text-white
|
||||
hover:bg-sky-500 hover:-translate-y-0.5 hover:shadow-md">
|
||||
Read the Spec
|
||||
</a> <a href="#faq" class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50">
|
||||
FAQ
|
||||
</a> </nav> </div> <!-- Scroll indicator --> <a href="#about" class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
animate-fade-in delay-700
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-accent)] transition-colors" aria-label="Scroll to content"> <svg class="w-6 h-6 animate-bounce-subtle" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 14l-7 7m0 0l-7-7m7 7V3"></path> </svg> </a> </section> <section id="about" class="py-20 sm:py-28" data-astro-cid-x2lc2h5w> <div class="section-container" data-astro-cid-x2lc2h5w> <div class="max-w-3xl mx-auto" data-astro-cid-x2lc2h5w> <!-- Section header --> <div class="mb-12 text-center" data-astro-cid-x2lc2h5w> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-x2lc2h5w>About Common-Flow</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w>
|
||||
A practical git workflow that combines the best of GitHub Flow with
|
||||
versioned releases
|
||||
</p> </div> <!-- Introduction --> <div class="prose-spec mb-12" data-astro-cid-x2lc2h5w> <div class="spec-content" data-astro-cid-x2lc2h5w></div> </div> <!-- Summary as feature cards --> <div class="mb-16" data-astro-cid-x2lc2h5w> <h3 class="text-xl font-display font-semibold mb-6
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]" data-astro-cid-x2lc2h5w>
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-sky-600 transition-colors" aria-label="Scroll to content"> <svg width="1em" height="1em" class="w-6 h-6 animate-bounce-subtle" data-icon="heroicons:arrow-down"> <symbol id="ai:heroicons:arrow-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3"/></symbol><use href="#ai:heroicons:arrow-down"></use> </svg> </a> </section> <section id="about" class="py-20 sm:py-28"> <div class="section-container"> <div class="max-w-3xl mx-auto"> <div class="mb-12 text-center"> <h2 class="text-3xl sm:text-4xl mb-4">About Common-Flow</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> A practical git workflow that combines the best of GitHub Flow with versioned releases </p> </div> <!-- Introduction --> <div class="prose-spec mb-12"></div> <!-- Summary as feature cards --> <div class="mb-16"> <h3 class="text-xl font-display font-semibold mb-6
|
||||
text-gray-950 dark:text-neutral-50">
|
||||
Key Principles
|
||||
</h3> <div class="spec-content prose-spec" data-astro-cid-x2lc2h5w><p>Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
</h3> <div class="prose-spec"><p>Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
the <a href="http://scottchacon.com/2011/08/31/github-flow.html">original variant</a>
|
||||
of <a href="https://guides.github.com/introduction/flow/">GitHub Flow</a>, while taking
|
||||
into account how a lot of open source projects use git.</p>
|
||||
<p>In short, Common-Flow is essentially GitHub Flow with the addition of versioned
|
||||
releases, optional release branches, and without the requirement to deploy to
|
||||
production all the time.</p></div> </div> <!-- Author & License --> <div class="pt-8 border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-x2lc2h5w> <div class="grid sm:grid-cols-2 gap-8" data-astro-cid-x2lc2h5w> <div data-astro-cid-x2lc2h5w> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-x2lc2h5w>
|
||||
Author
|
||||
</h4> <div class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w><p>The Git Common-Flow specification is authored
|
||||
by <a href="http://jimeh.me">Jim Myhrberg</a>.</p>
|
||||
<p>If you'd like to leave feedback,
|
||||
please <a href="https://github.com/jimeh/common-flow/issues">open an issue on GitHub</a>.</p></div> </div> <div data-astro-cid-x2lc2h5w> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-x2lc2h5w>
|
||||
production all the time.</p></div> </div> <!-- Feedback & License --> <div class="pt-8 border-t border-gray-200 dark:border-neutral-800"> <div class="grid sm:grid-cols-2 gap-8"> <div> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Feedback
|
||||
</h4> <p class="text-gray-600 dark:text-neutral-400">
|
||||
Please <a href="https://github.com/jimeh/common-flow/issues" class="text-sky-600 hover:text-sky-400" target="_blank" rel="noopener noreferrer">open an issue on GitHub</a>.
|
||||
</p> </div> <div> <h4 class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
License
|
||||
</h4> <div class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-x2lc2h5w><p><a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons - CC BY 3.0</a></p></div> </div> </div> </div> </div> </div> </section> <section id="spec" class="py-20 sm:py-28" data-astro-cid-6lwcykzv> <div class="section-container" data-astro-cid-6lwcykzv> <!-- Section header --> <div class="max-w-3xl mx-auto mb-12 text-center" data-astro-cid-6lwcykzv> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-6lwcykzv>The Specification</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-6lwcykzv>
|
||||
The complete Git Common-Flow specification
|
||||
</p> </div> <!-- Content with sidebar --> <div class="lg:flex lg:gap-8" data-astro-cid-6lwcykzv> <!-- Sidebar --> <div class="lg:w-64 lg:flex-shrink-0" data-astro-cid-6lwcykzv> <aside id="spec-sidebar" class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
</h4> <div class="text-gray-600 dark:text-neutral-400"><p><a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons - CC BY 3.0</a></p></div> </div> </div> </div> </div> </div> </section> <section id="spec" class="py-20 sm:py-28"> <div class="section-container"> <div class="mb-12 text-center max-w-3xl mx-auto"> <h2 class="text-3xl sm:text-4xl mb-4">The Specification</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> The complete Git Common-Flow specification </p> </div> <!-- Content with sidebar --> <div class="lg:flex lg:gap-8"> <!-- Sidebar --> <div class="lg:w-64 lg:flex-shrink-0"> <aside id="spec-sidebar" class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
lg:max-h-[calc(100vh-8rem)] lg:overflow-y-auto
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]" data-astro-cid-lfaoh65k> <nav class="space-y-1 py-2" data-astro-cid-lfaoh65k> <div class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-lfaoh65k>
|
||||
On This Page
|
||||
</div> <a href="#summary" class="sidebar-link " data-sidebar-link data-section-id="summary" data-astro-cid-lfaoh65k> Summary </a><a href="#terminology" class="sidebar-link " data-sidebar-link data-section-id="terminology" data-astro-cid-lfaoh65k> Terminology </a><a href="#specification" class="sidebar-link " data-sidebar-link data-section-id="specification" data-astro-cid-lfaoh65k> Specification </a><a href="#spec-tldr" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-tldr" data-astro-cid-lfaoh65k> TL;DR </a><a href="#spec-the-master-branch" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-the-master-branch" data-astro-cid-lfaoh65k> The Master Branch </a><a href="#spec-change-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-change-branches" data-astro-cid-lfaoh65k> Change Branches </a><a href="#spec-pull-requests" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-pull-requests" data-astro-cid-lfaoh65k> Pull Requests </a><a href="#spec-versioning" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-versioning" data-astro-cid-lfaoh65k> Versioning </a><a href="#spec-releases" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-releases" data-astro-cid-lfaoh65k> Releases </a><a href="#spec-short-term-release-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-short-term-release-branches" data-astro-cid-lfaoh65k> Short-Term Release Branches </a><a href="#spec-long-term-release-branches" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-long-term-release-branches" data-astro-cid-lfaoh65k> Long-term Release Branches </a><a href="#spec-bug-fixes-rollback" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-bug-fixes-rollback" data-astro-cid-lfaoh65k> Bug Fixes & Rollback </a><a href="#spec-git-best-practices" class="sidebar-link sidebar-link-sub" data-sidebar-link data-section-id="spec-git-best-practices" data-astro-cid-lfaoh65k> Git Best Practices </a> </nav> </aside> <!-- Mobile floating button --> <button id="spec-toc-toggle" class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-gray-200 dark:border-neutral-800"> <nav class="space-y-1 py-2"> <div class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Table of Contents
|
||||
</div> <a href="#terminology" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-sidebar-link data-section-id="terminology"> <span>Terminology</span> </a><a href="#specification" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-sidebar-link data-section-id="specification"> <span>Specification</span> </a><a href="#spec-tldr" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-tldr"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 1. </span> <span>TL;DR</span> </a><a href="#spec-the-master-branch" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-the-master-branch"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 2. </span> <span>The Master Branch</span> </a><a href="#spec-change-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-change-branches"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 3. </span> <span>Change Branches</span> </a><a href="#spec-pull-requests" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-pull-requests"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 4. </span> <span>Pull Requests</span> </a><a href="#spec-versioning" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-versioning"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 5. </span> <span>Versioning</span> </a><a href="#spec-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-releases"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 6. </span> <span>Releases</span> </a><a href="#spec-release-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-release-branches"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 7. </span> <span>Release Branches</span> </a><a href="#spec-bug-fixes-rollback" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-bug-fixes-rollback"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 8. </span> <span>Bug Fixes & Rollback</span> </a><a href="#spec-git-best-practices" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-sidebar-link data-section-id="spec-git-best-practices"> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 9. </span> <span>Git Best Practices</span> </a> </nav> </aside> <!-- Mobile floating button --> <button id="spec-toc-toggle" class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
w-12 h-12 rounded-full shadow-lg
|
||||
bg-[var(--color-accent)] text-white
|
||||
bg-sky-600 text-white
|
||||
flex items-center justify-center
|
||||
hover:bg-[var(--color-accent-light)]
|
||||
transition-all duration-200" aria-label="Jump to section" data-astro-cid-lfaoh65k> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-lfaoh65k> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h7" data-astro-cid-lfaoh65k></path> </svg> </button> <!-- Mobile TOC drawer --> <div id="spec-toc-drawer" class="lg:hidden fixed inset-0 z-50 hidden" data-toc-drawer data-astro-cid-lfaoh65k> <!-- Backdrop --> <div class="absolute inset-0 bg-black/50" data-toc-backdrop data-astro-cid-lfaoh65k></div> <!-- Drawer --> <div class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-[var(--color-bg-primary)] dark:bg-[var(--color-dark-bg-primary)]
|
||||
rounded-t-2xl shadow-xl p-6" data-astro-cid-lfaoh65k> <div class="flex items-center justify-between mb-4" data-astro-cid-lfaoh65k> <span class="text-sm font-semibold uppercase tracking-wider
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]" data-astro-cid-lfaoh65k>
|
||||
hover:bg-sky-500
|
||||
transition-all duration-200" aria-label="Jump to section"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:bars-3-bottom-left"> <symbol id="ai:heroicons:bars-3-bottom-left" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12"/></symbol><use href="#ai:heroicons:bars-3-bottom-left"></use> </svg> </button> <!-- Mobile TOC drawer --> <div id="spec-toc-drawer" class="lg:hidden fixed inset-0 z-50 hidden" data-toc-drawer> <!-- Backdrop --> <div class="absolute inset-0 bg-black/50" data-toc-backdrop></div> <!-- Drawer --> <div class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-gray-50 dark:bg-neutral-950
|
||||
rounded-t-2xl shadow-xl p-6"> <div class="flex items-center justify-between mb-4"> <span class="text-sm font-semibold uppercase tracking-wider
|
||||
text-gray-500 dark:text-neutral-500">
|
||||
Jump to Section
|
||||
</span> <button class="p-2 rounded-lg hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]" data-toc-close aria-label="Close" data-astro-cid-lfaoh65k> <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-lfaoh65k> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" data-astro-cid-lfaoh65k></path> </svg> </button> </div> <nav class="space-y-1" data-astro-cid-lfaoh65k> <a href="#summary" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Summary </a><a href="#terminology" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Terminology </a><a href="#specification" class="sidebar-link " data-toc-link data-astro-cid-lfaoh65k> Specification </a><a href="#spec-tldr" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> TL;DR </a><a href="#spec-the-master-branch" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> The Master Branch </a><a href="#spec-change-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Change Branches </a><a href="#spec-pull-requests" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Pull Requests </a><a href="#spec-versioning" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Versioning </a><a href="#spec-releases" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Releases </a><a href="#spec-short-term-release-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Short-Term Release Branches </a><a href="#spec-long-term-release-branches" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Long-term Release Branches </a><a href="#spec-bug-fixes-rollback" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Bug Fixes & Rollback </a><a href="#spec-git-best-practices" class="sidebar-link sidebar-link-sub" data-toc-link data-astro-cid-lfaoh65k> Git Best Practices </a> </nav> </div> </div> <script type="module">function l(){const r=document.querySelectorAll("[data-sidebar-link]"),d=new Map;r.forEach(e=>{const t=e.getAttribute("data-section-id");if(t){const o=document.getElementById(t);o&&d.set(t,o)}});const g=new IntersectionObserver(e=>{e.forEach(t=>{if(t.isIntersecting){const o=t.target.getAttribute("id");r.forEach(a=>{const E=a.getAttribute("data-section-id");a.classList.toggle("active",E===o)})}})},{rootMargin:"-20% 0% -60% 0%",threshold:0});d.forEach(e=>g.observe(e));const n=document.getElementById("spec-toc-toggle"),c=document.getElementById("spec-toc-drawer"),u=c?.querySelector("[data-toc-backdrop]"),b=c?.querySelector("[data-toc-close]"),v=c?.querySelectorAll("[data-toc-link]");function f(){c?.classList.remove("hidden"),document.body.style.overflow="hidden"}function s(){c?.classList.add("hidden"),document.body.style.overflow=""}n?.addEventListener("click",f),u?.addEventListener("click",s),b?.addEventListener("click",s),v?.forEach(e=>{e.addEventListener("click",s)});const i=document.getElementById("spec");i&&n&&new IntersectionObserver(([t])=>{n.classList.toggle("hidden",!t.isIntersecting)},{threshold:0}).observe(i)}l();document.addEventListener("astro:after-swap",l);</script> </div> <!-- Main content --> <div class="flex-1 min-w-0" data-astro-cid-6lwcykzv> <article class="prose-spec spec-content" data-astro-cid-6lwcykzv> <!-- Terminology --> <section id="terminology" data-astro-cid-6lwcykzv> <h2 data-astro-cid-6lwcykzv>Terminology</h2> <ul>
|
||||
</span> <button class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800" data-toc-close aria-label="Close"> <svg width="1em" height="1em" class="w-5 h-5" data-icon="heroicons:x-mark"> <symbol id="ai:heroicons:x-mark" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M6 18L18 6M6 6l12 12"/></symbol><use href="#ai:heroicons:x-mark"></use> </svg> </button> </div> <nav class="space-y-1"> <a href="#terminology" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-toc-link> <span>Terminology</span> </a><a href="#specification" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800" data-toc-link> <span>Specification</span> </a><a href="#spec-tldr" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 1. </span> <span>TL;DR</span> </a><a href="#spec-the-master-branch" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 2. </span> <span>The Master Branch</span> </a><a href="#spec-change-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 3. </span> <span>Change Branches</span> </a><a href="#spec-pull-requests" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 4. </span> <span>Pull Requests</span> </a><a href="#spec-versioning" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 5. </span> <span>Versioning</span> </a><a href="#spec-releases" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 6. </span> <span>Releases</span> </a><a href="#spec-release-branches" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 7. </span> <span>Release Branches</span> </a><a href="#spec-bug-fixes-rollback" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 8. </span> <span>Bug Fixes & Rollback</span> </a><a href="#spec-git-best-practices" class="sidebar-link block py-2 px-4 text-sm rounded-md transition-colors text-gray-500 hover:text-gray-950 hover:bg-gray-100 dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800 pl-6 text-[0.8125rem] flex" data-toc-link> <span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600"> 9. </span> <span>Git Best Practices</span> </a> </nav> </div> </div> <script type="module" src="/_astro/SpecSidebar.astro_astro_type_script_index_0_lang.BQBj5HuJ.js"></script> </div> <!-- Main content --> <div class="flex-1 min-w-0"> <article class="prose-spec"> <!-- Terminology --> <section id="terminology"> <h2>Terminology</h2> <ul>
|
||||
<li><strong>Master Branch</strong> - Must be named "master", must always have passing tests,
|
||||
and is not guaranteed to always work in production environments.</li>
|
||||
<li><strong>Change Branches</strong> - Any branch that introduces changes like a new feature, a
|
||||
@@ -181,17 +190,17 @@ environments. Consists of a version bump commit, and a git tag named according
|
||||
to the new version string placed on said commit.</li>
|
||||
<li><strong>Release Branches</strong> - Used both for short-term preparations of a release, and
|
||||
also for long-term maintenance of older version.</li>
|
||||
</ul> </section> <!-- Main specification --> <section id="specification" data-astro-cid-6lwcykzv> <h2 data-astro-cid-6lwcykzv>Git Common-Flow Specification</h2> <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
</ul> </section> <!-- Main specification --> <section id="specification"> <h2>Specification</h2> <p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in <a href="https://tools.ietf.org/html/rfc2119">RFC 2119</a>.</p>
|
||||
<ol>
|
||||
<li>TL;DR
|
||||
<li id="spec-tldr">TL;DR
|
||||
<ol>
|
||||
<li>Don't break the master branch.</li>
|
||||
<li>A release is a git tag.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>The Master Branch
|
||||
<li id="spec-the-master-branch">The Master Branch
|
||||
<ol>
|
||||
<li>A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".</li>
|
||||
@@ -205,7 +214,7 @@ release/production" state to reduce any friction with creating a new
|
||||
release.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Change Branches
|
||||
<li id="spec-change-branches">Change Branches
|
||||
<ol>
|
||||
<li>Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches". All change
|
||||
@@ -227,7 +236,7 @@ the change branch to the remote server. This will require you to do a
|
||||
force push, and you SHOULD use the "--force-with-lease" git push option.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Pull Requests
|
||||
<li id="spec-pull-requests">Pull Requests
|
||||
<ol>
|
||||
<li>To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent) so others can review and approve your changes.</li>
|
||||
@@ -240,7 +249,7 @@ others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Versioning
|
||||
<li id="spec-versioning">Versioning
|
||||
<ol>
|
||||
<li>The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
@@ -253,7 +262,7 @@ but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Releases
|
||||
<li id="spec-releases">Releases
|
||||
<ol>
|
||||
<li>To create a new release, you MUST create a "version bump" commit which
|
||||
changes the hard-coded version string of the project. The version bump
|
||||
@@ -278,7 +287,7 @@ of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Release Branches
|
||||
<li id="spec-release-branches">Release Branches
|
||||
<ol>
|
||||
<li>Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".</li>
|
||||
@@ -330,7 +339,7 @@ release tag. The security fix release will then end up being version
|
||||
</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Bug Fixes & Rollback
|
||||
<li id="spec-bug-fixes-rollback">Bug Fixes & Rollback
|
||||
<ol>
|
||||
<li>You MUST NOT under any circumstances force push to the master branch.</li>
|
||||
<li>If a change branch which has been merged into the master branch is found
|
||||
@@ -343,7 +352,7 @@ merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Git Best Practices
|
||||
<li id="spec-git-best-practices">Git Best Practices
|
||||
<ol>
|
||||
<li>All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
@@ -368,17 +377,10 @@ and creates a merge commit to mark the integration of the branch with
|
||||
master.</li>
|
||||
</ol>
|
||||
</li>
|
||||
</ol> </section> </article> </div> </div> </div> </section> <section id="faq" class="faq-section py-20 sm:py-28" data-astro-cid-hqz3ghsx> <div class="section-container" data-astro-cid-hqz3ghsx> <div class="max-w-3xl mx-auto" data-astro-cid-hqz3ghsx> <!-- Section header --> <div class="mb-12 text-center" data-astro-cid-hqz3ghsx> <h2 class="text-3xl sm:text-4xl mb-4" data-astro-cid-hqz3ghsx>FAQ</h2> <p class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]" data-astro-cid-hqz3ghsx>
|
||||
Common questions about Git Common-Flow
|
||||
</p> </div> <!-- FAQ Items --> <div class="space-y-0" data-astro-cid-hqz3ghsx> </div> </div> </div> </section> <script type="module">function s(){const r=document.querySelectorAll("[data-faq-item]");r.forEach(t=>{const e=t.querySelector("[data-faq-trigger]"),o=t.querySelector("[data-faq-content]"),i=t.querySelector("[data-faq-icon]");!e||!o||!i||e.addEventListener("click",()=>{const c=e.getAttribute("aria-expanded")==="true";r.forEach(a=>{if(a!==t){const d=a.querySelector("[data-faq-trigger]"),l=a.querySelector("[data-faq-content]"),f=a.querySelector("[data-faq-icon]");d?.setAttribute("aria-expanded","false"),l?.classList.add("hidden"),f?.classList.remove("rotate-180")}}),e.setAttribute("aria-expanded",c?"false":"true"),o.classList.toggle("hidden",c),i.classList.toggle("rotate-180",!c)})});const n=r[0]?.querySelector("[data-faq-trigger]");n&&n.click()}s();document.addEventListener("astro:after-swap",s);</script> </main> <footer class="py-8 text-center text-sm
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"> <div class="section-container"> <p>
|
||||
Git Common-Flow is authored by
|
||||
<a href="https://jimeh.me/" class="hover:text-[var(--color-accent)]" target="_blank" rel="noopener noreferrer">
|
||||
Jim Myhrberg
|
||||
</a> </p> <p class="mt-2"> <a href="https://creativecommons.org/licenses/by/4.0/" class="hover:text-[var(--color-accent)]" target="_blank" rel="noopener noreferrer">
|
||||
CC BY 4.0
|
||||
</a> </p> </div> </footer> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme");e==="dark"||!e&&window.matchMedia("(prefers-color-scheme: dark)").matches?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
</ol> </section> </article> </div> </div> </div> </section> <section id="faq" class="py-20 sm:py-28"> <div class="section-container"> <div class="max-w-3xl mx-auto"> <div class="mb-12 text-center"> <h2 class="text-3xl sm:text-4xl mb-4">FAQ</h2> <p class="text-lg text-gray-600 dark:text-neutral-400"> Common questions about Git Common-Flow </p> </div> <!-- FAQ Items --> <div class="space-y-0"> </div> </div> </div> </section> <script type="module">function n(){document.querySelectorAll("[data-faq-item]").forEach(r=>{const t=r.querySelector("[data-faq-trigger]"),a=r.querySelector("[data-faq-content]"),s=r.querySelector("[data-faq-icon]");!t||!a||!s||t.addEventListener("click",()=>{const e=t.getAttribute("aria-expanded")==="true";t.setAttribute("aria-expanded",e?"false":"true"),a.classList.toggle("grid-rows-[1fr]",!e),a.classList.toggle("grid-rows-[0fr]",e),s.classList.toggle("rotate-180",!e)})})}n();document.addEventListener("astro:after-swap",n);</script> </main> <footer class="pt-12 pb-6 my-28 text-sm
|
||||
text-gray-500 dark:text-neutral-500
|
||||
border-t border-gray-200 dark:border-neutral-800"> <div class="section-container flex flex-col sm:flex-row
|
||||
sm:justify-between sm:items-center gap-2"> <p>
|
||||
License:
|
||||
<a href="https://creativecommons.org/licenses/by/4.0/" class="hover:text-sky-600" target="_blank" rel="noopener noreferrer"> CC BY 4.0 </a> </p> <p> Git Common-Flow by
|
||||
<a href="https://jimeh.me/" class="hover:text-sky-600" target="_blank" rel="noopener noreferrer"> Jim Myhrberg </a> </p> </div> </footer> <!-- Re-init theme on Astro page transitions --> <script type="module">document.addEventListener("astro:after-swap",()=>{const e=localStorage.getItem("theme"),t=window.matchMedia("(prefers-color-scheme: dark)").matches;e==="dark"||e!=="light"&&t?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark")});</script> </body> </html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
21
eslint.config.js
Normal file
21
eslint.config.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import eslint from "@eslint/js";
|
||||
import tseslint from "typescript-eslint";
|
||||
import astro from "eslint-plugin-astro";
|
||||
|
||||
export default tseslint.config(
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
...astro.configs.recommended,
|
||||
{
|
||||
ignores: ["docs/**", ".astro/**"],
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
// Allow unused vars prefixed with _
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
||||
],
|
||||
},
|
||||
},
|
||||
);
|
||||
21
package.json
21
package.json
@@ -1,26 +1,43 @@
|
||||
{
|
||||
"name": "commonflow-org",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"check": "astro check",
|
||||
"lint": "eslint .",
|
||||
"format": "prettier --write .",
|
||||
"format:check": "prettier --check .",
|
||||
"update": "bun scripts/update-specs.ts",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/sitemap": "^3.6.1",
|
||||
"@fontsource-variable/bricolage-grotesque": "^5.2.10",
|
||||
"@fontsource-variable/dm-sans": "^5.2.8",
|
||||
"@fontsource-variable/jetbrains-mono": "^5.2.8",
|
||||
"@iconify-json/heroicons": "^1.2.3",
|
||||
"@iconify-json/simple-icons": "^1.2.65",
|
||||
"astro": "^5.16.8",
|
||||
"astro-icon": "^1.1.5",
|
||||
"rehype-stringify": "^10.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-rehype": "^11.1.2",
|
||||
"unified": "^11.0.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "^0.9.6",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@tailwindcss/typography": "^0.5.19",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-astro": "^1.5.0",
|
||||
"prettier": "^3.7.4",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"typescript": "^5.9.3"
|
||||
"typescript": "^5.9.3",
|
||||
"typescript-eslint": "^8.52.0"
|
||||
}
|
||||
}
|
||||
|
||||
12
prettier.config.js
Normal file
12
prettier.config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/** @type {import("prettier").Config} */
|
||||
export default {
|
||||
plugins: ["prettier-plugin-astro"],
|
||||
overrides: [
|
||||
{
|
||||
files: "*.astro",
|
||||
options: {
|
||||
parser: "astro",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
17
public/favicon.svg
Normal file
17
public/favicon.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<!-- Main horizontal line -->
|
||||
<path d="M 4 10 L 28 10" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
|
||||
<!-- Branch line: down from left, curve, up to right -->
|
||||
<path d="M 8 10 L 8 16 Q 8 22 16 22 Q 24 22 24 16 L 24 10"
|
||||
fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
|
||||
<!-- Left dot on main line -->
|
||||
<circle cx="8" cy="10" r="3" fill="currentColor"/>
|
||||
|
||||
<!-- Right dot on main line -->
|
||||
<circle cx="24" cy="10" r="3" fill="currentColor"/>
|
||||
|
||||
<!-- Middle dot on branch -->
|
||||
<circle cx="16" cy="22" r="3" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 625 B |
@@ -1,8 +1,6 @@
|
||||
/**
|
||||
* Fetches spec documents and diagrams from the common-flow GitHub repo
|
||||
* and writes them to the appropriate locations for Astro to consume.
|
||||
*
|
||||
* Equivalent to the Jekyll Rakefile's `rake update` task.
|
||||
*/
|
||||
|
||||
import * as fs from "node:fs";
|
||||
@@ -38,7 +36,7 @@ version: {{version}}
|
||||
|
||||
function buildFileUrl(
|
||||
fileType: "document" | "diagram",
|
||||
version: string
|
||||
version: string,
|
||||
): string {
|
||||
const file = config.update.files[fileType];
|
||||
return config.update.urlTemplate
|
||||
|
||||
@@ -1,77 +1,67 @@
|
||||
---
|
||||
import SectionHeader from "./SectionHeader.astro";
|
||||
import { config } from "../config";
|
||||
|
||||
interface Props {
|
||||
introduction: string;
|
||||
summary: string;
|
||||
about: string;
|
||||
license: string;
|
||||
}
|
||||
|
||||
const { introduction, summary, about, license } = Astro.props;
|
||||
const { introduction, summary, license } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="about" class="py-20 sm:py-28">
|
||||
<div class="section-container">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<!-- Section header -->
|
||||
<div class="mb-12 text-center">
|
||||
<h2 class="text-3xl sm:text-4xl mb-4">About Common-Flow</h2>
|
||||
<p
|
||||
class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
>
|
||||
A practical git workflow that combines the best of GitHub Flow with
|
||||
versioned releases
|
||||
</p>
|
||||
</div>
|
||||
<SectionHeader
|
||||
title="About Common-Flow"
|
||||
subtitle="A practical git workflow that combines the best of GitHub Flow with versioned releases"
|
||||
/>
|
||||
|
||||
<!-- Introduction -->
|
||||
<div class="prose-spec mb-12">
|
||||
<div class="spec-content" set:html={introduction} />
|
||||
</div>
|
||||
<div class="prose-spec mb-12" set:html={introduction} />
|
||||
|
||||
<!-- Summary as feature cards -->
|
||||
<div class="mb-16">
|
||||
<h3
|
||||
class="text-xl font-display font-semibold mb-6
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]"
|
||||
text-gray-950 dark:text-neutral-50"
|
||||
>
|
||||
Key Principles
|
||||
</h3>
|
||||
<div class="spec-content prose-spec" set:html={summary} />
|
||||
<div class="prose-spec" set:html={summary} />
|
||||
</div>
|
||||
|
||||
<!-- Author & License -->
|
||||
<div
|
||||
class="pt-8 border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"
|
||||
>
|
||||
<!-- Feedback & License -->
|
||||
<div class="pt-8 border-t border-gray-200 dark:border-neutral-800">
|
||||
<div class="grid sm:grid-cols-2 gap-8">
|
||||
<div>
|
||||
<h4
|
||||
class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]"
|
||||
text-gray-500 dark:text-neutral-500"
|
||||
>
|
||||
Author
|
||||
Feedback
|
||||
</h4>
|
||||
<div
|
||||
class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
set:html={about}
|
||||
/>
|
||||
<p class="text-gray-600 dark:text-neutral-400">
|
||||
Please{" "}
|
||||
<a
|
||||
href={`${config.repoUrl}/issues`}
|
||||
class="text-sky-600 hover:text-sky-400"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">open an issue on GitHub</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4
|
||||
class="text-sm font-semibold uppercase tracking-wider mb-3
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]"
|
||||
text-gray-500 dark:text-neutral-500"
|
||||
>
|
||||
License
|
||||
</h4>
|
||||
<div
|
||||
class="spec-content text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
class="text-gray-600 dark:text-neutral-400"
|
||||
set:html={license}
|
||||
/>
|
||||
</div>
|
||||
@@ -80,17 +70,3 @@ const { introduction, summary, about, license } = Astro.props;
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.spec-content :global(p:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.spec-content :global(a) {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.spec-content :global(a:hover) {
|
||||
color: var(--color-accent-light);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import SectionHeader from "./SectionHeader.astro";
|
||||
import type { FAQItem } from "../utils/parseSpecContent";
|
||||
|
||||
interface Props {
|
||||
@@ -8,51 +10,49 @@ interface Props {
|
||||
const { items } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="faq" class="faq-section py-20 sm:py-28">
|
||||
<section id="faq" class="py-20 sm:py-28">
|
||||
<div class="section-container">
|
||||
<div class="max-w-3xl mx-auto">
|
||||
<!-- Section header -->
|
||||
<div class="mb-12 text-center">
|
||||
<h2 class="text-3xl sm:text-4xl mb-4">FAQ</h2>
|
||||
<p
|
||||
class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
>
|
||||
Common questions about Git Common-Flow
|
||||
</p>
|
||||
</div>
|
||||
<SectionHeader
|
||||
title="FAQ"
|
||||
subtitle="Common questions about Git Common-Flow"
|
||||
/>
|
||||
|
||||
<!-- FAQ Items -->
|
||||
<div class="space-y-0">
|
||||
{
|
||||
items.map((item, index) => (
|
||||
<div class="faq-item" data-faq-item>
|
||||
items.map((item) => (
|
||||
<div
|
||||
class="border-b border-gray-200 dark:border-neutral-800"
|
||||
data-faq-item
|
||||
>
|
||||
<button
|
||||
class="faq-question"
|
||||
class="flex justify-between items-center w-full py-6 text-left
|
||||
font-display text-lg font-semibold cursor-pointer
|
||||
transition-colors
|
||||
text-gray-950 dark:text-neutral-50
|
||||
hover:text-sky-600"
|
||||
aria-expanded="false"
|
||||
data-faq-trigger
|
||||
>
|
||||
<span class="pr-4">{item.question}</span>
|
||||
<svg
|
||||
<Icon
|
||||
name="heroicons:chevron-down"
|
||||
class="w-5 h-5 flex-shrink-0 transition-transform duration-200"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
data-faq-icon
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 9l-7 7-7-7"
|
||||
/>
|
||||
</svg>
|
||||
/>
|
||||
</button>
|
||||
<div
|
||||
class="faq-answer hidden prose-spec spec-content"
|
||||
class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 ease-out"
|
||||
data-faq-content
|
||||
set:html={item.answer}
|
||||
/>
|
||||
>
|
||||
<div class="overflow-hidden">
|
||||
<div
|
||||
class="pb-6 text-gray-600 dark:text-neutral-400 prose-spec"
|
||||
set:html={item.answer}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
@@ -75,33 +75,13 @@ const { items } = Astro.props;
|
||||
trigger.addEventListener("click", () => {
|
||||
const isExpanded = trigger.getAttribute("aria-expanded") === "true";
|
||||
|
||||
// Close all other items
|
||||
items.forEach((otherItem) => {
|
||||
if (otherItem !== item) {
|
||||
const otherTrigger = otherItem.querySelector("[data-faq-trigger]");
|
||||
const otherContent = otherItem.querySelector("[data-faq-content]");
|
||||
const otherIcon = otherItem.querySelector("[data-faq-icon]");
|
||||
|
||||
otherTrigger?.setAttribute("aria-expanded", "false");
|
||||
otherContent?.classList.add("hidden");
|
||||
otherIcon?.classList.remove("rotate-180");
|
||||
}
|
||||
});
|
||||
|
||||
// Toggle current item
|
||||
trigger.setAttribute("aria-expanded", isExpanded ? "false" : "true");
|
||||
content.classList.toggle("hidden", isExpanded);
|
||||
content.classList.toggle("grid-rows-[1fr]", !isExpanded);
|
||||
content.classList.toggle("grid-rows-[0fr]", isExpanded);
|
||||
icon.classList.toggle("rotate-180", !isExpanded);
|
||||
});
|
||||
});
|
||||
|
||||
// Open first item by default
|
||||
const firstTrigger = items[0]?.querySelector(
|
||||
"[data-faq-trigger]"
|
||||
) as HTMLButtonElement;
|
||||
if (firstTrigger) {
|
||||
firstTrigger.click();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on load
|
||||
@@ -110,30 +90,3 @@ const { items } = Astro.props;
|
||||
// Re-initialize on Astro page transitions
|
||||
document.addEventListener("astro:after-swap", initFAQ);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.faq-section {
|
||||
background-color: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
:global(.dark) .faq-section {
|
||||
background-color: var(--color-dark-bg-secondary);
|
||||
}
|
||||
|
||||
.spec-content :global(p:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.spec-content :global(ul),
|
||||
.spec-content :global(ol) {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.spec-content :global(li) {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(li) {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
</style>
|
||||
|
||||
37
src/components/Footer.astro
Normal file
37
src/components/Footer.astro
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
import { config } from "../config";
|
||||
---
|
||||
|
||||
<footer
|
||||
class="pt-12 pb-6 my-28 text-sm
|
||||
text-gray-500 dark:text-neutral-500
|
||||
border-t border-gray-200 dark:border-neutral-800"
|
||||
>
|
||||
<div
|
||||
class="section-container flex flex-col sm:flex-row
|
||||
sm:justify-between sm:items-center gap-2"
|
||||
>
|
||||
<p>
|
||||
License:
|
||||
<a
|
||||
href={config.license.url}
|
||||
class="hover:text-sky-600"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{config.license.name}
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
{config.title} by
|
||||
<a
|
||||
href={config.authorUrl}
|
||||
class="hover:text-sky-600"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{config.author}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import VersionSelector from "./VersionSelector.astro";
|
||||
import ThemeToggle from "./ThemeToggle.astro";
|
||||
import { config } from "../config";
|
||||
@@ -8,85 +9,90 @@ interface Props {
|
||||
}
|
||||
|
||||
const { version } = Astro.props;
|
||||
|
||||
const navItems = [
|
||||
{ id: "about", label: "About", icon: "heroicons:information-circle" },
|
||||
{ id: "spec", label: "Spec", icon: "heroicons:document-text" },
|
||||
{ id: "faq", label: "FAQ", icon: "heroicons:question-mark-circle" },
|
||||
];
|
||||
---
|
||||
|
||||
<header
|
||||
id="site-header"
|
||||
class="fixed top-0 inset-x-0 z-50 glass border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300"
|
||||
class="fixed top-0 inset-x-0 z-50 border-b border-transparent
|
||||
translate-y-[-100%] transition-transform duration-300
|
||||
backdrop-blur-xl bg-gray-50/85 dark:bg-neutral-950/85"
|
||||
>
|
||||
<div
|
||||
class="max-w-6xl mx-auto px-4 sm:px-6 h-16 flex items-center justify-between"
|
||||
>
|
||||
<!-- Logo / Title -->
|
||||
<a
|
||||
href="#hero"
|
||||
class="header-title flex items-center gap-3 no-underline
|
||||
hover:text-[var(--color-accent)] transition-colors"
|
||||
>
|
||||
<span class="font-display font-bold text-lg tracking-tight">
|
||||
Git Common-Flow
|
||||
</span>
|
||||
</a>
|
||||
<!-- Logo / Title + Version -->
|
||||
<div class="flex items-center gap-3">
|
||||
<a
|
||||
href="#hero"
|
||||
class="flex items-center gap-3 no-underline
|
||||
text-gray-950 dark:text-neutral-50
|
||||
hover:text-sky-600 transition-colors"
|
||||
>
|
||||
<span class="font-display font-bold text-lg tracking-tight">
|
||||
Git Common-Flow
|
||||
</span>
|
||||
</a>
|
||||
<div class="hidden md:block">
|
||||
<VersionSelector
|
||||
currentVersion={version}
|
||||
versions={Array.from(config.versions)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Navigation -->
|
||||
<nav class="hidden md:flex items-center gap-1">
|
||||
<a href="#about" class="btn btn-ghost text-sm">About</a>
|
||||
<a href="#spec" class="btn btn-ghost text-sm">Spec</a>
|
||||
<a href="#faq" class="btn btn-ghost text-sm">FAQ</a>
|
||||
{
|
||||
navItems.map((item) => (
|
||||
<a
|
||||
href={`#${item.id}`}
|
||||
class="nav-link inline-flex items-center gap-1.5 px-4 py-2 text-sm
|
||||
font-medium rounded-lg transition-colors cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50"
|
||||
data-nav-link
|
||||
data-section-id={item.id}
|
||||
>
|
||||
<Icon name={item.icon} class="w-4 h-4" />
|
||||
{item.label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</nav>
|
||||
|
||||
<!-- Right side: Version, Theme, GitHub -->
|
||||
<!-- Right side: Theme, GitHub -->
|
||||
<div class="flex items-center gap-3">
|
||||
<VersionSelector
|
||||
currentVersion={version}
|
||||
versions={Array.from(config.versions)}
|
||||
/>
|
||||
|
||||
<ThemeToggle />
|
||||
|
||||
<a
|
||||
href={config.repoUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors"
|
||||
class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800"
|
||||
aria-label="View on GitHub"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<Icon name="simple-icons:github" class="w-5 h-5" />
|
||||
</a>
|
||||
|
||||
<!-- Mobile menu button -->
|
||||
<button
|
||||
id="mobile-menu-btn"
|
||||
class="md:hidden p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]"
|
||||
class="md:hidden p-2 rounded-lg
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800"
|
||||
aria-label="Toggle menu"
|
||||
>
|
||||
<svg
|
||||
class="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
</svg>
|
||||
<Icon name="heroicons:bars-3" class="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,39 +100,36 @@ const { version } = Astro.props;
|
||||
<!-- Mobile Navigation -->
|
||||
<nav
|
||||
id="mobile-nav"
|
||||
class="md:hidden hidden border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"
|
||||
class="md:hidden hidden border-t border-gray-200 dark:border-neutral-800"
|
||||
>
|
||||
<div class="px-4 py-3 space-y-1">
|
||||
<a
|
||||
href="#about"
|
||||
class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
<a
|
||||
href="#spec"
|
||||
class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]"
|
||||
>
|
||||
Spec
|
||||
</a>
|
||||
<a
|
||||
href="#faq"
|
||||
class="block py-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:text-[var(--color-accent)]"
|
||||
>
|
||||
FAQ
|
||||
</a>
|
||||
<div class="px-4 py-3 space-y-1 text-center">
|
||||
<div class="py-2 flex justify-center">
|
||||
<VersionSelector
|
||||
currentVersion={version}
|
||||
versions={Array.from(config.versions)}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
navItems.map((item) => (
|
||||
<a
|
||||
href={`#${item.id}`}
|
||||
class="nav-link flex items-center justify-center gap-1.5 py-2
|
||||
text-gray-600 dark:text-neutral-400 hover:text-sky-600"
|
||||
data-nav-link
|
||||
data-section-id={item.id}
|
||||
>
|
||||
<Icon name={item.icon} class="w-4 h-4" />
|
||||
{item.label}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
import { initActiveSectionTracker } from "../scripts/activeSectionTracker";
|
||||
|
||||
function initHeader() {
|
||||
const header = document.getElementById("site-header");
|
||||
const hero = document.getElementById("hero");
|
||||
@@ -135,23 +138,25 @@ const { version } = Astro.props;
|
||||
|
||||
if (!header || !hero) return;
|
||||
|
||||
// Show/hide header based on scroll past hero
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
if (entry.isIntersecting) {
|
||||
header.classList.add("translate-y-[-100%]");
|
||||
header.classList.remove("border-[var(--color-border)]");
|
||||
header.classList.remove("dark:border-[var(--color-dark-border)]");
|
||||
} else {
|
||||
header.classList.remove("translate-y-[-100%]");
|
||||
header.classList.add("border-[var(--color-border)]");
|
||||
header.classList.add("dark:border-[var(--color-dark-border)]");
|
||||
}
|
||||
},
|
||||
{ threshold: 0, rootMargin: "-64px 0px 0px 0px" }
|
||||
);
|
||||
// Show/hide header based on scroll position
|
||||
// Show header once scrolled down by the navbar height (64px)
|
||||
const navbarHeight = 64;
|
||||
|
||||
observer.observe(hero);
|
||||
function updateHeaderVisibility() {
|
||||
if (!header) return;
|
||||
if (window.scrollY >= navbarHeight) {
|
||||
header.classList.remove("translate-y-[-100%]", "border-transparent");
|
||||
header.classList.add("border-gray-200", "dark:border-neutral-800");
|
||||
} else {
|
||||
header.classList.add("translate-y-[-100%]", "border-transparent");
|
||||
header.classList.remove("border-gray-200", "dark:border-neutral-800");
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", updateHeaderVisibility, {
|
||||
passive: true,
|
||||
});
|
||||
updateHeaderVisibility();
|
||||
|
||||
// Mobile menu toggle
|
||||
if (mobileMenuBtn && mobileNav) {
|
||||
@@ -166,6 +171,12 @@ const { version } = Astro.props;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Active section tracking for nav links
|
||||
initActiveSectionTracker({
|
||||
linkSelector: "[data-nav-link]",
|
||||
defaultToFirst: false,
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize on load
|
||||
@@ -174,13 +185,3 @@ const { version } = Astro.props;
|
||||
// Re-initialize on Astro page transitions
|
||||
document.addEventListener("astro:after-swap", initHeader);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.header-title {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
:global(.dark) .header-title {
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import VersionSelector from "./VersionSelector.astro";
|
||||
import ThemeToggle from "./ThemeToggle.astro";
|
||||
import { config } from "../config";
|
||||
@@ -14,29 +15,30 @@ const { version, svgPath } = Astro.props;
|
||||
<section
|
||||
id="hero"
|
||||
class="relative min-h-[75vh] flex flex-col items-center justify-center
|
||||
px-6 py-16 overflow-hidden"
|
||||
px-6 pt-16 pb-24 overflow-hidden"
|
||||
>
|
||||
<!-- Background gradient/texture -->
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-b from-[var(--color-bg-secondary)]
|
||||
to-[var(--color-bg-primary)]
|
||||
dark:from-[var(--color-dark-bg-secondary)]
|
||||
dark:to-[var(--color-dark-bg-primary)]"
|
||||
class="absolute inset-0 bg-gradient-to-b
|
||||
from-gray-100 to-gray-50
|
||||
dark:from-neutral-900 dark:to-neutral-950"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Subtle grid pattern -->
|
||||
<!-- Subtle grid pattern with fade -->
|
||||
<div
|
||||
class="absolute inset-0 opacity-[0.03] dark:opacity-[0.05]"
|
||||
style="background-image: linear-gradient(var(--color-text-primary) 1px, transparent 1px),
|
||||
linear-gradient(90deg, var(--color-text-primary) 1px, transparent 1px);
|
||||
background-size: 60px 60px;"
|
||||
class="absolute inset-0 opacity-[0.06] dark:opacity-[0.12]
|
||||
bg-[linear-gradient(theme(colors.gray.950)_1px,transparent_1px),linear-gradient(90deg,theme(colors.gray.950)_1px,transparent_1px)]
|
||||
dark:bg-[linear-gradient(theme(colors.neutral.600)_1px,transparent_1px),linear-gradient(90deg,theme(colors.neutral.600)_1px,transparent_1px)]
|
||||
bg-[size:60px_60px] bg-center
|
||||
[-webkit-mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]
|
||||
[mask-image:linear-gradient(to_bottom,black_20%,transparent_80%)]"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Top bar with version & theme -->
|
||||
<div
|
||||
class="absolute top-0 inset-x-0 flex items-center justify-between
|
||||
class="absolute top-0 inset-x-0 z-20 flex items-center justify-between
|
||||
px-6 py-4 animate-fade-in-down"
|
||||
>
|
||||
<div class="flex items-center gap-3">
|
||||
@@ -51,20 +53,13 @@ const { version, svgPath } = Astro.props;
|
||||
href={config.repoUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-white/50 dark:hover:bg-white/10
|
||||
transition-colors"
|
||||
class="p-2 rounded-lg transition-colors
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-white/50 dark:hover:bg-neutral-800/50"
|
||||
aria-label="View on GitHub"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<Icon name="simple-icons:github" class="w-5 h-5" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -74,8 +69,7 @@ const { version, svgPath } = Astro.props;
|
||||
<!-- Title -->
|
||||
<h1
|
||||
class="animate-fade-in-up mb-4
|
||||
text-[var(--color-text-primary)]
|
||||
dark:text-[var(--color-dark-text-primary)]"
|
||||
text-gray-950 dark:text-neutral-50"
|
||||
>
|
||||
Git Common-Flow
|
||||
</h1>
|
||||
@@ -84,25 +78,30 @@ const { version, svgPath } = Astro.props;
|
||||
<p
|
||||
class="animate-fade-in-up delay-100
|
||||
text-lg sm:text-xl max-w-2xl mx-auto mb-8
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
text-gray-600 dark:text-neutral-400"
|
||||
>
|
||||
A sensible git workflow for teams who ship
|
||||
</p>
|
||||
|
||||
<!-- Version badge -->
|
||||
<div class="animate-fade-in-up delay-200 mb-10">
|
||||
<span class="version-badge">v{version}</span>
|
||||
<span
|
||||
class="inline-flex items-center px-3 py-1 font-mono text-xs font-medium
|
||||
rounded-full border
|
||||
bg-gray-100 border-gray-200 text-gray-500
|
||||
dark:bg-neutral-800/50 dark:border-neutral-700 dark:text-neutral-400"
|
||||
>
|
||||
v{version}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- SVG Diagram -->
|
||||
<div
|
||||
class="animate-fade-in-up delay-300
|
||||
relative mx-auto mb-12 p-4 sm:p-8
|
||||
bg-white dark:bg-[var(--color-dark-bg-secondary)]
|
||||
bg-white dark:bg-neutral-900
|
||||
rounded-2xl shadow-lg dark:shadow-none
|
||||
border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"
|
||||
border border-gray-200 dark:border-neutral-800"
|
||||
>
|
||||
<img
|
||||
src={svgPath}
|
||||
@@ -117,9 +116,35 @@ const { version, svgPath } = Astro.props;
|
||||
class="animate-fade-in-up delay-400
|
||||
flex flex-wrap items-center justify-center gap-4"
|
||||
>
|
||||
<a href="#about" class="btn btn-ghost">About</a>
|
||||
<a href="#spec" class="btn btn-primary">Read the Spec</a>
|
||||
<a href="#faq" class="btn btn-ghost">FAQ</a>
|
||||
<a
|
||||
href="#about"
|
||||
class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50"
|
||||
>
|
||||
About
|
||||
</a>
|
||||
<a
|
||||
href="#spec"
|
||||
class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
bg-sky-600 text-white
|
||||
hover:bg-sky-500 hover:-translate-y-0.5 hover:shadow-md"
|
||||
>
|
||||
Read the Spec
|
||||
</a>
|
||||
<a
|
||||
href="#faq"
|
||||
class="inline-flex items-center justify-center gap-2 px-6 py-3
|
||||
text-base font-medium rounded-lg transition-all cursor-pointer
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:bg-gray-100 hover:text-gray-950
|
||||
dark:hover:bg-neutral-800 dark:hover:text-neutral-50"
|
||||
>
|
||||
FAQ
|
||||
</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -128,22 +153,10 @@ const { version, svgPath } = Astro.props;
|
||||
href="#about"
|
||||
class="absolute bottom-8 left-1/2 -translate-x-1/2
|
||||
animate-fade-in delay-700
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-accent)] transition-colors"
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-sky-600 transition-colors"
|
||||
aria-label="Scroll to content"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 animate-bounce-subtle"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 14l-7 7m0 0l-7-7m7 7V3"></path>
|
||||
</svg>
|
||||
<Icon name="heroicons:arrow-down" class="w-6 h-6 animate-bounce-subtle" />
|
||||
</a>
|
||||
</section>
|
||||
|
||||
16
src/components/SectionHeader.astro
Normal file
16
src/components/SectionHeader.astro
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const { title, subtitle, class: className } = Astro.props;
|
||||
---
|
||||
|
||||
<div class:list={["mb-12 text-center", className]}>
|
||||
<h2 class="text-3xl sm:text-4xl mb-4">{title}</h2>
|
||||
<p class="text-lg text-gray-600 dark:text-neutral-400">
|
||||
{subtitle}
|
||||
</p>
|
||||
</div>
|
||||
@@ -1,28 +1,25 @@
|
||||
---
|
||||
import SectionHeader from "./SectionHeader.astro";
|
||||
import SpecSidebar from "./SpecSidebar.astro";
|
||||
import type { TocItem } from "../utils/parseSpecContent";
|
||||
|
||||
interface Props {
|
||||
terminology: string;
|
||||
terminologyTitle: string;
|
||||
specification: string;
|
||||
tocItems: TocItem[];
|
||||
}
|
||||
|
||||
const { terminology, specification, tocItems } = Astro.props;
|
||||
const { terminology, terminologyTitle, specification, tocItems } = Astro.props;
|
||||
---
|
||||
|
||||
<section id="spec" class="py-20 sm:py-28">
|
||||
<div class="section-container">
|
||||
<!-- Section header -->
|
||||
<div class="max-w-3xl mx-auto mb-12 text-center">
|
||||
<h2 class="text-3xl sm:text-4xl mb-4">The Specification</h2>
|
||||
<p
|
||||
class="text-lg text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
>
|
||||
The complete Git Common-Flow specification
|
||||
</p>
|
||||
</div>
|
||||
<SectionHeader
|
||||
title="The Specification"
|
||||
subtitle="The complete Git Common-Flow specification"
|
||||
class="max-w-3xl mx-auto"
|
||||
/>
|
||||
|
||||
<!-- Content with sidebar -->
|
||||
<div class="lg:flex lg:gap-8">
|
||||
@@ -33,16 +30,16 @@ const { terminology, specification, tocItems } = Astro.props;
|
||||
|
||||
<!-- Main content -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<article class="prose-spec spec-content">
|
||||
<article class="prose-spec">
|
||||
<!-- Terminology -->
|
||||
<section id="terminology">
|
||||
<h2>Terminology</h2>
|
||||
<h2>{terminologyTitle}</h2>
|
||||
<Fragment set:html={terminology} />
|
||||
</section>
|
||||
|
||||
<!-- Main specification -->
|
||||
<section id="specification">
|
||||
<h2>Git Common-Flow Specification</h2>
|
||||
<h2>Specification</h2>
|
||||
<Fragment set:html={specification} />
|
||||
</section>
|
||||
</article>
|
||||
@@ -50,130 +47,3 @@ const { terminology, specification, tocItems } = Astro.props;
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.spec-content {
|
||||
max-width: var(--content-max-width);
|
||||
}
|
||||
|
||||
.spec-content :global(h2) {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
color: var(--color-text-primary);
|
||||
scroll-margin-top: calc(var(--header-height) + 2rem);
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(h2) {
|
||||
border-bottom-color: var(--color-dark-border);
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
|
||||
.spec-content :global(h2:first-child) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.spec-content :global(h3) {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(h3) {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
|
||||
.spec-content :global(p) {
|
||||
margin-bottom: 1.25rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(p) {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
|
||||
.spec-content :global(strong) {
|
||||
color: var(--color-text-primary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(strong) {
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
|
||||
.spec-content :global(ul) {
|
||||
margin-bottom: 1.25rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.spec-content :global(ol) {
|
||||
margin-bottom: 1.25rem;
|
||||
padding-left: 2.5rem;
|
||||
counter-reset: item;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.spec-content :global(ol > li) {
|
||||
counter-increment: item;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.spec-content :global(ol > li::before) {
|
||||
content: counters(item, ".") ".";
|
||||
position: absolute;
|
||||
left: -2.5rem;
|
||||
width: 2rem;
|
||||
text-align: right;
|
||||
font-weight: 500;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(ol > li::before) {
|
||||
color: var(--color-dark-text-muted);
|
||||
}
|
||||
|
||||
.spec-content :global(li) {
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(li) {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
|
||||
.spec-content :global(a) {
|
||||
color: var(--color-accent);
|
||||
text-decoration: none;
|
||||
transition: color 150ms ease;
|
||||
}
|
||||
|
||||
.spec-content :global(a:hover) {
|
||||
color: var(--color-accent-light);
|
||||
}
|
||||
|
||||
.spec-content :global(blockquote) {
|
||||
border-left: 3px solid var(--color-accent);
|
||||
padding-left: 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
color: var(--color-text-muted);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
:global(.dark) .spec-content :global(blockquote) {
|
||||
color: var(--color-dark-text-muted);
|
||||
}
|
||||
|
||||
.spec-content :global(img) {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import TocLink from "./TocLink.astro";
|
||||
import type { TocItem } from "../utils/parseSpecContent";
|
||||
|
||||
interface Props {
|
||||
@@ -12,29 +14,16 @@ const { items } = Astro.props;
|
||||
id="spec-sidebar"
|
||||
class="hidden lg:block lg:sticky lg:top-24 lg:self-start
|
||||
lg:max-h-[calc(100vh-8rem)] lg:overflow-y-auto
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"
|
||||
lg:pr-8 lg:mr-8 lg:border-r border-gray-200 dark:border-neutral-800"
|
||||
>
|
||||
<nav class="space-y-1 py-2">
|
||||
<div
|
||||
class="text-xs font-semibold uppercase tracking-wider mb-4
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]"
|
||||
text-gray-500 dark:text-neutral-500"
|
||||
>
|
||||
On This Page
|
||||
Table of Contents
|
||||
</div>
|
||||
{
|
||||
items.map((item) => (
|
||||
<a
|
||||
href={`#${item.id}`}
|
||||
class={`sidebar-link ${item.level === 3 ? "sidebar-link-sub" : ""}`}
|
||||
data-sidebar-link
|
||||
data-section-id={item.id}
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
{items.map((item) => <TocLink item={item} trackActive />)}
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
@@ -43,19 +32,13 @@ const { items } = Astro.props;
|
||||
id="spec-toc-toggle"
|
||||
class="lg:hidden fixed bottom-6 right-6 z-40
|
||||
w-12 h-12 rounded-full shadow-lg
|
||||
bg-[var(--color-accent)] text-white
|
||||
bg-sky-600 text-white
|
||||
flex items-center justify-center
|
||||
hover:bg-[var(--color-accent-light)]
|
||||
hover:bg-sky-500
|
||||
transition-all duration-200"
|
||||
aria-label="Jump to section"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 6h16M4 12h16M4 18h7"></path>
|
||||
</svg>
|
||||
<Icon name="heroicons:bars-3-bottom-left" class="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
<!-- Mobile TOC drawer -->
|
||||
@@ -70,91 +53,40 @@ const { items } = Astro.props;
|
||||
<!-- Drawer -->
|
||||
<div
|
||||
class="absolute bottom-0 inset-x-0 max-h-[70vh] overflow-y-auto
|
||||
bg-[var(--color-bg-primary)] dark:bg-[var(--color-dark-bg-primary)]
|
||||
bg-gray-50 dark:bg-neutral-950
|
||||
rounded-t-2xl shadow-xl p-6"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<span
|
||||
class="text-sm font-semibold uppercase tracking-wider
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]"
|
||||
text-gray-500 dark:text-neutral-500"
|
||||
>
|
||||
Jump to Section
|
||||
</span>
|
||||
<button
|
||||
class="p-2 rounded-lg hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]"
|
||||
class="p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800"
|
||||
data-toc-close
|
||||
aria-label="Close"
|
||||
>
|
||||
<svg
|
||||
class="w-5 h-5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
<Icon name="heroicons:x-mark" class="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<nav class="space-y-1">
|
||||
{
|
||||
items.map((item) => (
|
||||
<a
|
||||
href={`#${item.id}`}
|
||||
class={`sidebar-link ${item.level === 3 ? "sidebar-link-sub" : ""}`}
|
||||
data-toc-link
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
))
|
||||
}
|
||||
{items.map((item) => <TocLink item={item} />)}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import { initActiveSectionTracker } from "../scripts/activeSectionTracker";
|
||||
|
||||
function initSpecSidebar() {
|
||||
// Active section tracking
|
||||
const sidebarLinks = document.querySelectorAll("[data-sidebar-link]");
|
||||
const sections = new Map<string, Element>();
|
||||
|
||||
sidebarLinks.forEach((link) => {
|
||||
const id = link.getAttribute("data-section-id");
|
||||
if (id) {
|
||||
const section = document.getElementById(id);
|
||||
if (section) {
|
||||
sections.set(id, section);
|
||||
}
|
||||
}
|
||||
// Active section tracking for sidebar links
|
||||
initActiveSectionTracker({
|
||||
linkSelector: "[data-sidebar-link]",
|
||||
});
|
||||
|
||||
// Intersection Observer for active state
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const id = entry.target.getAttribute("id");
|
||||
sidebarLinks.forEach((link) => {
|
||||
const linkId = link.getAttribute("data-section-id");
|
||||
link.classList.toggle("active", linkId === id);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
{
|
||||
rootMargin: "-20% 0% -60% 0%",
|
||||
threshold: 0,
|
||||
}
|
||||
);
|
||||
|
||||
sections.forEach((section) => observer.observe(section));
|
||||
|
||||
// Mobile TOC drawer
|
||||
const toggleBtn = document.getElementById("spec-toc-toggle");
|
||||
const drawer = document.getElementById("spec-toc-drawer");
|
||||
@@ -186,7 +118,7 @@ const { items } = Astro.props;
|
||||
([entry]) => {
|
||||
toggleBtn.classList.toggle("hidden", !entry.isIntersecting);
|
||||
},
|
||||
{ threshold: 0 }
|
||||
{ threshold: 0 },
|
||||
);
|
||||
specObserver.observe(specSection);
|
||||
}
|
||||
@@ -198,22 +130,3 @@ const { items } = Astro.props;
|
||||
// Re-initialize on Astro page transitions
|
||||
document.addEventListener("astro:after-swap", initSpecSidebar);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#spec-sidebar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
#spec-sidebar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#spec-sidebar::-webkit-scrollbar-thumb {
|
||||
background: var(--color-border);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
:global(.dark) #spec-sidebar::-webkit-scrollbar-thumb {
|
||||
background: var(--color-dark-border);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,87 +1,113 @@
|
||||
---
|
||||
// Theme toggle component - sun/moon icon to switch between light and dark mode
|
||||
import { Icon } from "astro-icon/components";
|
||||
---
|
||||
|
||||
<button
|
||||
data-theme-toggle
|
||||
type="button"
|
||||
class="p-2 rounded-lg text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
hover:text-[var(--color-text-primary)]
|
||||
dark:hover:text-[var(--color-dark-text-primary)]
|
||||
hover:bg-[var(--color-bg-secondary)]
|
||||
dark:hover:bg-[var(--color-dark-bg-secondary)]
|
||||
transition-colors duration-200"
|
||||
aria-label="Toggle dark mode"
|
||||
>
|
||||
<!-- Sun icon (shown in dark mode) -->
|
||||
<svg
|
||||
data-sun-icon
|
||||
class="hidden w-5 h-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
<div class="relative group">
|
||||
<button
|
||||
data-theme-toggle
|
||||
type="button"
|
||||
class="p-2 rounded-lg cursor-pointer transition-colors duration-200
|
||||
text-gray-500 dark:text-neutral-500
|
||||
hover:text-gray-950 dark:hover:text-neutral-50
|
||||
hover:bg-gray-100 dark:hover:bg-neutral-800"
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343
|
||||
6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16
|
||||
12a4 4 0 11-8 0 4 4 0 018 0z"></path>
|
||||
</svg>
|
||||
<!-- Moon icon (shown in light mode) -->
|
||||
<svg
|
||||
data-moon-icon
|
||||
class="w-5 h-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
<Icon
|
||||
name="heroicons:sun"
|
||||
data-theme-icon="light"
|
||||
class="hidden w-5 h-5"
|
||||
/>
|
||||
<Icon
|
||||
name="heroicons:moon"
|
||||
data-theme-icon="dark"
|
||||
class="hidden w-5 h-5"
|
||||
/>
|
||||
<Icon
|
||||
name="heroicons:computer-desktop"
|
||||
data-theme-icon="auto"
|
||||
class="hidden w-5 h-5"
|
||||
/>
|
||||
</button>
|
||||
<!-- Tooltip -->
|
||||
<div
|
||||
class="absolute left-1/2 -translate-x-1/2 top-full mt-2
|
||||
px-2 py-1 text-xs font-medium whitespace-nowrap rounded-md shadow-sm
|
||||
bg-gray-900 text-white dark:bg-white dark:text-gray-900
|
||||
opacity-0 group-hover:opacity-100
|
||||
transition-opacity duration-200 pointer-events-none"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003
|
||||
9.003 0 008.354-5.646z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<span data-tooltip-text="light" class="hidden">Light</span>
|
||||
<span data-tooltip-text="dark" class="hidden">Dark</span>
|
||||
<span data-tooltip-text="auto" class="hidden">System</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
type ThemeMode = "light" | "dark" | "auto";
|
||||
|
||||
function initTheme() {
|
||||
const toggles = document.querySelectorAll(
|
||||
"[data-theme-toggle]"
|
||||
"[data-theme-toggle]",
|
||||
) as NodeListOf<HTMLButtonElement>;
|
||||
|
||||
function getTheme(): "dark" | "light" {
|
||||
function getStoredMode(): ThemeMode {
|
||||
const stored = localStorage.getItem("theme");
|
||||
if (stored === "dark" || stored === "light") {
|
||||
if (stored === "dark" || stored === "light" || stored === "auto") {
|
||||
return stored;
|
||||
}
|
||||
return "auto";
|
||||
}
|
||||
|
||||
function getSystemTheme(): "dark" | "light" {
|
||||
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
}
|
||||
|
||||
function updateAllIcons(isDark: boolean) {
|
||||
// Update all sun/moon icons on the page
|
||||
document.querySelectorAll("[data-sun-icon]").forEach((icon) => {
|
||||
icon.classList.toggle("hidden", !isDark);
|
||||
function getEffectiveTheme(mode: ThemeMode): "dark" | "light" {
|
||||
if (mode === "auto") {
|
||||
return getSystemTheme();
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
function updateAllIcons(mode: ThemeMode) {
|
||||
document.querySelectorAll("[data-theme-icon]").forEach((icon) => {
|
||||
const iconMode = (icon as HTMLElement).dataset.themeIcon;
|
||||
icon.classList.toggle("hidden", iconMode !== mode);
|
||||
});
|
||||
document.querySelectorAll("[data-moon-icon]").forEach((icon) => {
|
||||
icon.classList.toggle("hidden", isDark);
|
||||
document.querySelectorAll("[data-tooltip-text]").forEach((text) => {
|
||||
const textMode = (text as HTMLElement).dataset.tooltipText;
|
||||
text.classList.toggle("hidden", textMode !== mode);
|
||||
});
|
||||
}
|
||||
|
||||
function setTheme(theme: "dark" | "light") {
|
||||
localStorage.setItem("theme", theme);
|
||||
document.documentElement.classList.toggle("dark", theme === "dark");
|
||||
updateAllIcons(theme === "dark");
|
||||
function applyTheme(mode: ThemeMode) {
|
||||
const effective = getEffectiveTheme(mode);
|
||||
if (effective === "dark") {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
updateAllIcons(mode);
|
||||
}
|
||||
|
||||
function setMode(mode: ThemeMode) {
|
||||
localStorage.setItem("theme", mode);
|
||||
applyTheme(mode);
|
||||
}
|
||||
|
||||
function cycleMode(): ThemeMode {
|
||||
const current = getStoredMode();
|
||||
// Cycle: light → dark → auto → light
|
||||
if (current === "light") return "dark";
|
||||
if (current === "dark") return "auto";
|
||||
return "light";
|
||||
}
|
||||
|
||||
// Initialize theme
|
||||
const currentTheme = getTheme();
|
||||
setTheme(currentTheme);
|
||||
const currentMode = getStoredMode();
|
||||
applyTheme(currentMode);
|
||||
|
||||
// Attach click handlers to all toggle buttons
|
||||
toggles.forEach((toggle) => {
|
||||
@@ -90,17 +116,16 @@
|
||||
toggle.dataset.initialized = "true";
|
||||
|
||||
toggle.addEventListener("click", () => {
|
||||
const isDark = document.documentElement.classList.contains("dark");
|
||||
setTheme(isDark ? "light" : "dark");
|
||||
setMode(cycleMode());
|
||||
});
|
||||
});
|
||||
|
||||
// Listen for system preference changes
|
||||
// Listen for system preference changes (only affects auto mode)
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", (e) => {
|
||||
if (!localStorage.getItem("theme")) {
|
||||
setTheme(e.matches ? "dark" : "light");
|
||||
.addEventListener("change", () => {
|
||||
if (getStoredMode() === "auto") {
|
||||
applyTheme("auto");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
34
src/components/TocLink.astro
Normal file
34
src/components/TocLink.astro
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
import type { TocItem } from "../utils/parseSpecContent";
|
||||
|
||||
interface Props {
|
||||
item: TocItem;
|
||||
trackActive?: boolean;
|
||||
}
|
||||
|
||||
const { item, trackActive = false } = Astro.props;
|
||||
---
|
||||
|
||||
<a
|
||||
href={`#${item.id}`}
|
||||
class:list={[
|
||||
"sidebar-link block py-2 px-4 text-sm rounded-md",
|
||||
"transition-colors",
|
||||
"text-gray-500 hover:text-gray-950 hover:bg-gray-100",
|
||||
"dark:text-neutral-500 dark:hover:text-neutral-50 dark:hover:bg-neutral-800",
|
||||
item.level === 3 && "pl-6 text-[0.8125rem]",
|
||||
item.clause && "flex",
|
||||
]}
|
||||
data-sidebar-link={trackActive ? "" : undefined}
|
||||
data-section-id={trackActive ? item.id : undefined}
|
||||
data-toc-link={!trackActive ? "" : undefined}
|
||||
>
|
||||
{
|
||||
item.clause && (
|
||||
<span class="shrink-0 w-6 text-gray-400 dark:text-neutral-600">
|
||||
{item.clause}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
@@ -1,4 +1,6 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
|
||||
interface Props {
|
||||
currentVersion: string;
|
||||
versions: string[];
|
||||
@@ -7,76 +9,128 @@ interface Props {
|
||||
const { currentVersion, versions } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="version-selector relative">
|
||||
<select
|
||||
data-version-select
|
||||
class="appearance-none bg-transparent border border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)] rounded-lg px-3 py-1.5
|
||||
pr-8 text-sm font-mono cursor-pointer
|
||||
text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]
|
||||
hover:border-[var(--color-accent)]
|
||||
focus:border-[var(--color-accent)]
|
||||
focus:outline-none transition-colors"
|
||||
<div class="relative" data-version-selector>
|
||||
<!-- Trigger button -->
|
||||
<button
|
||||
type="button"
|
||||
data-version-trigger
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded="false"
|
||||
class="flex items-center gap-1.5 px-2.5 py-1.5 text-sm font-mono
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-md bg-transparent cursor-pointer transition-colors
|
||||
text-gray-600 dark:text-neutral-400
|
||||
hover:border-sky-600 hover:text-gray-950 dark:hover:text-neutral-50"
|
||||
>
|
||||
<span>v{currentVersion}</span>
|
||||
<Icon
|
||||
name="heroicons:chevron-down"
|
||||
data-arrow-icon
|
||||
class="w-3.5 h-3.5 transition-transform duration-150"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<!-- Dropdown menu -->
|
||||
<div
|
||||
data-version-dropdown
|
||||
role="listbox"
|
||||
aria-label="Select version"
|
||||
class="absolute top-full left-0 mt-2 min-w-full p-1.5 z-50
|
||||
bg-gray-50 dark:bg-neutral-900
|
||||
border border-gray-200 dark:border-neutral-700
|
||||
rounded-lg shadow-lg
|
||||
opacity-0 invisible -translate-y-1 transition-all duration-150
|
||||
data-[open]:opacity-100 data-[open]:visible data-[open]:translate-y-0"
|
||||
>
|
||||
{
|
||||
versions.map((v) => (
|
||||
<option value={v} selected={v === currentVersion}>
|
||||
<a
|
||||
href={`/spec/${v}`}
|
||||
role="option"
|
||||
aria-selected={v === currentVersion}
|
||||
class:list={[
|
||||
"block px-3 py-2 font-mono text-sm rounded transition-colors",
|
||||
"text-gray-600 dark:text-neutral-400",
|
||||
"hover:bg-gray-100 dark:hover:bg-neutral-800",
|
||||
"hover:text-gray-950 dark:hover:text-neutral-50",
|
||||
v === currentVersion && [
|
||||
"bg-sky-500/15 dark:bg-sky-500/20",
|
||||
"text-sky-600 dark:text-sky-400",
|
||||
],
|
||||
]}
|
||||
>
|
||||
v{v}
|
||||
</option>
|
||||
</a>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
<!-- Dropdown arrow -->
|
||||
<svg
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 pointer-events-none
|
||||
text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function initVersionSelectors() {
|
||||
const selects = document.querySelectorAll(
|
||||
"[data-version-select]"
|
||||
) as NodeListOf<HTMLSelectElement>;
|
||||
const selectors = document.querySelectorAll("[data-version-selector]");
|
||||
|
||||
selects.forEach((select) => {
|
||||
// Avoid adding duplicate listeners
|
||||
if (select.dataset.initialized) return;
|
||||
select.dataset.initialized = "true";
|
||||
selectors.forEach((selector) => {
|
||||
if ((selector as HTMLElement).dataset.initialized) return;
|
||||
(selector as HTMLElement).dataset.initialized = "true";
|
||||
|
||||
select.addEventListener("change", (e) => {
|
||||
const target = e.target as HTMLSelectElement;
|
||||
const version = target.value;
|
||||
window.location.href = `/spec/${version}`;
|
||||
const trigger = selector.querySelector(
|
||||
"[data-version-trigger]",
|
||||
) as HTMLButtonElement;
|
||||
const dropdown = selector.querySelector(
|
||||
"[data-version-dropdown]",
|
||||
) as HTMLElement;
|
||||
const arrow = selector.querySelector("[data-arrow-icon]") as HTMLElement;
|
||||
|
||||
if (!trigger || !dropdown) return;
|
||||
|
||||
const open = () => {
|
||||
dropdown.dataset.open = "true";
|
||||
trigger.setAttribute("aria-expanded", "true");
|
||||
if (arrow) arrow.style.transform = "rotate(180deg)";
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
delete dropdown.dataset.open;
|
||||
trigger.setAttribute("aria-expanded", "false");
|
||||
if (arrow) arrow.style.transform = "";
|
||||
};
|
||||
|
||||
trigger.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
const isOpen = dropdown.dataset.open === "true";
|
||||
|
||||
// Close all other dropdowns
|
||||
document
|
||||
.querySelectorAll("[data-version-dropdown][data-open]")
|
||||
.forEach((d) => {
|
||||
delete (d as HTMLElement).dataset.open;
|
||||
const t = d.previousElementSibling as HTMLElement;
|
||||
t?.setAttribute("aria-expanded", "false");
|
||||
const a = t?.querySelector("[data-arrow-icon]") as HTMLElement;
|
||||
if (a) a.style.transform = "";
|
||||
});
|
||||
|
||||
if (isOpen) {
|
||||
close();
|
||||
} else {
|
||||
open();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!selector.contains(e.target as Node)) close();
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape" && dropdown.dataset.open === "true") {
|
||||
close();
|
||||
trigger.focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize on load
|
||||
initVersionSelectors();
|
||||
|
||||
// Re-initialize on Astro page transitions
|
||||
document.addEventListener("astro:after-swap", initVersionSelectors);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
select option {
|
||||
background-color: var(--color-bg-primary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
:global(.dark) select option {
|
||||
background-color: var(--color-dark-bg-primary);
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
export const config = {
|
||||
title: "Git Common Flow",
|
||||
title: "Git Common-Flow",
|
||||
description:
|
||||
"An attempt to gather a sensible selection of the most common usage " +
|
||||
"patterns of git into a single and concise specification.",
|
||||
author: "Jim Myhrberg",
|
||||
authorUrl: "https://jimeh.me/",
|
||||
hostname: "commonflow.org",
|
||||
url: "https://commonflow.org",
|
||||
repoUrl: "https://github.com/jimeh/common-flow",
|
||||
license: {
|
||||
name: "CC BY 4.0",
|
||||
url: "https://creativecommons.org/licenses/by/4.0/",
|
||||
},
|
||||
|
||||
currentVersion: "1.0.0-rc.5",
|
||||
versions: [
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
title: Git Common-Flow 1.0.0-rc.1
|
||||
version: 1.0.0-rc.1
|
||||
---
|
||||
Git Common-Flow 1.0.0-rc.1
|
||||
==============================
|
||||
|
||||
# Git Common-Flow 1.0.0-rc.1
|
||||
|
||||
<img src="/spec/1.0.0-rc.1.svg" alt="Git Common-Flow 1.0.0-rc.1 diagram" width="100%" />
|
||||
|
||||
Summary
|
||||
-------
|
||||
## Summary
|
||||
|
||||
Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
@@ -20,8 +19,7 @@ TL;DR: Common-Flow is basically GitHub Flow with the addition of versioned
|
||||
releases, maintenance releases for old versions, and without the requirement to
|
||||
deploy to production all the time.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
## Terminology
|
||||
|
||||
- **Master Branch** - Must always have passing tests, is considered bleeding
|
||||
edge, and must be named `master`.
|
||||
@@ -45,131 +43,129 @@ Terminology
|
||||
commit and release tag are on a maintenance branch instead of the master
|
||||
branch.
|
||||
|
||||
Git Common-Flow Specification (Common-Flow)
|
||||
-------------------------------------------
|
||||
## Git Common-Flow Specification (Common-Flow)
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
|
||||
1. The Master Branch
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST be considered bleeding edge.
|
||||
3. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch SHOULD always be in a "as near as possible ready for
|
||||
release/production" state to reduce the friction of creating a new
|
||||
release.
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST be considered bleeding edge.
|
||||
3. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch SHOULD always be in a "as near as possible ready for
|
||||
release/production" state to reduce the friction of creating a new
|
||||
release.
|
||||
2. Changes
|
||||
1. Changes MUST be performed on a separate branch that SHOULD be referred to
|
||||
as a "change branch". All change branches MUST have descriptive names. It
|
||||
is RECOMMENDED that you commit often locally, and you SHOULD regularly
|
||||
push your work to the same named branch on the remote server.
|
||||
2. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target branch", typically this will be the same
|
||||
as the source branch.
|
||||
3. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch. To be clear you MUST NOT merge a source branch into a
|
||||
change branch.
|
||||
4. After rebasing a change branch on top of its source branch you MUST push
|
||||
the change branch to the remote server. This will require you do a force
|
||||
push, and you SHOULD use the "--force-with-lease" git push option.
|
||||
5. To merge a change branch into its merge target branch, you MUST open a
|
||||
"pull request" (or equivalent) so others can review and approve your
|
||||
changes.
|
||||
6. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
7. To get feedback, help, or generally just discuss a change branch with
|
||||
others, it is RECOMMENDED you do this by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
1. Changes MUST be performed on a separate branch that SHOULD be referred to
|
||||
as a "change branch". All change branches MUST have descriptive names. It
|
||||
is RECOMMENDED that you commit often locally, and you SHOULD regularly
|
||||
push your work to the same named branch on the remote server.
|
||||
2. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target branch", typically this will be the same
|
||||
as the source branch.
|
||||
3. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch. To be clear you MUST NOT merge a source branch into a
|
||||
change branch.
|
||||
4. After rebasing a change branch on top of its source branch you MUST push
|
||||
the change branch to the remote server. This will require you do a force
|
||||
push, and you SHOULD use the "--force-with-lease" git push option.
|
||||
5. To merge a change branch into its merge target branch, you MUST open a
|
||||
"pull request" (or equivalent) so others can review and approve your
|
||||
changes.
|
||||
6. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
7. To get feedback, help, or generally just discuss a change branch with
|
||||
others, it is RECOMMENDED you do this by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
3. Git Best Practices
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
documentation:
|
||||
<https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project>
|
||||
2. You SHOULD always use "--force-with-lease" when doing a force push. The
|
||||
plain "--force" option is dangerous and destructive. More
|
||||
information:
|
||||
<https://developer.atlassian.com/blog/2015/04/force-with-lease/>
|
||||
3. You SHOULD understand and be comfortable with
|
||||
rebasing: <https://git-scm.com/book/en/v2/Git-Branching-Rebasing>
|
||||
4. It is RECOMMENDED that you always do "git pull --rebase" instead of "git
|
||||
pull" to avoid unnecessary merge commits. You can make this the default
|
||||
behavior of "git pull" with "git config --global pull.rebase true".
|
||||
5. It is RECOMMENDED that all branches be merged using "git merge --no-ff".
|
||||
This makes sure the reference to the original branch is kept in the commits,
|
||||
allows one to revert a merge by reverting a single merge commit, and creates
|
||||
a merge commit to mark the integration of the branch with master.
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
documentation:
|
||||
<https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project>
|
||||
2. You SHOULD always use "--force-with-lease" when doing a force push. The
|
||||
plain "--force" option is dangerous and destructive. More
|
||||
information:
|
||||
<https://developer.atlassian.com/blog/2015/04/force-with-lease/>
|
||||
3. You SHOULD understand and be comfortable with
|
||||
rebasing: <https://git-scm.com/book/en/v2/Git-Branching-Rebasing>
|
||||
4. It is RECOMMENDED that you always do "git pull --rebase" instead of "git
|
||||
pull" to avoid unnecessary merge commits. You can make this the default
|
||||
behavior of "git pull" with "git config --global pull.rebase true".
|
||||
5. It is RECOMMENDED that all branches be merged using "git merge --no-ff".
|
||||
This makes sure the reference to the original branch is kept in the commits,
|
||||
allows one to revert a merge by reverting a single merge commit, and creates
|
||||
a merge commit to mark the integration of the branch with master.
|
||||
4. Versioning
|
||||
1. The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
located in the root of the project.
|
||||
2. If you are using a "VERSION" file in the root of the project, this MUST
|
||||
only contain the exact version string.
|
||||
3. The version string SHOULD follow the Semantic Versioning
|
||||
(<http://semver.org/>) format. Use of Semantic Versioning is OPTIONAL,
|
||||
but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.
|
||||
1. The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
located in the root of the project.
|
||||
2. If you are using a "VERSION" file in the root of the project, this MUST
|
||||
only contain the exact version string.
|
||||
3. The version string SHOULD follow the Semantic Versioning
|
||||
(<http://semver.org/>) format. Use of Semantic Versioning is OPTIONAL,
|
||||
but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.
|
||||
5. Releases
|
||||
1. To create a new release, you MUST create a "version bump" commit directly
|
||||
on the master branch which changes the hard-coded version value of the
|
||||
project. The version bump commit MUST have a git tag created on it and
|
||||
named as the exact version string.
|
||||
2. A version bump commit MUST have a commit message title of "Bump version
|
||||
to VERSION". For example, if the new version string is "2.11.4", the
|
||||
first line of the commit message MUST read: "Bump version to 2.11.4"
|
||||
3. The release tag on the version bump commit MUST be named exactly the same
|
||||
as the version string. The tag name can OPTIONALLY be prefixed with
|
||||
"v". For example the tag name can be either "2.11.4" or "v2.11.4".
|
||||
4. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
5. If you use annotated release tags, the first line of the annotation MUST
|
||||
read "Release VERSION". For example for version "2.11.4" the first line
|
||||
of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.
|
||||
1. To create a new release, you MUST create a "version bump" commit directly
|
||||
on the master branch which changes the hard-coded version value of the
|
||||
project. The version bump commit MUST have a git tag created on it and
|
||||
named as the exact version string.
|
||||
2. A version bump commit MUST have a commit message title of "Bump version
|
||||
to VERSION". For example, if the new version string is "2.11.4", the
|
||||
first line of the commit message MUST read: "Bump version to 2.11.4"
|
||||
3. The release tag on the version bump commit MUST be named exactly the same
|
||||
as the version string. The tag name can OPTIONALLY be prefixed with
|
||||
"v". For example the tag name can be either "2.11.4" or "v2.11.4".
|
||||
4. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
5. If you use annotated release tags, the first line of the annotation MUST
|
||||
read "Release VERSION". For example for version "2.11.4" the first line
|
||||
of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.
|
||||
6. Bug Fixes & Rollback
|
||||
1. You MUST NOT under any circumstances force push to the master branch.
|
||||
2. If a change branch which has been merged in to the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged in to master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
1. You MUST NOT under any circumstances force push to the master branch.
|
||||
2. If a change branch which has been merged in to the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged in to master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
7. Maintenance Releases
|
||||
1. Any branch that has a name starting with "stable-" SHOULD be referred to
|
||||
as a "maintenance branch".
|
||||
2. Maintenance branches are used for managing new releases of older
|
||||
versions. Typically this is used to provide security updates for older
|
||||
versions when the master branch has moved on to a point that a new
|
||||
release for the old version cannot be made from the master branch.
|
||||
3. A "maintenance release" is identical to a regular release, except the
|
||||
version bump commit and the release tag are placed on the maintenance
|
||||
branch instead of on the master branch.
|
||||
3. A maintenance branch SHOULD follow a "stable-X.Y" naming pattern, where
|
||||
"X" is the MAJOR version and "Y" is the minor version.
|
||||
4. A maintenance branch MUST be created from the relevant release tag. For
|
||||
example if there is a security fix for all 2.9.x releases, the latest of
|
||||
which is "2.9.7", we create a new branch called "stable-2.9" off of the
|
||||
"2.9.7" release tag. The security fix release will then end up being
|
||||
version "2.9.8".
|
||||
5. When working on a maintenance release, the relevant maintenance branch
|
||||
MUST be thought of as the master branch for that maintenance work.
|
||||
6. Changes in a maintenance branch SHOULD typically come from work being
|
||||
done against the master branch. Meaning changes SHOULD only trickle
|
||||
downwards from the master branch. If a change needs to trickle back up
|
||||
into the master branch, that work should have happened against the master
|
||||
branch in the first place.
|
||||
1. Any branch that has a name starting with "stable-" SHOULD be referred to
|
||||
as a "maintenance branch".
|
||||
2. Maintenance branches are used for managing new releases of older
|
||||
versions. Typically this is used to provide security updates for older
|
||||
versions when the master branch has moved on to a point that a new
|
||||
release for the old version cannot be made from the master branch.
|
||||
3. A "maintenance release" is identical to a regular release, except the
|
||||
version bump commit and the release tag are placed on the maintenance
|
||||
branch instead of on the master branch.
|
||||
4. A maintenance branch SHOULD follow a "stable-X.Y" naming pattern, where
|
||||
"X" is the MAJOR version and "Y" is the minor version.
|
||||
5. A maintenance branch MUST be created from the relevant release tag. For
|
||||
example if there is a security fix for all 2.9.x releases, the latest of
|
||||
which is "2.9.7", we create a new branch called "stable-2.9" off of the
|
||||
"2.9.7" release tag. The security fix release will then end up being
|
||||
version "2.9.8".
|
||||
6. When working on a maintenance release, the relevant maintenance branch
|
||||
MUST be thought of as the master branch for that maintenance work.
|
||||
7. Changes in a maintenance branch SHOULD typically come from work being
|
||||
done against the master branch. Meaning changes SHOULD only trickle
|
||||
downwards from the master branch. If a change needs to trickle back up
|
||||
into the master branch, that work should have happened against the master
|
||||
branch in the first place.
|
||||
|
||||
About
|
||||
-----
|
||||
## About
|
||||
|
||||
The Git Common-Flow specification is authored
|
||||
by [Jim Myhrberg](http://jimeh.me).
|
||||
@@ -177,7 +173,6 @@ by [Jim Myhrberg](http://jimeh.me).
|
||||
If you'd like to leave feedback,
|
||||
please [open an issue on GitHub](https://github.com/jimeh/common-flow/issues).
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
[Creative Commons - CC BY 3.0](http://creativecommons.org/licenses/by/3.0/)
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
title: Git Common-Flow 1.0.0-rc.2
|
||||
version: 1.0.0-rc.2
|
||||
---
|
||||
Git Common-Flow 1.0.0-rc.2
|
||||
==============================
|
||||
|
||||
# Git Common-Flow 1.0.0-rc.2
|
||||
|
||||
<img src="/spec/1.0.0-rc.2.svg" alt="Git Common-Flow 1.0.0-rc.2 diagram" width="100%" />
|
||||
|
||||
Summary
|
||||
-------
|
||||
## Summary
|
||||
|
||||
Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
@@ -20,8 +19,7 @@ TL;DR: Common-Flow is basically GitHub Flow with the addition of versioned
|
||||
releases, maintenance releases for old versions, and without the requirement to
|
||||
deploy to production all the time.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
## Terminology
|
||||
|
||||
- **Master Branch** - Must always have passing tests, is considered bleeding
|
||||
edge, and must be named `master`.
|
||||
@@ -40,161 +38,159 @@ Terminology
|
||||
- **Release Branches** - Used both for short-term preparations of a release, and
|
||||
also for long-term maintenance of older version.
|
||||
|
||||
Git Common-Flow Specification (Common-Flow)
|
||||
-------------------------------------------
|
||||
## Git Common-Flow Specification (Common-Flow)
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
|
||||
1. The Master Branch
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST be considered bleeding edge.
|
||||
3. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST be considered bleeding edge.
|
||||
3. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
2. Change Branches
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches". All change
|
||||
branches MUST have descriptive names. It is RECOMMENDED that you commit
|
||||
often locally, and you SHOULD regularly push your work to the same named
|
||||
branch on the remote server.
|
||||
2. You MUST create separate change branches for each distinctly different
|
||||
change. You MUST NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
3. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
4. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
5. After rebasing a change branch on top of its source branch you MUST push
|
||||
the change branch to the remote server. This will require you to do a
|
||||
force push, and you SHOULD use the "--force-with-lease" git push option.
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches". All change
|
||||
branches MUST have descriptive names. It is RECOMMENDED that you commit
|
||||
often locally, and you SHOULD regularly push your work to the same named
|
||||
branch on the remote server.
|
||||
2. You MUST create separate change branches for each distinctly different
|
||||
change. You MUST NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
3. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
4. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
5. After rebasing a change branch on top of its source branch you MUST push
|
||||
the change branch to the remote server. This will require you to do a
|
||||
force push, and you SHOULD use the "--force-with-lease" git push option.
|
||||
3. Pull Requests
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent) so others can review and approve your changes.
|
||||
2. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
3. To get feedback, help, or generally just discuss a change branch with
|
||||
others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent) so others can review and approve your changes.
|
||||
2. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
3. To get feedback, help, or generally just discuss a change branch with
|
||||
others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
4. Versioning
|
||||
1. The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
located in the root of the project.
|
||||
2. If you are using a "VERSION" file in the root of the project, this MUST
|
||||
only contain the exact version string.
|
||||
3. The version string SHOULD follow the Semantic Versioning
|
||||
(<http://semver.org/>) format. Use of Semantic Versioning is OPTIONAL,
|
||||
but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.
|
||||
1. The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
located in the root of the project.
|
||||
2. If you are using a "VERSION" file in the root of the project, this MUST
|
||||
only contain the exact version string.
|
||||
3. The version string SHOULD follow the Semantic Versioning
|
||||
(<http://semver.org/>) format. Use of Semantic Versioning is OPTIONAL,
|
||||
but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.
|
||||
5. Releases
|
||||
1. To create a new release, you MUST create a "version bump" commit which
|
||||
changes the hard-coded version string of the project. The version bump
|
||||
commit MUST have a git tag created on it and named as the exact version
|
||||
string.
|
||||
2. If you are not using a release branch, then the version bump commit MUST
|
||||
be created directly on the master branch.
|
||||
3. The version bump commit MUST have a commit message title of "Bump version
|
||||
to VERSION". For example, if the new version string is "2.11.4", the
|
||||
first line of the commit message MUST read: "Bump version to 2.11.4"
|
||||
4. The release tag on the version bump commit MUST be named exactly the same
|
||||
as the version string. The tag name can OPTIONALLY be prefixed with
|
||||
"v". For example the tag name can be either "2.11.4" or "v2.11.4". You
|
||||
MUST not use a mix of "v" prefixed and non-prefixed tags. Pick one form
|
||||
and stick to it.
|
||||
5. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
6. If you use annotated release tags, the first line of the annotation MUST
|
||||
read "Release VERSION". For example for version "2.11.4" the first line
|
||||
of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.
|
||||
1. To create a new release, you MUST create a "version bump" commit which
|
||||
changes the hard-coded version string of the project. The version bump
|
||||
commit MUST have a git tag created on it and named as the exact version
|
||||
string.
|
||||
2. If you are not using a release branch, then the version bump commit MUST
|
||||
be created directly on the master branch.
|
||||
3. The version bump commit MUST have a commit message title of "Bump version
|
||||
to VERSION". For example, if the new version string is "2.11.4", the
|
||||
first line of the commit message MUST read: "Bump version to 2.11.4"
|
||||
4. The release tag on the version bump commit MUST be named exactly the same
|
||||
as the version string. The tag name can OPTIONALLY be prefixed with
|
||||
"v". For example the tag name can be either "2.11.4" or "v2.11.4". You
|
||||
MUST not use a mix of "v" prefixed and non-prefixed tags. Pick one form
|
||||
and stick to it.
|
||||
5. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
6. If you use annotated release tags, the first line of the annotation MUST
|
||||
read "Release VERSION". For example for version "2.11.4" the first line
|
||||
of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.
|
||||
6. Release Branches
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Use of release branches is OPTIONAL.
|
||||
3. Changes in a release branch SHOULD typically come from work being
|
||||
done against the master branch. Meaning changes SHOULD only trickle
|
||||
downwards from the master branch. If a change needs to trickle back up
|
||||
into the master branch, that work should have happened against the master
|
||||
branch in the first place. One exception to this is version bump commits.
|
||||
4. There are two types of release branches; short-term, and long-term.
|
||||
5. Short-Term Release Branches
|
||||
1. Used for creating a specific versioned release.
|
||||
2. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
3. MUST have a name of "release-VERSION". For example for version
|
||||
"2.11.4" the release branch name MUST be "release-2.11.4".
|
||||
4. When using a short-term release branch, the version bump commit and
|
||||
release tag MUST be made directly on the release branch itself.
|
||||
5. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master
|
||||
branch, and SHOULD be pulled into the release branch by rebasing it
|
||||
on top of the master branch the same way a change branch pulls in
|
||||
updates from its source branch.
|
||||
6. After the version bump commit and release tag have been created, the
|
||||
release branch MUST be merged back into its source branch and then
|
||||
deleted. Typically the source branch will be the master branch.
|
||||
6. Long-Term Release Branches
|
||||
1. Used for work on versions which are not currently part of the master
|
||||
branch. Typically this is useful when you need to create a new
|
||||
maintenance release for a older version.
|
||||
2. The branch name MUST have a non-specific version number. For example
|
||||
a long-term release branch for creating new 2.9.x releases would be
|
||||
named "release-2.9".
|
||||
3. To create a new release from a long-term release branch, you MUST
|
||||
create a version bump commit and release tag directly on the release
|
||||
branch.
|
||||
4. A long-term release branch MUST be created from the relevant release
|
||||
tag. For example if the master branch is on version 2.11.4 and there
|
||||
is a security fix for all 2.9.x releases, the latest of which is
|
||||
"2.9.7". Create a new branch called "release-2.9" off of the "2.9.7"
|
||||
release tag. The security fix release will then end up being version
|
||||
"2.9.8".
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Use of release branches is OPTIONAL.
|
||||
3. Changes in a release branch SHOULD typically come from work being
|
||||
done against the master branch. Meaning changes SHOULD only trickle
|
||||
downwards from the master branch. If a change needs to trickle back up
|
||||
into the master branch, that work should have happened against the master
|
||||
branch in the first place. One exception to this is version bump commits.
|
||||
4. There are two types of release branches; short-term, and long-term.
|
||||
5. Short-Term Release Branches
|
||||
1. Used for creating a specific versioned release.
|
||||
2. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
3. MUST have a name of "release-VERSION". For example for version
|
||||
"2.11.4" the release branch name MUST be "release-2.11.4".
|
||||
4. When using a short-term release branch, the version bump commit and
|
||||
release tag MUST be made directly on the release branch itself.
|
||||
5. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master
|
||||
branch, and SHOULD be pulled into the release branch by rebasing it
|
||||
on top of the master branch the same way a change branch pulls in
|
||||
updates from its source branch.
|
||||
6. After the version bump commit and release tag have been created, the
|
||||
release branch MUST be merged back into its source branch and then
|
||||
deleted. Typically the source branch will be the master branch.
|
||||
6. Long-Term Release Branches
|
||||
1. Used for work on versions which are not currently part of the master
|
||||
branch. Typically this is useful when you need to create a new
|
||||
maintenance release for a older version.
|
||||
2. The branch name MUST have a non-specific version number. For example
|
||||
a long-term release branch for creating new 2.9.x releases would be
|
||||
named "release-2.9".
|
||||
3. To create a new release from a long-term release branch, you MUST
|
||||
create a version bump commit and release tag directly on the release
|
||||
branch.
|
||||
4. A long-term release branch MUST be created from the relevant release
|
||||
tag. For example if the master branch is on version 2.11.4 and there
|
||||
is a security fix for all 2.9.x releases, the latest of which is
|
||||
"2.9.7". Create a new branch called "release-2.9" off of the "2.9.7"
|
||||
release tag. The security fix release will then end up being version
|
||||
"2.9.8".
|
||||
7. Bug Fixes & Rollback
|
||||
1. You MUST NOT under any circumstances force push to the master branch.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
1. You MUST NOT under any circumstances force push to the master branch.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
8. Git Best Practices
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
documentation:
|
||||
<https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project>
|
||||
2. You SHOULD never blindly commit all changes with "git commit -a". It is
|
||||
RECOMMENDED you use "git add -i" to add individual changes to the staging
|
||||
area so you are fully aware of what you are committing.
|
||||
3. You SHOULD always use "--force-with-lease" when doing a force push. The
|
||||
regular "--force" option is dangerous and destructive. More
|
||||
information:
|
||||
<https://developer.atlassian.com/blog/2015/04/force-with-lease/>
|
||||
4. You SHOULD understand and be comfortable with
|
||||
rebasing: <https://git-scm.com/book/en/v2/Git-Branching-Rebasing>
|
||||
5. It is RECOMMENDED that you always do "git pull --rebase" instead of "git
|
||||
pull" to avoid unnecessary merge commits. You can make this the default
|
||||
behavior of "git pull" with "git config --global pull.rebase true".
|
||||
6. It is RECOMMENDED that all branches be merged using "git merge --no-ff".
|
||||
This makes sure the reference to the original branch is kept in the
|
||||
commits, allows one to revert a merge by reverting a single merge commit,
|
||||
and creates a merge commit to mark the integration of the branch with
|
||||
master.
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
documentation:
|
||||
<https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project>
|
||||
2. You SHOULD never blindly commit all changes with "git commit -a". It is
|
||||
RECOMMENDED you use "git add -i" to add individual changes to the staging
|
||||
area so you are fully aware of what you are committing.
|
||||
3. You SHOULD always use "--force-with-lease" when doing a force push. The
|
||||
regular "--force" option is dangerous and destructive. More
|
||||
information:
|
||||
<https://developer.atlassian.com/blog/2015/04/force-with-lease/>
|
||||
4. You SHOULD understand and be comfortable with
|
||||
rebasing: <https://git-scm.com/book/en/v2/Git-Branching-Rebasing>
|
||||
5. It is RECOMMENDED that you always do "git pull --rebase" instead of "git
|
||||
pull" to avoid unnecessary merge commits. You can make this the default
|
||||
behavior of "git pull" with "git config --global pull.rebase true".
|
||||
6. It is RECOMMENDED that all branches be merged using "git merge --no-ff".
|
||||
This makes sure the reference to the original branch is kept in the
|
||||
commits, allows one to revert a merge by reverting a single merge commit,
|
||||
and creates a merge commit to mark the integration of the branch with
|
||||
master.
|
||||
|
||||
About
|
||||
-----
|
||||
## About
|
||||
|
||||
The Git Common-Flow specification is authored
|
||||
by [Jim Myhrberg](http://jimeh.me).
|
||||
@@ -202,7 +198,6 @@ by [Jim Myhrberg](http://jimeh.me).
|
||||
If you'd like to leave feedback,
|
||||
please [open an issue on GitHub](https://github.com/jimeh/common-flow/issues).
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
[Creative Commons - CC BY 3.0](http://creativecommons.org/licenses/by/3.0/)
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
title: Git Common-Flow 1.0.0-rc.3
|
||||
version: 1.0.0-rc.3
|
||||
---
|
||||
Git Common-Flow 1.0.0-rc.3
|
||||
===========================
|
||||
|
||||
# Git Common-Flow 1.0.0-rc.3
|
||||
|
||||
<img src="/spec/1.0.0-rc.3.svg" alt="Git Common-Flow 1.0.0-rc.3 diagram" width="100%" />
|
||||
|
||||
Summary
|
||||
-------
|
||||
## Summary
|
||||
|
||||
Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
@@ -20,8 +19,7 @@ In short, Common-Flow is essentially GitHub Flow with the addition of versioned
|
||||
releases, optional release branches, and without the requirement to deploy to
|
||||
production all the time.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
## Terminology
|
||||
|
||||
- **Master Branch** - Must be named "master", must always have passing tests,
|
||||
and is not guaranteed to always work in production environments.
|
||||
@@ -41,166 +39,164 @@ Terminology
|
||||
- **Release Branches** - Used both for short-term preparations of a release, and
|
||||
also for long-term maintenance of older version.
|
||||
|
||||
Git Common-Flow Specification (Common-Flow)
|
||||
-------------------------------------------
|
||||
## Git Common-Flow Specification (Common-Flow)
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
|
||||
1. TL;DR
|
||||
1. Don't break the master branch.
|
||||
2. A release is a git tag.
|
||||
1. Don't break the master branch.
|
||||
2. A release is a git tag.
|
||||
2. The Master Branch
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch IS NOT guaranteed to always work in production
|
||||
environments. Despite test suites passing it may at times contain
|
||||
unfinished work. Only releases may be considered safe for production use.
|
||||
5. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
3. The master branch IS NOT guaranteed to always work in production
|
||||
environments. Despite test suites passing it may at times contain
|
||||
unfinished work. Only releases may be considered safe for production use.
|
||||
4. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
3. Change Branches
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches". All change
|
||||
branches MUST have descriptive names. It is RECOMMENDED that you commit
|
||||
often locally, and you SHOULD regularly push your work to the same named
|
||||
branch on the remote server.
|
||||
2. You MUST create separate change branches for each distinctly different
|
||||
change. You MUST NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
3. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
4. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
5. After rebasing a change branch on top of its source branch you MUST push
|
||||
the change branch to the remote server. This will require you to do a
|
||||
force push, and you SHOULD use the "--force-with-lease" git push option.
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches". All change
|
||||
branches MUST have descriptive names. It is RECOMMENDED that you commit
|
||||
often locally, and you SHOULD regularly push your work to the same named
|
||||
branch on the remote server.
|
||||
2. You MUST create separate change branches for each distinctly different
|
||||
change. You MUST NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
3. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
4. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
5. After rebasing a change branch on top of its source branch you MUST push
|
||||
the change branch to the remote server. This will require you to do a
|
||||
force push, and you SHOULD use the "--force-with-lease" git push option.
|
||||
4. Pull Requests
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent) so others can review and approve your changes.
|
||||
2. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
3. To get feedback, help, or generally just discuss a change branch with
|
||||
others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent) so others can review and approve your changes.
|
||||
2. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
3. To get feedback, help, or generally just discuss a change branch with
|
||||
others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
5. Versioning
|
||||
1. The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
located in the root of the project.
|
||||
2. If you are using a "VERSION" file in the root of the project, this MUST
|
||||
only contain the exact version string.
|
||||
3. The version string SHOULD follow the Semantic Versioning
|
||||
(<http://semver.org/>) format. Use of Semantic Versioning is OPTIONAL,
|
||||
but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.
|
||||
1. The project MUST have its version hard-coded somewhere in the
|
||||
code-base. It is RECOMMENDED that this is done in a file called "VERSION"
|
||||
located in the root of the project.
|
||||
2. If you are using a "VERSION" file in the root of the project, this MUST
|
||||
only contain the exact version string.
|
||||
3. The version string SHOULD follow the Semantic Versioning
|
||||
(<http://semver.org/>) format. Use of Semantic Versioning is OPTIONAL,
|
||||
but the version string MUST NOT have a "v" prefix. For example "v2.11.4"
|
||||
is bad, and "2.11.4" is good.
|
||||
6. Releases
|
||||
1. To create a new release, you MUST create a "version bump" commit which
|
||||
changes the hard-coded version string of the project. The version bump
|
||||
commit MUST have a git tag created on it and named as the exact version
|
||||
string.
|
||||
2. If you are not using a release branch, then the version bump commit MUST
|
||||
be created directly on the master branch.
|
||||
3. The version bump commit MUST have a commit message title of "Bump version
|
||||
to VERSION". For example, if the new version string is "2.11.4", the
|
||||
first line of the commit message MUST read: "Bump version to 2.11.4"
|
||||
4. The release tag on the version bump commit MUST be named exactly the same
|
||||
as the version string. The tag name can OPTIONALLY be prefixed with
|
||||
"v". For example the tag name can be either "2.11.4" or "v2.11.4". You
|
||||
MUST not use a mix of "v" prefixed and non-prefixed tags. Pick one form
|
||||
and stick to it.
|
||||
5. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
6. If you use annotated release tags, the first line of the annotation MUST
|
||||
read "Release VERSION". For example for version "2.11.4" the first line
|
||||
of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.
|
||||
1. To create a new release, you MUST create a "version bump" commit which
|
||||
changes the hard-coded version string of the project. The version bump
|
||||
commit MUST have a git tag created on it and named as the exact version
|
||||
string.
|
||||
2. If you are not using a release branch, then the version bump commit MUST
|
||||
be created directly on the master branch.
|
||||
3. The version bump commit MUST have a commit message title of "Bump version
|
||||
to VERSION". For example, if the new version string is "2.11.4", the
|
||||
first line of the commit message MUST read: "Bump version to 2.11.4"
|
||||
4. The release tag on the version bump commit MUST be named exactly the same
|
||||
as the version string. The tag name can OPTIONALLY be prefixed with
|
||||
"v". For example the tag name can be either "2.11.4" or "v2.11.4". You
|
||||
MUST not use a mix of "v" prefixed and non-prefixed tags. Pick one form
|
||||
and stick to it.
|
||||
5. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
6. If you use annotated release tags, the first line of the annotation MUST
|
||||
read "Release VERSION". For example for version "2.11.4" the first line
|
||||
of the tag annotation would read "Release 2.11.4". The second line must
|
||||
be blank, and the changelog MUST start on the third line.
|
||||
7. Release Branches
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Use of release branches is OPTIONAL.
|
||||
3. Changes in a release branch SHOULD typically come from work being
|
||||
done against the master branch. Meaning changes SHOULD only trickle
|
||||
downwards from the master branch. If a change needs to trickle back up
|
||||
into the master branch, that work should have happened against the master
|
||||
branch in the first place. One exception to this is version bump commits.
|
||||
4. There are two types of release branches; short-term, and long-term.
|
||||
5. Short-Term Release Branches
|
||||
1. Used for creating a specific versioned release.
|
||||
2. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
3. MUST have a name of "release-VERSION". For example for version
|
||||
"2.11.4" the release branch name MUST be "release-2.11.4".
|
||||
4. When using a short-term release branch, the version bump commit and
|
||||
release tag MUST be made directly on the release branch itself.
|
||||
5. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master
|
||||
branch, and SHOULD be pulled into the release branch by rebasing it
|
||||
on top of the master branch the same way a change branch pulls in
|
||||
updates from its source branch.
|
||||
6. After the version bump commit and release tag have been created, the
|
||||
release branch MUST be merged back into its source branch and then
|
||||
deleted. Typically the source branch will be the master branch.
|
||||
6. Long-Term Release Branches
|
||||
1. Used for work on versions which are not currently part of the master
|
||||
branch. Typically this is useful when you need to create a new
|
||||
maintenance release for a older version.
|
||||
2. The branch name MUST have a non-specific version number. For example
|
||||
a long-term release branch for creating new 2.9.x releases would be
|
||||
named "release-2.9".
|
||||
3. To create a new release from a long-term release branch, you MUST
|
||||
create a version bump commit and release tag directly on the release
|
||||
branch.
|
||||
4. A long-term release branch MUST be created from the relevant release
|
||||
tag. For example if the master branch is on version 2.11.4 and there
|
||||
is a security fix for all 2.9.x releases, the latest of which is
|
||||
"2.9.7". Create a new branch called "release-2.9" off of the "2.9.7"
|
||||
release tag. The security fix release will then end up being version
|
||||
"2.9.8".
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Use of release branches is OPTIONAL.
|
||||
3. Changes in a release branch SHOULD typically come from work being
|
||||
done against the master branch. Meaning changes SHOULD only trickle
|
||||
downwards from the master branch. If a change needs to trickle back up
|
||||
into the master branch, that work should have happened against the master
|
||||
branch in the first place. One exception to this is version bump commits.
|
||||
4. There are two types of release branches; short-term, and long-term.
|
||||
5. Short-Term Release Branches
|
||||
1. Used for creating a specific versioned release.
|
||||
2. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
3. MUST have a name of "release-VERSION". For example for version
|
||||
"2.11.4" the release branch name MUST be "release-2.11.4".
|
||||
4. When using a short-term release branch, the version bump commit and
|
||||
release tag MUST be made directly on the release branch itself.
|
||||
5. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master
|
||||
branch, and SHOULD be pulled into the release branch by rebasing it
|
||||
on top of the master branch the same way a change branch pulls in
|
||||
updates from its source branch.
|
||||
6. After the version bump commit and release tag have been created, the
|
||||
release branch MUST be merged back into its source branch and then
|
||||
deleted. Typically the source branch will be the master branch.
|
||||
6. Long-Term Release Branches
|
||||
1. Used for work on versions which are not currently part of the master
|
||||
branch. Typically this is useful when you need to create a new
|
||||
maintenance release for a older version.
|
||||
2. The branch name MUST have a non-specific version number. For example
|
||||
a long-term release branch for creating new 2.9.x releases would be
|
||||
named "release-2.9".
|
||||
3. To create a new release from a long-term release branch, you MUST
|
||||
create a version bump commit and release tag directly on the release
|
||||
branch.
|
||||
4. A long-term release branch MUST be created from the relevant release
|
||||
tag. For example if the master branch is on version 2.11.4 and there
|
||||
is a security fix for all 2.9.x releases, the latest of which is
|
||||
"2.9.7". Create a new branch called "release-2.9" off of the "2.9.7"
|
||||
release tag. The security fix release will then end up being version
|
||||
"2.9.8".
|
||||
8. Bug Fixes & Rollback
|
||||
1. You MUST NOT under any circumstances force push to the master branch.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
1. You MUST NOT under any circumstances force push to the master branch.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
9. Git Best Practices
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
documentation:
|
||||
<https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines>
|
||||
2. You SHOULD never blindly commit all changes with "git commit -a". It is
|
||||
RECOMMENDED you use "git add -i" to add individual changes to the staging
|
||||
area so you are fully aware of what you are committing.
|
||||
3. You SHOULD always use "--force-with-lease" when doing a force push. The
|
||||
regular "--force" option is dangerous and destructive. More
|
||||
information:
|
||||
<https://developer.atlassian.com/blog/2015/04/force-with-lease/>
|
||||
4. You SHOULD understand and be comfortable with
|
||||
rebasing: <https://git-scm.com/book/en/v2/Git-Branching-Rebasing>
|
||||
5. It is RECOMMENDED that you always do "git pull --rebase" instead of "git
|
||||
pull" to avoid unnecessary merge commits. You can make this the default
|
||||
behavior of "git pull" with "git config --global pull.rebase true".
|
||||
6. It is RECOMMENDED that all branches be merged using "git merge --no-ff".
|
||||
This makes sure the reference to the original branch is kept in the
|
||||
commits, allows one to revert a merge by reverting a single merge commit,
|
||||
and creates a merge commit to mark the integration of the branch with
|
||||
master.
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
documentation:
|
||||
<https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines>
|
||||
2. You SHOULD never blindly commit all changes with "git commit -a". It is
|
||||
RECOMMENDED you use "git add -i" to add individual changes to the staging
|
||||
area so you are fully aware of what you are committing.
|
||||
3. You SHOULD always use "--force-with-lease" when doing a force push. The
|
||||
regular "--force" option is dangerous and destructive. More
|
||||
information:
|
||||
<https://developer.atlassian.com/blog/2015/04/force-with-lease/>
|
||||
4. You SHOULD understand and be comfortable with
|
||||
rebasing: <https://git-scm.com/book/en/v2/Git-Branching-Rebasing>
|
||||
5. It is RECOMMENDED that you always do "git pull --rebase" instead of "git
|
||||
pull" to avoid unnecessary merge commits. You can make this the default
|
||||
behavior of "git pull" with "git config --global pull.rebase true".
|
||||
6. It is RECOMMENDED that all branches be merged using "git merge --no-ff".
|
||||
This makes sure the reference to the original branch is kept in the
|
||||
commits, allows one to revert a merge by reverting a single merge commit,
|
||||
and creates a merge commit to mark the integration of the branch with
|
||||
master.
|
||||
|
||||
About
|
||||
-----
|
||||
## About
|
||||
|
||||
The Git Common-Flow specification is authored
|
||||
by [Jim Myhrberg](http://jimeh.me).
|
||||
@@ -208,7 +204,6 @@ by [Jim Myhrberg](http://jimeh.me).
|
||||
If you'd like to leave feedback,
|
||||
please [open an issue on GitHub](https://github.com/jimeh/common-flow/issues).
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
[Creative Commons - CC BY 3.0](http://creativecommons.org/licenses/by/3.0/)
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
title: Git Common-Flow 1.0.0-rc.4
|
||||
version: 1.0.0-rc.4
|
||||
---
|
||||
Git Common-Flow 1.0.0-rc.4
|
||||
===========================
|
||||
|
||||
# Git Common-Flow 1.0.0-rc.4
|
||||
|
||||
<img src="/spec/1.0.0-rc.4.svg" alt="Git Common-Flow 1.0.0-rc.4 diagram" width="100%" />
|
||||
|
||||
Summary
|
||||
-------
|
||||
## Summary
|
||||
|
||||
Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
@@ -20,8 +19,7 @@ In short, Common-Flow is essentially GitHub Flow with the addition of versioned
|
||||
releases, optional release branches, and without the requirement to deploy to
|
||||
production all the time.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
## Terminology
|
||||
|
||||
- **Master Branch** - Must be named "master", must always have passing tests,
|
||||
and is not guaranteed to always work in production environments.
|
||||
@@ -40,183 +38,182 @@ Terminology
|
||||
- **Release Branches** - Used both for short-term preparations of a release, and
|
||||
also for long-term maintenance of older version.
|
||||
|
||||
Git Common-Flow Specification (Common-Flow)
|
||||
-------------------------------------------
|
||||
## Git Common-Flow Specification (Common-Flow)
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
|
||||
1. TL;DR
|
||||
1. Don't break the master branch.
|
||||
2. A release is a git tag.
|
||||
1. Don't break the master branch.
|
||||
2. A release is a git tag.
|
||||
2. The Master Branch
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch IS NOT guaranteed to always work in production
|
||||
environments. Despite test suites passing it may at times contain
|
||||
unfinished work. Only releases may be considered safe for production use.
|
||||
5. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
3. The master branch IS NOT guaranteed to always work in production
|
||||
environments. Despite test suites passing it may at times contain
|
||||
unfinished work. Only releases may be considered safe for production use.
|
||||
4. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
3. Change Branches
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches".
|
||||
2. All change branches MUST have descriptive names.
|
||||
3. It is RECOMMENDED that you commit often locally, and that you try and
|
||||
keep the commits reasonably structured to avoid a messy and confusing git
|
||||
history.
|
||||
4. You SHOULD regularly push your work to the same named branch on the
|
||||
remote server.
|
||||
5. You SHOULD create separate change branches for each distinctly different
|
||||
change. You SHOULD NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
6. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
7. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
8. After updating a change branch from its source branch you MUST push the
|
||||
change branch to the remote server. Due to the nature of rebasing, you
|
||||
will be required to do a force push, and you MUST use the
|
||||
"--force-with-lease" git push option when doing so instead of the regular
|
||||
"--force".
|
||||
9. If there is a truly valid technical reason to not use rebase when
|
||||
updating change branches, then you can update change branches via merge
|
||||
instead of rebase. The decision to use merge MUST only be taken after all
|
||||
possible options to use rebase have been tried and failed. People not
|
||||
understanding how to use rebase is NOT a valid reason to use merge. If
|
||||
you do decide to use merge instead of rebase, you MUST NOT use a mixture
|
||||
of both methods, pick one and stick to it.
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches".
|
||||
2. All change branches MUST have descriptive names.
|
||||
3. It is RECOMMENDED that you commit often locally, and that you try and
|
||||
keep the commits reasonably structured to avoid a messy and confusing git
|
||||
history.
|
||||
4. You SHOULD regularly push your work to the same named branch on the
|
||||
remote server.
|
||||
5. You SHOULD create separate change branches for each distinctly different
|
||||
change. You SHOULD NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
6. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
7. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
8. After updating a change branch from its source branch you MUST push the
|
||||
change branch to the remote server. Due to the nature of rebasing, you
|
||||
will be required to do a force push, and you MUST use the
|
||||
"--force-with-lease" git push option when doing so instead of the regular
|
||||
"--force".
|
||||
9. If there is a truly valid technical reason to not use rebase when
|
||||
updating change branches, then you can update change branches via merge
|
||||
instead of rebase. The decision to use merge MUST only be taken after all
|
||||
possible options to use rebase have been tried and failed. People not
|
||||
understanding how to use rebase is NOT a valid reason to use merge. If
|
||||
you do decide to use merge instead of rebase, you MUST NOT use a mixture
|
||||
of both methods, pick one and stick to it.
|
||||
4. Pull Requests
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent).
|
||||
2. The purpose of a pull request is to allow others to review your changes
|
||||
and give feedback. You can then fix any issues, complaints, and more that
|
||||
might arise, and then let people review again.
|
||||
3. Before creating a pull request, it is RECOMMENDED that you consider the
|
||||
state of your change branch's commit history. If it is messy and
|
||||
confusing, it might be a good idea to rebase your branch with "git rebase
|
||||
-i" to present a cleaner and easier to follow commit history for your
|
||||
reviewers.
|
||||
4. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
5. To get feedback, help, or generally just discuss a change branch with
|
||||
others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent).
|
||||
2. The purpose of a pull request is to allow others to review your changes
|
||||
and give feedback. You can then fix any issues, complaints, and more that
|
||||
might arise, and then let people review again.
|
||||
3. Before creating a pull request, it is RECOMMENDED that you consider the
|
||||
state of your change branch's commit history. If it is messy and
|
||||
confusing, it might be a good idea to rebase your branch with "git rebase
|
||||
-i" to present a cleaner and easier to follow commit history for your
|
||||
reviewers.
|
||||
4. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
5. To get feedback, help, or generally just discuss a change branch with
|
||||
others, the RECOMMENDED way to do so is by creating a pull request and
|
||||
discuss the changes with others there.
|
||||
5. Versioning
|
||||
1. A "version string" is a typically mostly numeric string that identifies a
|
||||
specific version of a project. The version string itself MUST NOT have a
|
||||
"v" prefix, but the version string can be displayed with a "v" prefix to
|
||||
indicate it is a version that is being referred to.
|
||||
2. The source of truth for a project's version MUST be a git tag with a name
|
||||
based on the version string. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
3. It is OPTIONAL, but RECOMMENDED to also keep the version string
|
||||
hard-coded somewhere in the project code-base.
|
||||
4. If you hard-code the version string into the code-base, it is RECOMMENDED
|
||||
that you do so in a file called "VERSION" located in the root of the
|
||||
project. But be mindful of the conventions of your programming language
|
||||
and community when choosing if, where and how to hard-code the version
|
||||
string.
|
||||
5. If you are using a "VERSION" file in the root of the project, this file
|
||||
MUST only contain the exact version string, meaning it MUST NOT have a
|
||||
"v" prefix. For example "v2.11.4" is bad, and "2.11.4" is good.
|
||||
6. It is OPTIONAL, but RECOMMENDED that that the version string follows
|
||||
Semantic Versioning (<http://semver.org/>).
|
||||
1. A "version string" is a typically mostly numeric string that identifies a
|
||||
specific version of a project. The version string itself MUST NOT have a
|
||||
"v" prefix, but the version string can be displayed with a "v" prefix to
|
||||
indicate it is a version that is being referred to.
|
||||
2. The source of truth for a project's version MUST be a git tag with a name
|
||||
based on the version string. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
3. It is OPTIONAL, but RECOMMENDED to also keep the version string
|
||||
hard-coded somewhere in the project code-base.
|
||||
4. If you hard-code the version string into the code-base, it is RECOMMENDED
|
||||
that you do so in a file called "VERSION" located in the root of the
|
||||
project. But be mindful of the conventions of your programming language
|
||||
and community when choosing if, where and how to hard-code the version
|
||||
string.
|
||||
5. If you are using a "VERSION" file in the root of the project, this file
|
||||
MUST only contain the exact version string, meaning it MUST NOT have a
|
||||
"v" prefix. For example "v2.11.4" is bad, and "2.11.4" is good.
|
||||
6. It is OPTIONAL, but RECOMMENDED that that the version string follows
|
||||
Semantic Versioning (<http://semver.org/>).
|
||||
6. Releases
|
||||
1. To create a new release, you MUST create a git tag named as the exact
|
||||
version string of the release. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
2. The release tag name can OPTIONALLY be prefixed with "v". For example the
|
||||
tag name can be either "2.11.4" or "v2.11.4". It is however RECOMMENDED
|
||||
that you do not use a "v" prefix. You MUST NOT use a mixture of "v"
|
||||
prefixed and non-prefixed tags. Pick one form and stick to it.
|
||||
3. If the version string is hard-coded into the code-base, you MUST create a
|
||||
"version bump" commit which changes the hard-coded version string of the
|
||||
project.
|
||||
4. When using version bump commits, the release tag MUST be placed on the
|
||||
version bump commit.
|
||||
5. If you are not using a release branch, then the release tag, and if
|
||||
relevant the version bump commit, MUST be created directly on the master
|
||||
branch.
|
||||
6. The version bump commit SHOULD have a commit message title of "Bump
|
||||
version to VERSION". For example, if the new version string is "2.11.4",
|
||||
the first line of the commit message SHOULD read: "Bump version to
|
||||
2.11.4"
|
||||
7. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
8. If you use annotated release tags, the first line of the annotation
|
||||
SHOULD read "Release VERSION". For example for version "2.11.4" the first
|
||||
line of the tag annotation SHOULD read "Release 2.11.4". The second line
|
||||
MUST be blank, and the changelog MUST start on the third line.
|
||||
1. To create a new release, you MUST create a git tag named as the exact
|
||||
version string of the release. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
2. The release tag name can OPTIONALLY be prefixed with "v". For example the
|
||||
tag name can be either "2.11.4" or "v2.11.4". It is however RECOMMENDED
|
||||
that you do not use a "v" prefix. You MUST NOT use a mixture of "v"
|
||||
prefixed and non-prefixed tags. Pick one form and stick to it.
|
||||
3. If the version string is hard-coded into the code-base, you MUST create a
|
||||
"version bump" commit which changes the hard-coded version string of the
|
||||
project.
|
||||
4. When using version bump commits, the release tag MUST be placed on the
|
||||
version bump commit.
|
||||
5. If you are not using a release branch, then the release tag, and if
|
||||
relevant the version bump commit, MUST be created directly on the master
|
||||
branch.
|
||||
6. The version bump commit SHOULD have a commit message title of "Bump
|
||||
version to VERSION". For example, if the new version string is "2.11.4",
|
||||
the first line of the commit message SHOULD read: "Bump version to
|
||||
2.11.4"
|
||||
7. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
8. If you use annotated release tags, the first line of the annotation
|
||||
SHOULD read "Release VERSION". For example for version "2.11.4" the first
|
||||
line of the tag annotation SHOULD read "Release 2.11.4". The second line
|
||||
MUST be blank, and the changelog MUST start on the third line.
|
||||
7. Short-Term Release Branches
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Any release branch which has a name ending with a specific version
|
||||
string, MUST be referred to as a "short-term release branch".
|
||||
3. Use of short-term release branches are OPTIONAL, and intended to be used
|
||||
to create a specific versioned release.
|
||||
4. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
5. Short-term release branches MUST have a name of "release-VERSION". For
|
||||
example for version "2.11.4" the release branch name MUST be
|
||||
"release-2.11.4".
|
||||
6. When using a short-term release branch to create a release, the release
|
||||
tag and if used, version bump commit, MUST be placed directly on the
|
||||
short-term release branch itself.
|
||||
7. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master branch,
|
||||
and SHOULD be pulled into the release branch by rebasing it on top of the
|
||||
master branch the same way a change branch pulls in updates from its
|
||||
source branch.
|
||||
8. After a release tag has been created, the release branch MUST be merged
|
||||
back into its source branch and then deleted. Typically the source branch
|
||||
will be the master branch.
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Any release branch which has a name ending with a specific version
|
||||
string, MUST be referred to as a "short-term release branch".
|
||||
3. Use of short-term release branches are OPTIONAL, and intended to be used
|
||||
to create a specific versioned release.
|
||||
4. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
5. Short-term release branches MUST have a name of "release-VERSION". For
|
||||
example for version "2.11.4" the release branch name MUST be
|
||||
"release-2.11.4".
|
||||
6. When using a short-term release branch to create a release, the release
|
||||
tag and if used, version bump commit, MUST be placed directly on the
|
||||
short-term release branch itself.
|
||||
7. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master branch,
|
||||
and SHOULD be pulled into the release branch by rebasing it on top of the
|
||||
master branch the same way a change branch pulls in updates from its
|
||||
source branch.
|
||||
8. After a release tag has been created, the release branch MUST be merged
|
||||
back into its source branch and then deleted. Typically the source branch
|
||||
will be the master branch.
|
||||
8. Long-term Release Branches
|
||||
1. Any release branch which has a name ending with a non-specific version
|
||||
string, MUST be referred to as a "long-term release branch". For example
|
||||
"release-2.11" is a long-term release branch, while "release-2.11.4" is a
|
||||
short-term release branch.
|
||||
2. Use of long-term release branches are OPTIONAL, and intended for work on
|
||||
versions which are not currently part of the master branch. Typically
|
||||
this is useful when you need to create a new maintenance release for a
|
||||
older version.
|
||||
3. A long-term release branch MUST have a name with a non-specific version
|
||||
number. For example a long-term release branch for creating new 2.9.x
|
||||
releases MUST be named "release-2.9".
|
||||
4. Long-term release branches for maintenance releases of older versions
|
||||
MUST be created from the relevant release tag. For example if the master
|
||||
branch is on version 2.11.4 and there is a security fix for all 2.9.x
|
||||
releases, the latest of which is "2.9.7". Create a new branch called
|
||||
"release-2.9" off of the "2.9.7" release tag. The security fix release
|
||||
will then end up being version "2.9.8".
|
||||
5. To create a new release from a long-term release branch, you MUST follow
|
||||
the same process as a release from the master branch, except the
|
||||
long-term release branch takes the place of the master branch.
|
||||
7. A long-term release branch should be treated with the same respect as the
|
||||
master branch. It is effectively the master branch for the release series
|
||||
in question. Meaning it MUST always be in a non-broken state, MUST NOT be
|
||||
force pushed to, etc.
|
||||
1. Any release branch which has a name ending with a non-specific version
|
||||
string, MUST be referred to as a "long-term release branch". For example
|
||||
"release-2.11" is a long-term release branch, while "release-2.11.4" is a
|
||||
short-term release branch.
|
||||
2. Use of long-term release branches are OPTIONAL, and intended for work on
|
||||
versions which are not currently part of the master branch. Typically
|
||||
this is useful when you need to create a new maintenance release for a
|
||||
older version.
|
||||
3. A long-term release branch MUST have a name with a non-specific version
|
||||
number. For example a long-term release branch for creating new 2.9.x
|
||||
releases MUST be named "release-2.9".
|
||||
4. Long-term release branches for maintenance releases of older versions
|
||||
MUST be created from the relevant release tag. For example if the master
|
||||
branch is on version 2.11.4 and there is a security fix for all 2.9.x
|
||||
releases, the latest of which is "2.9.7". Create a new branch called
|
||||
"release-2.9" off of the "2.9.7" release tag. The security fix release
|
||||
will then end up being version "2.9.8".
|
||||
5. To create a new release from a long-term release branch, you MUST follow
|
||||
the same process as a release from the master branch, except the
|
||||
long-term release branch takes the place of the master branch.
|
||||
6. A long-term release branch should be treated with the same respect as the
|
||||
master branch. It is effectively the master branch for the release series
|
||||
in question. Meaning it MUST always be in a non-broken state, MUST NOT be
|
||||
force pushed to, etc.
|
||||
9. Bug Fixes & Rollback
|
||||
1. You MUST NOT under any circumstances force push to the master branch or
|
||||
to long-term release branches.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
1. You MUST NOT under any circumstances force push to the master branch or
|
||||
to long-term release branches.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
10. Git Best Practices
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
@@ -241,8 +238,7 @@ interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
and creates a merge commit to mark the integration of the branch with
|
||||
master.
|
||||
|
||||
FAQ
|
||||
---
|
||||
## FAQ
|
||||
|
||||
### Why use Common-Flow instead of Git Flow, and how does it differ?
|
||||
|
||||
@@ -325,8 +321,7 @@ complicated task and you're short on time, a short-term release branch gives you
|
||||
a instant fix to the situation at hand, and let's you resolve the issues with
|
||||
the master branch when you have more time on your hands.
|
||||
|
||||
About
|
||||
-----
|
||||
## About
|
||||
|
||||
The Git Common-Flow specification is authored
|
||||
by [Jim Myhrberg](http://jimeh.me).
|
||||
@@ -334,7 +329,6 @@ by [Jim Myhrberg](http://jimeh.me).
|
||||
If you'd like to leave feedback,
|
||||
please [open an issue on GitHub](https://github.com/jimeh/common-flow/issues).
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
[Creative Commons - CC BY 3.0](http://creativecommons.org/licenses/by/3.0/)
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
title: Git Common-Flow 1.0.0-rc.5
|
||||
version: 1.0.0-rc.5
|
||||
---
|
||||
Git Common-Flow 1.0.0-rc.5
|
||||
===========================
|
||||
|
||||
# Git Common-Flow 1.0.0-rc.5
|
||||
|
||||
<img src="/spec/1.0.0-rc.5.svg" alt="Git Common-Flow 1.0.0-rc.5 diagram" width="100%" />
|
||||
|
||||
Introduction
|
||||
------------
|
||||
## Introduction
|
||||
|
||||
Common-Flow is an attempt to gather a sensible selection of the most common
|
||||
usage patterns of git into a single and concise specification. It is based on
|
||||
@@ -20,8 +19,7 @@ In short, Common-Flow is essentially GitHub Flow with the addition of versioned
|
||||
releases, optional release branches, and without the requirement to deploy to
|
||||
production all the time.
|
||||
|
||||
Summary
|
||||
-------
|
||||
## Summary
|
||||
|
||||
- The "master" branch is the mainline branch with latest changes, and must not
|
||||
be broken.
|
||||
@@ -34,8 +32,7 @@ Summary
|
||||
- Release branches can be used to avoid change freezes on master. They are not
|
||||
required, instead they are available if you need them.
|
||||
|
||||
Terminology
|
||||
-----------
|
||||
## Terminology
|
||||
|
||||
- **Master Branch** - Must be named "master", must always have passing tests,
|
||||
and is not guaranteed to always work in production environments.
|
||||
@@ -54,184 +51,183 @@ Terminology
|
||||
- **Release Branches** - Used both for short-term preparations of a release, and
|
||||
also for long-term maintenance of older version.
|
||||
|
||||
Git Common-Flow Specification (Common-Flow)
|
||||
-------------------------------------------
|
||||
## Git Common-Flow Specification (Common-Flow)
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD",
|
||||
"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be
|
||||
interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
|
||||
1. TL;DR
|
||||
1. Do not break the master branch.
|
||||
2. A release is a git tag.
|
||||
1. Do not break the master branch.
|
||||
2. A release is a git tag.
|
||||
2. The Master Branch
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
4. The master branch IS NOT guaranteed to always work in production
|
||||
environments. Despite test suites passing it may at times contain
|
||||
unfinished work. Only releases may be considered safe for production use.
|
||||
5. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
1. A branch named "master" MUST exist and it MUST be referred to as the
|
||||
"master branch".
|
||||
2. The master branch MUST always be in a non-broken state with its test
|
||||
suite passing.
|
||||
3. The master branch IS NOT guaranteed to always work in production
|
||||
environments. Despite test suites passing it may at times contain
|
||||
unfinished work. Only releases may be considered safe for production use.
|
||||
4. The master branch SHOULD always be in a "as near as possibly ready for
|
||||
release/production" state to reduce any friction with creating a new
|
||||
release.
|
||||
3. Change Branches
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches".
|
||||
2. All change branches MUST have descriptive names.
|
||||
3. It is RECOMMENDED that you commit often locally, and that you try and
|
||||
keep the commits reasonably structured to avoid a messy and confusing git
|
||||
history.
|
||||
4. You SHOULD regularly push your work to the same named branch on the
|
||||
remote server.
|
||||
5. You SHOULD create separate change branches for each distinctly different
|
||||
change. You SHOULD NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
6. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
7. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
8. After updating a change branch from its source branch you MUST push the
|
||||
change branch to the remote server. Due to the nature of rebasing, you
|
||||
will be required to do a force push, and you MUST use the
|
||||
"--force-with-lease" git push option when doing so instead of the regular
|
||||
"--force".
|
||||
9. If there is a truly valid technical reason to not use rebase when
|
||||
updating change branches, then you can update change branches via merge
|
||||
instead of rebase. The decision to use merge MUST only be taken after all
|
||||
possible options to use rebase have been tried and failed. People not
|
||||
understanding how to use rebase is NOT a valid reason to use merge. If
|
||||
you do decide to use merge instead of rebase, you MUST NOT use a mixture
|
||||
of both methods, pick one and stick to it.
|
||||
1. Each change (feature, bugfix, etc.) MUST be performed on separate
|
||||
branches that SHOULD be referred to as "change branches".
|
||||
2. All change branches MUST have descriptive names.
|
||||
3. It is RECOMMENDED that you commit often locally, and that you try and
|
||||
keep the commits reasonably structured to avoid a messy and confusing git
|
||||
history.
|
||||
4. You SHOULD regularly push your work to the same named branch on the
|
||||
remote server.
|
||||
5. You SHOULD create separate change branches for each distinctly different
|
||||
change. You SHOULD NOT include multiple unrelated changes into a single
|
||||
change branch.
|
||||
6. When a change branch is created, the branch that it is created from
|
||||
SHOULD be referred to as the "source branch". Each change branch also
|
||||
needs a designated "merge target" branch, typically this will be the same
|
||||
as the source branch.
|
||||
7. Change branches MUST be regularly updated with any changes from their
|
||||
source branch. This MUST be done by rebasing the change branch on top of
|
||||
the source branch.
|
||||
8. After updating a change branch from its source branch you MUST push the
|
||||
change branch to the remote server. Due to the nature of rebasing, you
|
||||
will be required to do a force push, and you MUST use the
|
||||
"--force-with-lease" git push option when doing so instead of the regular
|
||||
"--force".
|
||||
9. If there is a truly valid technical reason to not use rebase when
|
||||
updating change branches, then you can update change branches via merge
|
||||
instead of rebase. The decision to use merge MUST only be taken after all
|
||||
possible options to use rebase have been tried and failed. People not
|
||||
understanding how to use rebase is NOT a valid reason to use merge. If
|
||||
you do decide to use merge instead of rebase, you MUST NOT use a mixture
|
||||
of both methods, pick one and stick to it.
|
||||
4. Pull Requests
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent).
|
||||
2. The purpose of a pull request is to allow others to review your changes
|
||||
and give feedback. You can then fix any issues, complaints, and more that
|
||||
might arise, and then let people review again.
|
||||
3. Before creating a pull request, it is RECOMMENDED that you consider the
|
||||
state of your change branch's commit history. If it is messy and
|
||||
confusing, it might be a good idea to rebase your branch with "git rebase
|
||||
-i" to present a cleaner and easier to follow commit history for your
|
||||
reviewers.
|
||||
4. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
5. To get feedback, help, or generally just discuss a change branch with
|
||||
others, it is RECOMMENDED you create a pull request and discuss the
|
||||
changes with others there. This leaves a clear and visible history of
|
||||
how, when, and why the code looks and behaves the way it does.
|
||||
1. To merge a change branch into its merge target, you MUST open a "pull
|
||||
request" (or equivalent).
|
||||
2. The purpose of a pull request is to allow others to review your changes
|
||||
and give feedback. You can then fix any issues, complaints, and more that
|
||||
might arise, and then let people review again.
|
||||
3. Before creating a pull request, it is RECOMMENDED that you consider the
|
||||
state of your change branch's commit history. If it is messy and
|
||||
confusing, it might be a good idea to rebase your branch with "git rebase
|
||||
-i" to present a cleaner and easier to follow commit history for your
|
||||
reviewers.
|
||||
4. A pull request MUST only be merged when the change branch is up-to-date
|
||||
with its source branch, the test suite is passing, and you and others are
|
||||
happy with the change. This is especially important if the merge target
|
||||
is the master branch.
|
||||
5. To get feedback, help, or generally just discuss a change branch with
|
||||
others, it is RECOMMENDED you create a pull request and discuss the
|
||||
changes with others there. This leaves a clear and visible history of
|
||||
how, when, and why the code looks and behaves the way it does.
|
||||
5. Versioning
|
||||
1. A "version string" is a typically mostly numeric string that identifies a
|
||||
specific version of a project. The version string itself MUST NOT have a
|
||||
"v" prefix, but the version string can be displayed with a "v" prefix to
|
||||
indicate it is a version that is being referred to.
|
||||
2. The source of truth for a project's version MUST be a git tag with a name
|
||||
based on the version string. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
3. It is OPTIONAL, but RECOMMENDED to also keep the version string
|
||||
hard-coded somewhere in the project code-base.
|
||||
4. If you hard-code the version string into the code-base, it is RECOMMENDED
|
||||
that you do so in a file called "VERSION" located in the root of the
|
||||
project. But be mindful of the conventions of your programming language
|
||||
and community when choosing if, where and how to hard-code the version
|
||||
string.
|
||||
5. If you are using a "VERSION" file in the root of the project, this file
|
||||
MUST only contain the exact version string, meaning it MUST NOT have a
|
||||
"v" prefix. For example "v2.11.4" is bad, and "2.11.4" is good.
|
||||
6. It is OPTIONAL, but RECOMMENDED that that the version string follows
|
||||
Semantic Versioning (<http://semver.org/>).
|
||||
1. A "version string" is a typically mostly numeric string that identifies a
|
||||
specific version of a project. The version string itself MUST NOT have a
|
||||
"v" prefix, but the version string can be displayed with a "v" prefix to
|
||||
indicate it is a version that is being referred to.
|
||||
2. The source of truth for a project's version MUST be a git tag with a name
|
||||
based on the version string. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
3. It is OPTIONAL, but RECOMMENDED to also keep the version string
|
||||
hard-coded somewhere in the project code-base.
|
||||
4. If you hard-code the version string into the code-base, it is RECOMMENDED
|
||||
that you do so in a file called "VERSION" located in the root of the
|
||||
project. But be mindful of the conventions of your programming language
|
||||
and community when choosing if, where and how to hard-code the version
|
||||
string.
|
||||
5. If you are using a "VERSION" file in the root of the project, this file
|
||||
MUST only contain the exact version string, meaning it MUST NOT have a
|
||||
"v" prefix. For example "v2.11.4" is bad, and "2.11.4" is good.
|
||||
6. It is OPTIONAL, but RECOMMENDED that that the version string follows
|
||||
Semantic Versioning (<http://semver.org/>).
|
||||
6. Releases
|
||||
1. To create a new release, you MUST create a git tag named as the exact
|
||||
version string of the release. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
2. The release tag name can OPTIONALLY be prefixed with "v". For example the
|
||||
tag name can be either "2.11.4" or "v2.11.4". It is however RECOMMENDED
|
||||
that you do not use a "v" prefix. You MUST NOT use a mixture of "v"
|
||||
prefixed and non-prefixed tags. Pick one form and stick to it.
|
||||
3. If the version string is hard-coded into the code-base, you MUST create a
|
||||
"version bump" commit which changes the hard-coded version string of the
|
||||
project.
|
||||
4. When using version bump commits, the release tag MUST be placed on the
|
||||
version bump commit.
|
||||
5. If you are not using a release branch, then the release tag, and if
|
||||
relevant the version bump commit, MUST be created directly on the master
|
||||
branch.
|
||||
6. The version bump commit SHOULD have a commit message title of "Bump
|
||||
version to VERSION". For example, if the new version string is "2.11.4",
|
||||
the first line of the commit message SHOULD read: "Bump version to
|
||||
2.11.4"
|
||||
7. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
8. If you use annotated release tags, the first line of the annotation
|
||||
SHOULD read "Release VERSION". For example for version "2.11.4" the first
|
||||
line of the tag annotation SHOULD read "Release 2.11.4". The second line
|
||||
MUST be blank, and the changelog MUST start on the third line.
|
||||
1. To create a new release, you MUST create a git tag named as the exact
|
||||
version string of the release. This kind of tag MUST be referred to as a
|
||||
"release tag".
|
||||
2. The release tag name can OPTIONALLY be prefixed with "v". For example the
|
||||
tag name can be either "2.11.4" or "v2.11.4". It is however RECOMMENDED
|
||||
that you do not use a "v" prefix. You MUST NOT use a mixture of "v"
|
||||
prefixed and non-prefixed tags. Pick one form and stick to it.
|
||||
3. If the version string is hard-coded into the code-base, you MUST create a
|
||||
"version bump" commit which changes the hard-coded version string of the
|
||||
project.
|
||||
4. When using version bump commits, the release tag MUST be placed on the
|
||||
version bump commit.
|
||||
5. If you are not using a release branch, then the release tag, and if
|
||||
relevant the version bump commit, MUST be created directly on the master
|
||||
branch.
|
||||
6. The version bump commit SHOULD have a commit message title of "Bump
|
||||
version to VERSION". For example, if the new version string is "2.11.4",
|
||||
the first line of the commit message SHOULD read: "Bump version to
|
||||
2.11.4"
|
||||
7. It is RECOMMENDED that release tags are lightweight tags, but you can
|
||||
OPTIONALLY use annotated tags if you want to include changelog
|
||||
information in the release tag itself.
|
||||
8. If you use annotated release tags, the first line of the annotation
|
||||
SHOULD read "Release VERSION". For example for version "2.11.4" the first
|
||||
line of the tag annotation SHOULD read "Release 2.11.4". The second line
|
||||
MUST be blank, and the changelog MUST start on the third line.
|
||||
7. Short-Term Release Branches
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Any release branch which has a name ending with a specific version
|
||||
string, MUST be referred to as a "short-term release branch".
|
||||
3. Use of short-term release branches are OPTIONAL, and intended to be used
|
||||
to create a specific versioned release.
|
||||
4. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
5. Short-term release branches MUST have a name of "release-VERSION". For
|
||||
example for version "2.11.4" the release branch name MUST be
|
||||
"release-2.11.4".
|
||||
6. When using a short-term release branch to create a release, the release
|
||||
tag and if used, version bump commit, MUST be placed directly on the
|
||||
short-term release branch itself.
|
||||
7. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master branch,
|
||||
and SHOULD be pulled into the release branch by rebasing it on top of the
|
||||
master branch the same way a change branch pulls in updates from its
|
||||
source branch.
|
||||
8. After a release tag has been created, the release branch MUST be merged
|
||||
back into its source branch and then deleted. Typically the source branch
|
||||
will be the master branch.
|
||||
1. Any branch that has a name starting with "release-" SHOULD be referred to
|
||||
as a "release branch".
|
||||
2. Any release branch which has a name ending with a specific version
|
||||
string, MUST be referred to as a "short-term release branch".
|
||||
3. Use of short-term release branches are OPTIONAL, and intended to be used
|
||||
to create a specific versioned release.
|
||||
4. A short-term release branch is RECOMMENDED if there is a lengthy
|
||||
pre-release verification process to avoid a code freeze on the master
|
||||
branch.
|
||||
5. Short-term release branches MUST have a name of "release-VERSION". For
|
||||
example for version "2.11.4" the release branch name MUST be
|
||||
"release-2.11.4".
|
||||
6. When using a short-term release branch to create a release, the release
|
||||
tag and if used, version bump commit, MUST be placed directly on the
|
||||
short-term release branch itself.
|
||||
7. Only very minor changes should be performed on a short-term release
|
||||
branch directly. Any larger changes SHOULD be done in the master branch,
|
||||
and SHOULD be pulled into the release branch by rebasing it on top of the
|
||||
master branch the same way a change branch pulls in updates from its
|
||||
source branch.
|
||||
8. After a release tag has been created, the release branch MUST be merged
|
||||
back into its source branch and then deleted. Typically the source branch
|
||||
will be the master branch.
|
||||
8. Long-term Release Branches
|
||||
1. Any release branch which has a name ending with a non-specific version
|
||||
string, MUST be referred to as a "long-term release branch". For example
|
||||
"release-2.11" is a long-term release branch, while "release-2.11.4" is a
|
||||
short-term release branch.
|
||||
2. Use of long-term release branches are OPTIONAL, and intended for work on
|
||||
versions which are not currently part of the master branch. Typically
|
||||
this is useful when you need to create a new maintenance release for a
|
||||
older version.
|
||||
3. A long-term release branch MUST have a name with a non-specific version
|
||||
number. For example a long-term release branch for creating new 2.9.x
|
||||
releases MUST be named "release-2.9".
|
||||
4. Long-term release branches for maintenance releases of older versions
|
||||
MUST be created from the relevant release tag. For example if the master
|
||||
branch is on version 2.11.4 and there is a security fix for all 2.9.x
|
||||
releases, the latest of which is "2.9.7". Create a new branch called
|
||||
"release-2.9" from the "2.9.7" release tag. The security fix release will
|
||||
then end up being version "2.9.8".
|
||||
5. To create a new release from a long-term release branch, you MUST follow
|
||||
the same process as a release from the master branch, except the
|
||||
long-term release branch takes the place of the master branch.
|
||||
7. A long-term release branch should be treated with the same respect as the
|
||||
master branch. It is effectively the master branch for the release series
|
||||
in question. Meaning it MUST always be in a non-broken state, MUST NOT be
|
||||
force pushed to, etc.
|
||||
1. Any release branch which has a name ending with a non-specific version
|
||||
string, MUST be referred to as a "long-term release branch". For example
|
||||
"release-2.11" is a long-term release branch, while "release-2.11.4" is a
|
||||
short-term release branch.
|
||||
2. Use of long-term release branches are OPTIONAL, and intended for work on
|
||||
versions which are not currently part of the master branch. Typically
|
||||
this is useful when you need to create a new maintenance release for a
|
||||
older version.
|
||||
3. A long-term release branch MUST have a name with a non-specific version
|
||||
number. For example a long-term release branch for creating new 2.9.x
|
||||
releases MUST be named "release-2.9".
|
||||
4. Long-term release branches for maintenance releases of older versions
|
||||
MUST be created from the relevant release tag. For example if the master
|
||||
branch is on version 2.11.4 and there is a security fix for all 2.9.x
|
||||
releases, the latest of which is "2.9.7". Create a new branch called
|
||||
"release-2.9" from the "2.9.7" release tag. The security fix release will
|
||||
then end up being version "2.9.8".
|
||||
5. To create a new release from a long-term release branch, you MUST follow
|
||||
the same process as a release from the master branch, except the
|
||||
long-term release branch takes the place of the master branch.
|
||||
6. A long-term release branch should be treated with the same respect as the
|
||||
master branch. It is effectively the master branch for the release series
|
||||
in question. Meaning it MUST always be in a non-broken state, MUST NOT be
|
||||
force pushed to, etc.
|
||||
9. Bug Fixes & Rollback
|
||||
1. You MUST NOT under any circumstances force push to the master branch or
|
||||
to long-term release branches.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
1. You MUST NOT under any circumstances force push to the master branch or
|
||||
to long-term release branches.
|
||||
2. If a change branch which has been merged into the master branch is found
|
||||
to have a bug in it, the bug fix work MUST be done as a new separate
|
||||
change branch and MUST follow the same workflow as any other change
|
||||
branch.
|
||||
3. If a change branch is wrongfully merged into master, or for any other
|
||||
reason the merge must be undone, you MUST undo the merge by reverting the
|
||||
merge commit itself. Effectively creating a new commit that reverses all
|
||||
the relevant changes.
|
||||
10. Git Best Practices
|
||||
1. All commit messages SHOULD follow the Commit Guidelines and format from
|
||||
the official git
|
||||
@@ -256,8 +252,7 @@ interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119).
|
||||
and creates a merge commit to mark the integration of the branch with
|
||||
master.
|
||||
|
||||
FAQ
|
||||
---
|
||||
## FAQ
|
||||
|
||||
### Why use Common-Flow instead of Git Flow, and how does it differ?
|
||||
|
||||
@@ -346,8 +341,7 @@ complicated task and you're short on time, a short-term release branch gives you
|
||||
a instant fix to the situation at hand, and let's you resolve the issues with
|
||||
the master branch when you have more time on your hands.
|
||||
|
||||
About
|
||||
-----
|
||||
## About
|
||||
|
||||
The Git Common-Flow specification is authored
|
||||
by [Jim Myhrberg](https://jimeh.me/).
|
||||
@@ -355,7 +349,6 @@ by [Jim Myhrberg](https://jimeh.me/).
|
||||
If you'd like to leave feedback,
|
||||
please [open an issue on GitHub](https://github.com/jimeh/common-flow/issues).
|
||||
|
||||
License
|
||||
-------
|
||||
## License
|
||||
|
||||
[Creative Commons - CC BY 4.0](https://creativecommons.org/licenses/by/4.0/)
|
||||
|
||||
76
src/layouts/BaseLayout.astro
Normal file
76
src/layouts/BaseLayout.astro
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
import "@fontsource-variable/bricolage-grotesque";
|
||||
import "@fontsource-variable/dm-sans";
|
||||
import "@fontsource-variable/jetbrains-mono";
|
||||
import "../styles/global.css";
|
||||
import { config } from "../config";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
const { title, description = config.description } = Astro.props;
|
||||
const fullTitle = title === config.title ? title : `${title} | ${config.title}`;
|
||||
const canonicalUrl = Astro.url.href;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="canonical" href={canonicalUrl} />
|
||||
|
||||
<title>{fullTitle}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta name="author" content={config.author} />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content={fullTitle} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={canonicalUrl} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content={fullTitle} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" href="/favicon.ico" sizes="32x32" />
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
||||
|
||||
<!-- Prevent flash of wrong theme -->
|
||||
<script is:inline>
|
||||
(function () {
|
||||
const mode = localStorage.getItem("theme");
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
if (mode === "dark" || (mode !== "light" && prefersDark)) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="min-h-screen">
|
||||
<slot />
|
||||
|
||||
<!-- Re-init theme on Astro page transitions -->
|
||||
<script>
|
||||
document.addEventListener("astro:after-swap", () => {
|
||||
const mode = localStorage.getItem("theme");
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
if (mode === "dark" || (mode !== "light" && prefersDark)) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,50 +0,0 @@
|
||||
---
|
||||
import "../styles/global.css";
|
||||
import { config } from "../config";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
const { title, description = config.description } = Astro.props;
|
||||
const fullTitle = title === config.title ? title : `${title} | ${config.title}`;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="canonical" href={Astro.url} />
|
||||
|
||||
<title>{fullTitle}</title>
|
||||
<meta name="description" content={description} />
|
||||
<meta name="author" content={config.author} />
|
||||
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!-- Prevent flash of wrong theme -->
|
||||
<script is:inline>
|
||||
(function () {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="min-h-screen flex flex-col items-center justify-center p-8">
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,87 +0,0 @@
|
||||
---
|
||||
import "../styles/global.css";
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
description?: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
const { title, description, version } = Astro.props;
|
||||
|
||||
const defaultDescription =
|
||||
"An attempt to gather a sensible selection of the most common usage " +
|
||||
"patterns of git into a single and concise specification.";
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content={description || defaultDescription} />
|
||||
<meta name="author" content="Jim Myhrberg" />
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content={title} />
|
||||
<meta
|
||||
property="og:description"
|
||||
content={description || defaultDescription}
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={`https://commonflow.org/${version}`} />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary" />
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content={description || defaultDescription}
|
||||
/>
|
||||
|
||||
<title>{title}</title>
|
||||
|
||||
<!-- Fonts - distinctive choices -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,500;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
|
||||
<!-- Theme initialization - prevent flash -->
|
||||
<script is:inline>
|
||||
(function () {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="min-h-screen">
|
||||
<slot />
|
||||
|
||||
<!-- Re-init theme on Astro page transitions -->
|
||||
<script>
|
||||
document.addEventListener("astro:after-swap", () => {
|
||||
const theme = localStorage.getItem("theme");
|
||||
if (
|
||||
theme === "dark" ||
|
||||
(!theme &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches)
|
||||
) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
56
src/layouts/SpecLayout.astro
Normal file
56
src/layouts/SpecLayout.astro
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
|
||||
import BaseLayout from "./BaseLayout.astro";
|
||||
import Header from "../components/Header.astro";
|
||||
import Hero from "../components/Hero.astro";
|
||||
import AboutSection from "../components/AboutSection.astro";
|
||||
import SpecSection from "../components/SpecSection.astro";
|
||||
import FAQSection from "../components/FAQSection.astro";
|
||||
import Footer from "../components/Footer.astro";
|
||||
import { parseSpecContent } from "../utils/parseSpecContent";
|
||||
|
||||
interface Props {
|
||||
spec: CollectionEntry<"spec">;
|
||||
}
|
||||
|
||||
const { spec } = Astro.props;
|
||||
const version = spec.data.version;
|
||||
|
||||
// Read the markdown file
|
||||
const filePath = path.join(process.cwd(), "src/content/spec", `${version}.md`);
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
|
||||
// Remove frontmatter
|
||||
const markdown = content.replace(/^---[\s\S]*?---\n/, "");
|
||||
|
||||
// Parse the content into sections (handles markdown -> HTML internally)
|
||||
const parsed = await parseSpecContent(markdown, version);
|
||||
---
|
||||
|
||||
<BaseLayout title={spec.data.title}>
|
||||
<Header version={version} />
|
||||
|
||||
<main>
|
||||
<Hero version={version} svgPath={parsed.svgPath} />
|
||||
|
||||
<AboutSection
|
||||
introduction={parsed.introduction}
|
||||
summary={parsed.summary}
|
||||
license={parsed.license}
|
||||
/>
|
||||
|
||||
<SpecSection
|
||||
terminology={parsed.terminology}
|
||||
terminologyTitle={parsed.terminologyTitle}
|
||||
specification={parsed.specification}
|
||||
tocItems={parsed.tocItems}
|
||||
/>
|
||||
|
||||
<FAQSection items={parsed.faq} />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</BaseLayout>
|
||||
@@ -1,30 +1,32 @@
|
||||
---
|
||||
import Default from "../layouts/Default.astro";
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
---
|
||||
|
||||
<Default title="Page Not Found">
|
||||
<div class="text-center">
|
||||
<h1
|
||||
class="text-[8rem] sm:text-[12rem] font-display font-bold leading-none
|
||||
text-[var(--color-border-strong)]
|
||||
dark:text-[var(--color-dark-border-strong)]"
|
||||
>
|
||||
404
|
||||
</h1>
|
||||
<p
|
||||
class="text-xl mb-2 text-[var(--color-text-secondary)]
|
||||
dark:text-[var(--color-dark-text-secondary)]"
|
||||
>
|
||||
Page not found
|
||||
</p>
|
||||
<p class="text-[var(--color-text-muted)] dark:text-[var(--color-dark-text-muted)]">
|
||||
The page you're looking for doesn't exist.
|
||||
</p>
|
||||
<a
|
||||
href="/"
|
||||
class="inline-block mt-8 btn btn-primary"
|
||||
>
|
||||
Go to homepage
|
||||
</a>
|
||||
<BaseLayout title="Page Not Found">
|
||||
<div class="flex flex-col items-center justify-center min-h-screen p-8">
|
||||
<div class="text-center">
|
||||
<h1
|
||||
class="text-[8rem] sm:text-[12rem] font-display font-bold leading-none
|
||||
text-gray-300 dark:text-neutral-700"
|
||||
>
|
||||
404
|
||||
</h1>
|
||||
<p class="text-xl mb-2 text-gray-600 dark:text-neutral-400">
|
||||
Page not found
|
||||
</p>
|
||||
<p class="text-gray-500 dark:text-neutral-500">
|
||||
The page you're looking for doesn't exist.
|
||||
</p>
|
||||
<a
|
||||
href="/"
|
||||
class="inline-flex items-center justify-center gap-2 mt-8
|
||||
px-5 py-2.5 text-sm font-medium rounded-lg
|
||||
transition-all cursor-pointer
|
||||
bg-sky-600 text-white
|
||||
hover:bg-sky-500 hover:-translate-y-0.5 hover:shadow-md"
|
||||
>
|
||||
Go to homepage
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</Default>
|
||||
</BaseLayout>
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { unified } from "unified";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkRehype from "remark-rehype";
|
||||
import rehypeStringify from "rehype-stringify";
|
||||
|
||||
import SinglePage from "../layouts/SinglePage.astro";
|
||||
import Header from "../components/Header.astro";
|
||||
import Hero from "../components/Hero.astro";
|
||||
import AboutSection from "../components/AboutSection.astro";
|
||||
import SpecSection from "../components/SpecSection.astro";
|
||||
import FAQSection from "../components/FAQSection.astro";
|
||||
import { parseSpecContent } from "../utils/parseSpecContent";
|
||||
import SpecLayout from "../layouts/SpecLayout.astro";
|
||||
import { config } from "../config";
|
||||
|
||||
// Render the current/latest version
|
||||
@@ -24,83 +12,6 @@ const spec = specs.find((s) => s.data.version === version);
|
||||
if (!spec) {
|
||||
throw new Error(`Spec version ${version} not found`);
|
||||
}
|
||||
|
||||
// Read and process the markdown file
|
||||
const filePath = path.join(
|
||||
process.cwd(),
|
||||
"src/content/spec",
|
||||
`${version}.md`
|
||||
);
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
|
||||
// Remove frontmatter
|
||||
const body = content.replace(/^---[\s\S]*?---\n/, "");
|
||||
|
||||
// Process markdown to HTML
|
||||
const result = await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkRehype, { allowDangerousHtml: true })
|
||||
.use(rehypeStringify, { allowDangerousHtml: true })
|
||||
.process(body);
|
||||
|
||||
const html = String(result);
|
||||
|
||||
// Parse the content into sections
|
||||
const parsed = parseSpecContent(html, version);
|
||||
---
|
||||
|
||||
<SinglePage title={spec.data.title} version={version}>
|
||||
<Header version={version} />
|
||||
|
||||
<main>
|
||||
<Hero version={version} svgPath={parsed.svgPath} />
|
||||
|
||||
<AboutSection
|
||||
introduction={parsed.introduction}
|
||||
summary={parsed.summary}
|
||||
about={parsed.about}
|
||||
license={parsed.license}
|
||||
/>
|
||||
|
||||
<SpecSection
|
||||
terminology={parsed.terminology}
|
||||
specification={parsed.specification}
|
||||
tocItems={parsed.tocItems}
|
||||
/>
|
||||
|
||||
<FAQSection items={parsed.faq} />
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer
|
||||
class="py-8 text-center text-sm
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"
|
||||
>
|
||||
<div class="section-container">
|
||||
<p>
|
||||
Git Common-Flow is authored by
|
||||
<a
|
||||
href="https://jimeh.me/"
|
||||
class="hover:text-[var(--color-accent)]"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Jim Myhrberg
|
||||
</a>
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
<a
|
||||
href="https://creativecommons.org/licenses/by/4.0/"
|
||||
class="hover:text-[var(--color-accent)]"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
CC BY 4.0
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</SinglePage>
|
||||
<SpecLayout spec={spec} />
|
||||
|
||||
@@ -1,20 +1,7 @@
|
||||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import { unified } from "unified";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkRehype from "remark-rehype";
|
||||
import rehypeStringify from "rehype-stringify";
|
||||
|
||||
import SinglePage from "../../layouts/SinglePage.astro";
|
||||
import Header from "../../components/Header.astro";
|
||||
import Hero from "../../components/Hero.astro";
|
||||
import AboutSection from "../../components/AboutSection.astro";
|
||||
import SpecSection from "../../components/SpecSection.astro";
|
||||
import FAQSection from "../../components/FAQSection.astro";
|
||||
import { parseSpecContent } from "../../utils/parseSpecContent";
|
||||
import { config } from "../../config";
|
||||
import SpecLayout from "../../layouts/SpecLayout.astro";
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const specs = await getCollection("spec");
|
||||
@@ -25,84 +12,6 @@ export async function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { spec } = Astro.props;
|
||||
const version = spec.data.version;
|
||||
|
||||
// Read and process the markdown file
|
||||
const filePath = path.join(
|
||||
process.cwd(),
|
||||
"src/content/spec",
|
||||
`${version}.md`
|
||||
);
|
||||
const content = fs.readFileSync(filePath, "utf-8");
|
||||
|
||||
// Remove frontmatter
|
||||
const body = content.replace(/^---[\s\S]*?---\n/, "");
|
||||
|
||||
// Process markdown to HTML
|
||||
const result = await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkRehype, { allowDangerousHtml: true })
|
||||
.use(rehypeStringify, { allowDangerousHtml: true })
|
||||
.process(body);
|
||||
|
||||
const html = String(result);
|
||||
|
||||
// Parse the content into sections
|
||||
const parsed = parseSpecContent(html, version);
|
||||
---
|
||||
|
||||
<SinglePage title={spec.data.title} version={version}>
|
||||
<Header version={version} />
|
||||
|
||||
<main>
|
||||
<Hero version={version} svgPath={parsed.svgPath} />
|
||||
|
||||
<AboutSection
|
||||
introduction={parsed.introduction}
|
||||
summary={parsed.summary}
|
||||
about={parsed.about}
|
||||
license={parsed.license}
|
||||
/>
|
||||
|
||||
<SpecSection
|
||||
terminology={parsed.terminology}
|
||||
specification={parsed.specification}
|
||||
tocItems={parsed.tocItems}
|
||||
/>
|
||||
|
||||
<FAQSection items={parsed.faq} />
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer
|
||||
class="py-8 text-center text-sm
|
||||
text-[var(--color-text-muted)]
|
||||
dark:text-[var(--color-dark-text-muted)]
|
||||
border-t border-[var(--color-border)]
|
||||
dark:border-[var(--color-dark-border)]"
|
||||
>
|
||||
<div class="section-container">
|
||||
<p>
|
||||
Git Common-Flow is authored by
|
||||
<a
|
||||
href="https://jimeh.me/"
|
||||
class="hover:text-[var(--color-accent)]"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Jim Myhrberg
|
||||
</a>
|
||||
</p>
|
||||
<p class="mt-2">
|
||||
<a
|
||||
href="https://creativecommons.org/licenses/by/4.0/"
|
||||
class="hover:text-[var(--color-accent)]"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
CC BY 4.0
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</SinglePage>
|
||||
<SpecLayout spec={spec} />
|
||||
|
||||
64
src/scripts/activeSectionTracker.ts
Normal file
64
src/scripts/activeSectionTracker.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
export interface ActiveSectionTrackerOptions {
|
||||
linkSelector: string;
|
||||
sectionIdAttr?: string;
|
||||
headerOffset?: number;
|
||||
defaultToFirst?: boolean;
|
||||
}
|
||||
|
||||
export function initActiveSectionTracker(
|
||||
options: ActiveSectionTrackerOptions,
|
||||
): void {
|
||||
const {
|
||||
linkSelector,
|
||||
sectionIdAttr = "data-section-id",
|
||||
headerOffset = 100,
|
||||
defaultToFirst = true,
|
||||
} = options;
|
||||
|
||||
const links = document.querySelectorAll(linkSelector);
|
||||
const sections: { id: string; element: Element }[] = [];
|
||||
|
||||
// Collect unique section IDs
|
||||
const seenIds = new Set<string>();
|
||||
links.forEach((link) => {
|
||||
const id = link.getAttribute(sectionIdAttr);
|
||||
if (id && !seenIds.has(id)) {
|
||||
seenIds.add(id);
|
||||
const section = document.getElementById(id);
|
||||
if (section) {
|
||||
sections.push({ id, element: section });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function updateActiveSection(): void {
|
||||
let activeId: string | null = defaultToFirst ? sections[0]?.id : null;
|
||||
|
||||
for (const { id, element } of sections) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
if (rect.top <= headerOffset) {
|
||||
activeId = id;
|
||||
}
|
||||
}
|
||||
|
||||
links.forEach((link) => {
|
||||
const linkId = link.getAttribute(sectionIdAttr);
|
||||
link.classList.toggle("active", linkId === activeId);
|
||||
});
|
||||
}
|
||||
|
||||
// Update on scroll with throttling
|
||||
let ticking = false;
|
||||
window.addEventListener("scroll", () => {
|
||||
if (!ticking) {
|
||||
requestAnimationFrame(() => {
|
||||
updateActiveSection();
|
||||
ticking = false;
|
||||
});
|
||||
ticking = true;
|
||||
}
|
||||
});
|
||||
|
||||
// Initial update
|
||||
updateActiveSection();
|
||||
}
|
||||
@@ -1,39 +1,17 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "@tailwindcss/typography";
|
||||
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
@theme {
|
||||
/* Colors - refined palette */
|
||||
--color-sidebar: #0a0a0a;
|
||||
--color-sidebar-hover: #1a1a1a;
|
||||
--color-accent: #1f8dd6;
|
||||
--color-accent-light: #4da6e8;
|
||||
--color-accent-muted: rgba(31, 141, 214, 0.15);
|
||||
--color-text-primary: #0a0a0a;
|
||||
--color-text-secondary: #525252;
|
||||
--color-text-muted: #737373;
|
||||
--color-bg-primary: #fafafa;
|
||||
--color-bg-secondary: #f5f5f5;
|
||||
--color-bg-code: #f0f0f0;
|
||||
--color-bg-code-inline: rgba(0, 0, 0, 0.06);
|
||||
--color-border: #e5e5e5;
|
||||
--color-border-strong: #d4d4d4;
|
||||
/* Accent colors - using Tailwind sky palette */
|
||||
--color-accent: theme(colors.sky.500);
|
||||
--color-accent-light: theme(colors.sky.400);
|
||||
|
||||
/* Dark mode colors */
|
||||
--color-dark-text-primary: #fafafa;
|
||||
--color-dark-text-secondary: #a3a3a3;
|
||||
--color-dark-text-muted: #737373;
|
||||
--color-dark-bg-primary: #0a0a0a;
|
||||
--color-dark-bg-secondary: #141414;
|
||||
--color-dark-bg-code: #1a1a1a;
|
||||
--color-dark-bg-code-inline: rgba(255, 255, 255, 0.1);
|
||||
--color-dark-border: #262626;
|
||||
--color-dark-border-strong: #404040;
|
||||
--color-dark-accent-muted: rgba(31, 141, 214, 0.2);
|
||||
|
||||
/* Fonts - distinctive choices */
|
||||
--font-display: "Bricolage Grotesque", system-ui, sans-serif;
|
||||
--font-sans: "DM Sans", system-ui, sans-serif;
|
||||
--font-mono: "JetBrains Mono", "SF Mono", Consolas, monospace;
|
||||
/* Fonts - self-hosted via fontsource */
|
||||
--font-display: "Bricolage Grotesque Variable", system-ui, sans-serif;
|
||||
--font-sans: "DM Sans Variable", system-ui, sans-serif;
|
||||
--font-mono: "JetBrains Mono Variable", "SF Mono", Consolas, monospace;
|
||||
|
||||
/* Sizing */
|
||||
--header-height: 4rem;
|
||||
@@ -52,7 +30,7 @@
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
--shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.12);
|
||||
--shadow-glow: 0 0 40px rgba(31, 141, 214, 0.15);
|
||||
--shadow-glow: 0 0 40px theme(colors.sky.500 / 15%);
|
||||
}
|
||||
|
||||
/* Smooth scroll */
|
||||
@@ -78,23 +56,28 @@ html {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 1.7;
|
||||
color: var(--color-text-primary);
|
||||
background-color: var(--color-bg-primary);
|
||||
overflow-x: hidden;
|
||||
background-color: theme(colors.slate.50);
|
||||
color: theme(colors.slate.950);
|
||||
}
|
||||
|
||||
.dark body {
|
||||
color: var(--color-dark-text-primary);
|
||||
background-color: var(--color-dark-bg-primary);
|
||||
background-color: theme(colors.neutral.950);
|
||||
color: theme(colors.neutral.50);
|
||||
}
|
||||
|
||||
/* Typography */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
line-height: 1.2;
|
||||
letter-spacing: -0.02em;
|
||||
color: theme(colors.slate.950);
|
||||
}
|
||||
|
||||
.dark h1,
|
||||
@@ -103,7 +86,7 @@ html {
|
||||
.dark h4,
|
||||
.dark h5,
|
||||
.dark h6 {
|
||||
color: var(--color-dark-text-primary);
|
||||
color: theme(colors.neutral.50);
|
||||
}
|
||||
|
||||
h1 {
|
||||
@@ -144,26 +127,26 @@ html {
|
||||
code {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.875em;
|
||||
background-color: var(--color-bg-code-inline);
|
||||
border-radius: 4px;
|
||||
padding: 0.2em 0.4em;
|
||||
background-color: theme(colors.slate.950 / 5%);
|
||||
}
|
||||
|
||||
.dark code {
|
||||
background-color: var(--color-dark-bg-code-inline);
|
||||
background-color: theme(colors.neutral.400 / 15%);
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: var(--font-mono);
|
||||
background-color: var(--color-bg-code);
|
||||
border-radius: 8px;
|
||||
padding: 1.25rem;
|
||||
overflow-x: auto;
|
||||
line-height: 1.6;
|
||||
background-color: theme(colors.slate.200);
|
||||
}
|
||||
|
||||
.dark pre {
|
||||
background-color: var(--color-dark-bg-code);
|
||||
background-color: theme(colors.neutral.900);
|
||||
}
|
||||
|
||||
pre > code {
|
||||
@@ -173,7 +156,8 @@ html {
|
||||
}
|
||||
|
||||
/* Lists */
|
||||
ul, ol {
|
||||
ul,
|
||||
ol {
|
||||
margin-bottom: 1.25rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
@@ -190,11 +174,15 @@ html {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
ol ol, ul ol {
|
||||
ol ol,
|
||||
ul ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
ul ul ol, ul ol ol, ol ul ol, ol ol ol {
|
||||
ul ul ol,
|
||||
ul ol ol,
|
||||
ol ul ol,
|
||||
ol ol ol {
|
||||
list-style-type: decimal;
|
||||
}
|
||||
|
||||
@@ -203,12 +191,12 @@ html {
|
||||
border-left: 3px solid var(--color-accent);
|
||||
padding-left: 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
color: var(--color-text-secondary);
|
||||
font-style: italic;
|
||||
color: theme(colors.slate.600);
|
||||
}
|
||||
|
||||
.dark blockquote {
|
||||
color: var(--color-dark-text-secondary);
|
||||
color: theme(colors.neutral.400);
|
||||
}
|
||||
|
||||
/* Strong text */
|
||||
@@ -216,17 +204,6 @@ html {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Selection */
|
||||
::selection {
|
||||
background-color: var(--color-accent-muted);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.dark ::selection {
|
||||
background-color: var(--color-dark-accent-muted);
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
|
||||
/* Focus styles */
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--color-accent);
|
||||
@@ -236,8 +213,13 @@ html {
|
||||
|
||||
/* Keyframe animations - defined outside layers for proper cascade */
|
||||
@keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in-up {
|
||||
@@ -245,6 +227,7 @@ html {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
@@ -256,6 +239,7 @@ html {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
@@ -267,6 +251,7 @@ html {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
@@ -274,8 +259,14 @@ html {
|
||||
}
|
||||
|
||||
@keyframes bounce-subtle {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-8px); }
|
||||
0%,
|
||||
100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation utility classes */
|
||||
@@ -304,71 +295,128 @@ html {
|
||||
}
|
||||
|
||||
/* Animation delays */
|
||||
.delay-100 { animation-delay: 100ms; }
|
||||
.delay-200 { animation-delay: 200ms; }
|
||||
.delay-300 { animation-delay: 300ms; }
|
||||
.delay-400 { animation-delay: 400ms; }
|
||||
.delay-500 { animation-delay: 500ms; }
|
||||
.delay-600 { animation-delay: 600ms; }
|
||||
.delay-700 { animation-delay: 700ms; }
|
||||
.delay-800 { animation-delay: 800ms; }
|
||||
.delay-100 {
|
||||
animation-delay: 100ms;
|
||||
}
|
||||
|
||||
.delay-200 {
|
||||
animation-delay: 200ms;
|
||||
}
|
||||
|
||||
.delay-300 {
|
||||
animation-delay: 300ms;
|
||||
}
|
||||
|
||||
.delay-400 {
|
||||
animation-delay: 400ms;
|
||||
}
|
||||
|
||||
.delay-500 {
|
||||
animation-delay: 500ms;
|
||||
}
|
||||
|
||||
.delay-600 {
|
||||
animation-delay: 600ms;
|
||||
}
|
||||
|
||||
.delay-700 {
|
||||
animation-delay: 700ms;
|
||||
}
|
||||
|
||||
.delay-800 {
|
||||
animation-delay: 800ms;
|
||||
}
|
||||
|
||||
/* Component styles */
|
||||
@layer components {
|
||||
/* Glass effect for header */
|
||||
.glass {
|
||||
background: rgba(250, 250, 250, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.dark .glass {
|
||||
background: rgba(10, 10, 10, 0.85);
|
||||
}
|
||||
|
||||
/* Gradient text */
|
||||
.gradient-text {
|
||||
background: linear-gradient(135deg, var(--color-text-primary) 0%, var(--color-accent) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.dark .gradient-text {
|
||||
background: linear-gradient(135deg, var(--color-dark-text-primary) 0%, var(--color-accent-light) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
/* Section container */
|
||||
/* Section container - uses CSS vars, keep here */
|
||||
.section-container {
|
||||
max-width: calc(var(--content-max-width) + var(--sidebar-width) + 4rem);
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--section-padding-x);
|
||||
}
|
||||
|
||||
/* Content prose styling */
|
||||
/* Prose styling for markdown content - can't add classes to rendered HTML */
|
||||
.prose-spec {
|
||||
max-width: var(--content-max-width);
|
||||
}
|
||||
|
||||
.prose-spec h2 {
|
||||
font-size: 1.75rem;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 1.5rem;
|
||||
padding-bottom: 0.75rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
margin-top: 4rem;
|
||||
border-bottom: 1px solid theme(colors.slate.200);
|
||||
}
|
||||
|
||||
.dark .prose-spec h2 {
|
||||
border-bottom-color: var(--color-dark-border);
|
||||
border-bottom-color: theme(colors.neutral.800);
|
||||
}
|
||||
|
||||
.prose-spec h2:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.prose-spec h3 {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
color: theme(colors.slate.600);
|
||||
}
|
||||
|
||||
.dark .prose-spec h3 {
|
||||
color: var(--color-dark-text-secondary);
|
||||
color: theme(colors.neutral.400);
|
||||
}
|
||||
|
||||
.prose-spec p {
|
||||
color: theme(colors.slate.600);
|
||||
}
|
||||
|
||||
.dark .prose-spec p {
|
||||
color: theme(colors.neutral.400);
|
||||
}
|
||||
|
||||
.prose-spec strong {
|
||||
color: theme(colors.slate.950);
|
||||
}
|
||||
|
||||
.dark .prose-spec strong {
|
||||
color: theme(colors.neutral.50);
|
||||
}
|
||||
|
||||
.prose-spec li {
|
||||
color: theme(colors.slate.600);
|
||||
}
|
||||
|
||||
.dark .prose-spec li {
|
||||
color: theme(colors.neutral.400);
|
||||
}
|
||||
|
||||
/* Nested ordered list counters (spec numbering: 1., 1.1., 1.2.) */
|
||||
.prose-spec ol {
|
||||
padding-left: 2.5rem;
|
||||
counter-reset: item;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.prose-spec ol > li {
|
||||
counter-increment: item;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.prose-spec ol > li::before {
|
||||
content: counters(item, ".") ".";
|
||||
position: absolute;
|
||||
left: -2.5rem;
|
||||
width: 2rem;
|
||||
text-align: right;
|
||||
font-weight: 500;
|
||||
color: theme(colors.slate.400);
|
||||
}
|
||||
|
||||
.dark .prose-spec ol > li::before {
|
||||
color: theme(colors.neutral.500);
|
||||
}
|
||||
|
||||
.prose-spec img {
|
||||
@@ -378,169 +426,47 @@ html {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Subtle border */
|
||||
.border-subtle {
|
||||
border-color: var(--color-border);
|
||||
.prose-spec p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.dark .border-subtle {
|
||||
border-color: var(--color-dark-border);
|
||||
/* Nav link active state (toggled by JavaScript) */
|
||||
.nav-link.active {
|
||||
color: theme(colors.sky.700) !important;
|
||||
background-color: theme(colors.sky.600 / 15%) !important;
|
||||
}
|
||||
|
||||
/* Button base */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
border-radius: 8px;
|
||||
transition: all var(--transition-fast);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--color-accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: var(--color-accent-light);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background-color: transparent;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.btn-ghost:hover {
|
||||
background-color: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.dark .btn-ghost {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
|
||||
.dark .btn-ghost:hover {
|
||||
background-color: var(--color-dark-bg-secondary);
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
|
||||
/* Sidebar link styles */
|
||||
.sidebar-link {
|
||||
display: block;
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted);
|
||||
border-radius: 6px;
|
||||
transition: all var(--transition-fast);
|
||||
border-left: 2px solid transparent;
|
||||
margin-left: -2px;
|
||||
}
|
||||
|
||||
.sidebar-link:hover {
|
||||
color: var(--color-text-primary);
|
||||
background-color: var(--color-bg-secondary);
|
||||
}
|
||||
|
||||
.dark .sidebar-link {
|
||||
color: var(--color-dark-text-muted);
|
||||
}
|
||||
|
||||
.dark .sidebar-link:hover {
|
||||
color: var(--color-dark-text-primary);
|
||||
background-color: var(--color-dark-bg-secondary);
|
||||
.dark .nav-link.active {
|
||||
color: theme(colors.sky.400) !important;
|
||||
background-color: theme(colors.sky.600 / 20%) !important;
|
||||
}
|
||||
|
||||
/* Sidebar link active state (toggled by JavaScript) */
|
||||
.sidebar-link.active {
|
||||
color: var(--color-accent);
|
||||
border-left-color: var(--color-accent);
|
||||
background-color: var(--color-accent-muted);
|
||||
color: theme(colors.sky.700) !important;
|
||||
background-color: theme(colors.sky.600 / 15%) !important;
|
||||
}
|
||||
|
||||
.dark .sidebar-link.active {
|
||||
color: var(--color-accent-light);
|
||||
background-color: var(--color-dark-accent-muted);
|
||||
color: theme(colors.sky.400) !important;
|
||||
background-color: theme(colors.sky.600 / 20%) !important;
|
||||
}
|
||||
|
||||
.sidebar-link-sub {
|
||||
padding-left: 1.5rem;
|
||||
font-size: 0.8125rem;
|
||||
/* Sidebar scrollbar styling */
|
||||
#spec-sidebar::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
/* Version badge */
|
||||
.version-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.75rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
background-color: var(--color-bg-secondary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 9999px;
|
||||
color: var(--color-text-muted);
|
||||
#spec-sidebar::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.dark .version-badge {
|
||||
background-color: var(--color-dark-bg-secondary);
|
||||
border-color: var(--color-dark-border);
|
||||
color: var(--color-dark-text-muted);
|
||||
#spec-sidebar::-webkit-scrollbar-thumb {
|
||||
background-color: theme(colors.slate.200);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* FAQ accordion styles */
|
||||
.faq-item {
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.dark .faq-item {
|
||||
border-bottom-color: var(--color-dark-border);
|
||||
}
|
||||
|
||||
.faq-question {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 1.5rem 0;
|
||||
text-align: left;
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-primary);
|
||||
cursor: pointer;
|
||||
transition: color var(--transition-fast);
|
||||
}
|
||||
|
||||
.dark .faq-question {
|
||||
color: var(--color-dark-text-primary);
|
||||
}
|
||||
|
||||
.faq-question:hover {
|
||||
color: var(--color-accent);
|
||||
}
|
||||
|
||||
.faq-answer {
|
||||
padding-bottom: 1.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.dark .faq-answer {
|
||||
color: var(--color-dark-text-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
/* Transitions for interactive elements */
|
||||
@layer components {
|
||||
#layout,
|
||||
#menu,
|
||||
.menu-link {
|
||||
transition: all var(--transition-base);
|
||||
.dark #spec-sidebar::-webkit-scrollbar-thumb {
|
||||
background-color: theme(colors.neutral.800);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
/**
|
||||
* Parses rendered spec HTML into structured sections for the single-page
|
||||
* layout.
|
||||
* Parses spec content using markdown AST for robust section extraction.
|
||||
*/
|
||||
|
||||
import { unified } from "unified";
|
||||
import remarkParse from "remark-parse";
|
||||
import remarkRehype from "remark-rehype";
|
||||
import rehypeStringify from "rehype-stringify";
|
||||
import type { Root, RootContent, Heading, List, ListItem } from "mdast";
|
||||
import type { Root as HastRoot } from "hast";
|
||||
|
||||
export interface TocItem {
|
||||
id: string;
|
||||
title: string;
|
||||
level: number;
|
||||
clause?: string;
|
||||
}
|
||||
|
||||
export interface FAQItem {
|
||||
@@ -19,6 +26,7 @@ export interface SpecSection {
|
||||
id: string;
|
||||
title: string;
|
||||
content: string;
|
||||
clause: string;
|
||||
}
|
||||
|
||||
export interface ParsedSpec {
|
||||
@@ -26,16 +34,17 @@ export interface ParsedSpec {
|
||||
introduction: string;
|
||||
summary: string;
|
||||
terminology: string;
|
||||
terminologyTitle: string;
|
||||
specification: string;
|
||||
specificationTitle: string;
|
||||
specSections: SpecSection[];
|
||||
faq: FAQItem[];
|
||||
about: string;
|
||||
license: string;
|
||||
tocItems: TocItem[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a heading text to a URL-friendly ID
|
||||
* Convert text to a URL-friendly ID
|
||||
*/
|
||||
function slugify(text: string): string {
|
||||
return text
|
||||
@@ -45,141 +54,214 @@ function slugify(text: string): string {
|
||||
.trim();
|
||||
}
|
||||
|
||||
type MdastNode = Root | RootContent;
|
||||
|
||||
/**
|
||||
* Extract content between two headings or to the end of the document
|
||||
* Extract plain text from an mdast node tree
|
||||
*/
|
||||
function extractSection(
|
||||
html: string,
|
||||
startHeading: string,
|
||||
endHeadings: string[] = []
|
||||
): string {
|
||||
// Find the heading (h2) - use partial match to handle additional text
|
||||
// e.g., "Git Common-Flow Specification (Common-Flow)"
|
||||
const headingPattern = new RegExp(
|
||||
`<h2[^>]*>[^<]*${escapeRegex(startHeading)}[^<]*</h2>`,
|
||||
"i"
|
||||
function extractText(node: MdastNode): string {
|
||||
if ("value" in node && typeof node.value === "string") {
|
||||
return node.value;
|
||||
}
|
||||
if ("children" in node && Array.isArray(node.children)) {
|
||||
return node.children.map((child) => extractText(child)).join("");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Find index of heading containing specific text
|
||||
*/
|
||||
function findHeadingIndex(
|
||||
nodes: RootContent[],
|
||||
text: string,
|
||||
depth: number = 2,
|
||||
): number {
|
||||
return nodes.findIndex(
|
||||
(node) =>
|
||||
node.type === "heading" &&
|
||||
(node as Heading).depth === depth &&
|
||||
extractText(node).toLowerCase().includes(text.toLowerCase()),
|
||||
);
|
||||
const match = html.match(headingPattern);
|
||||
if (!match || match.index === undefined) return "";
|
||||
|
||||
const startIdx = match.index + match[0].length;
|
||||
|
||||
// Find the next section heading
|
||||
let endIdx = html.length;
|
||||
for (const endHeading of endHeadings) {
|
||||
const endPattern = new RegExp(
|
||||
`<h2[^>]*>\\s*${escapeRegex(endHeading)}\\s*</h2>`,
|
||||
"i"
|
||||
);
|
||||
const endMatch = html.slice(startIdx).match(endPattern);
|
||||
if (endMatch && endMatch.index !== undefined) {
|
||||
const possibleEnd = startIdx + endMatch.index;
|
||||
if (possibleEnd < endIdx) {
|
||||
endIdx = possibleEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also check for any h2 as a fallback
|
||||
const anyH2 = html.slice(startIdx).match(/<h2[^>]*>/i);
|
||||
if (anyH2 && anyH2.index !== undefined) {
|
||||
const possibleEnd = startIdx + anyH2.index;
|
||||
if (possibleEnd < endIdx) {
|
||||
endIdx = possibleEnd;
|
||||
}
|
||||
}
|
||||
|
||||
return html.slice(startIdx, endIdx).trim();
|
||||
}
|
||||
|
||||
function escapeRegex(str: string): string {
|
||||
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the numbered spec sections (1. TL;DR, 2. The Master Branch, etc.)
|
||||
* Extract nodes between two headings
|
||||
*/
|
||||
function extractSpecSections(specContent: string): SpecSection[] {
|
||||
function extractSectionNodes(
|
||||
nodes: RootContent[],
|
||||
startText: string,
|
||||
depth: number = 2,
|
||||
): RootContent[] {
|
||||
const startIdx = findHeadingIndex(nodes, startText, depth);
|
||||
if (startIdx === -1) return [];
|
||||
|
||||
// Find the next heading of same or higher level
|
||||
let endIdx = nodes.length;
|
||||
for (let i = startIdx + 1; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (node.type === "heading" && (node as Heading).depth <= depth) {
|
||||
endIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return nodes after the heading (not including the heading itself)
|
||||
return nodes.slice(startIdx + 1, endIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full heading text
|
||||
*/
|
||||
function getHeadingText(
|
||||
nodes: RootContent[],
|
||||
text: string,
|
||||
depth: number = 2,
|
||||
): string {
|
||||
const idx = findHeadingIndex(nodes, text, depth);
|
||||
if (idx === -1) return text;
|
||||
return extractText(nodes[idx]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert mdast nodes to HTML string
|
||||
*/
|
||||
async function nodesToHtml(nodes: RootContent[]): Promise<string> {
|
||||
if (nodes.length === 0) return "";
|
||||
|
||||
// Create a root node with these children
|
||||
const root: Root = { type: "root", children: nodes };
|
||||
|
||||
const result = await unified()
|
||||
.use(remarkRehype, { allowDangerousHtml: true })
|
||||
.use(rehypeStringify, { allowDangerousHtml: true })
|
||||
.run(root);
|
||||
|
||||
const html = unified()
|
||||
.use(rehypeStringify, { allowDangerousHtml: true })
|
||||
.stringify(result as HastRoot);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract top-level list item titles from an ordered list
|
||||
*/
|
||||
function extractListItemTitles(list: List): string[] {
|
||||
const titles: string[] = [];
|
||||
|
||||
for (const item of list.children) {
|
||||
if (item.type !== "listItem") continue;
|
||||
|
||||
// Get the first paragraph or text content of the list item
|
||||
// The title is the text before any nested list
|
||||
let title = "";
|
||||
for (const child of item.children) {
|
||||
if (child.type === "list") break; // Stop at nested list
|
||||
if (child.type === "paragraph") {
|
||||
title = extractText(child);
|
||||
break;
|
||||
}
|
||||
// Handle inline text directly in list item
|
||||
title += extractText(child);
|
||||
}
|
||||
|
||||
title = title.split("\n")[0].trim();
|
||||
if (title) {
|
||||
titles.push(title);
|
||||
}
|
||||
}
|
||||
|
||||
return titles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the first ordered list in nodes and extract its structure
|
||||
*/
|
||||
function findSpecSections(nodes: RootContent[]): SpecSection[] {
|
||||
const sections: SpecSection[] = [];
|
||||
|
||||
// The spec uses an ordered list with nested items
|
||||
// Each top-level li starts a new section
|
||||
const olMatch = specContent.match(/<ol[^>]*>([\s\S]*?)<\/ol>/i);
|
||||
if (!olMatch) return sections;
|
||||
|
||||
// Split by top-level list items
|
||||
// We need to handle nested lists carefully
|
||||
const sectionTitles = [
|
||||
"TL;DR",
|
||||
"The Master Branch",
|
||||
"Change Branches",
|
||||
"Pull Requests",
|
||||
"Versioning",
|
||||
"Releases",
|
||||
"Short-Term Release Branches",
|
||||
"Long-term Release Branches",
|
||||
"Bug Fixes & Rollback",
|
||||
"Git Best Practices",
|
||||
];
|
||||
|
||||
// Find each section by looking for the title pattern
|
||||
for (let i = 0; i < sectionTitles.length; i++) {
|
||||
const title = sectionTitles[i];
|
||||
const id = slugify(title);
|
||||
|
||||
// For the content, we'll just use the title for navigation
|
||||
// The actual content stays in the main specification block
|
||||
sections.push({
|
||||
id: `spec-${id}`,
|
||||
title,
|
||||
content: "", // Content handled inline
|
||||
});
|
||||
for (const node of nodes) {
|
||||
if (node.type === "list" && (node as List).ordered) {
|
||||
const titles = extractListItemTitles(node as List);
|
||||
for (let i = 0; i < titles.length; i++) {
|
||||
const title = titles[i];
|
||||
sections.push({
|
||||
id: `spec-${slugify(title)}`,
|
||||
title,
|
||||
content: "",
|
||||
clause: `${i + 1}.`,
|
||||
});
|
||||
}
|
||||
break; // Only process first ordered list
|
||||
}
|
||||
}
|
||||
|
||||
return sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract FAQ items from the FAQ section HTML
|
||||
* Add anchor IDs to list items in the spec ordered list
|
||||
*/
|
||||
function extractFAQItems(faqContent: string): FAQItem[] {
|
||||
const items: FAQItem[] = [];
|
||||
function addAnchorsToList(list: List, sections: SpecSection[]): void {
|
||||
const titleMap = new Map(sections.map((s) => [s.title, s.id]));
|
||||
|
||||
// Split by h3 headings
|
||||
const h3Pattern = /<h3[^>]*>([\s\S]*?)<\/h3>/gi;
|
||||
let lastIndex = 0;
|
||||
let lastQuestion = "";
|
||||
let lastId = "";
|
||||
for (const item of list.children) {
|
||||
if (item.type !== "listItem") continue;
|
||||
|
||||
const matches = [...faqContent.matchAll(h3Pattern)];
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const match = matches[i];
|
||||
const question = match[1].replace(/<[^>]+>/g, "").trim();
|
||||
const id = slugify(question).slice(0, 50);
|
||||
|
||||
if (i > 0 && match.index !== undefined) {
|
||||
// Get content between previous h3 and this one
|
||||
const answer = faqContent.slice(lastIndex, match.index).trim();
|
||||
items.push({
|
||||
id: `faq-${lastId}`,
|
||||
question: lastQuestion,
|
||||
answer,
|
||||
});
|
||||
// Get the title of this item
|
||||
let title = "";
|
||||
for (const child of item.children) {
|
||||
if (child.type === "list") break;
|
||||
if (child.type === "paragraph") {
|
||||
title = extractText(child).split("\n")[0].trim();
|
||||
break;
|
||||
}
|
||||
title += extractText(child);
|
||||
}
|
||||
title = title.split("\n")[0].trim();
|
||||
|
||||
lastQuestion = question;
|
||||
lastId = id;
|
||||
lastIndex = match.index! + match[0].length;
|
||||
// Add ID as data attribute (will be processed by rehype)
|
||||
const id = titleMap.get(title);
|
||||
if (id) {
|
||||
// Add hProperties for rehype to convert to HTML id attribute
|
||||
(item as ListItem & { data?: { hProperties?: { id?: string } } }).data = {
|
||||
hProperties: { id },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract FAQ items from FAQ section nodes
|
||||
*/
|
||||
function extractFAQFromNodes(nodes: RootContent[]): FAQItem[] {
|
||||
const items: FAQItem[] = [];
|
||||
let currentQuestion = "";
|
||||
let currentId = "";
|
||||
|
||||
for (const node of nodes) {
|
||||
if (node.type === "heading" && (node as Heading).depth === 3) {
|
||||
// Save previous FAQ item if we had one
|
||||
if (currentQuestion) {
|
||||
items.push({
|
||||
id: currentId,
|
||||
question: currentQuestion,
|
||||
answer: "", // Placeholder, will be filled later
|
||||
});
|
||||
}
|
||||
|
||||
currentQuestion = extractText(node);
|
||||
currentId = `faq-${slugify(currentQuestion).slice(0, 50)}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't forget the last FAQ item
|
||||
if (lastQuestion) {
|
||||
const answer = faqContent.slice(lastIndex).trim();
|
||||
// Don't forget the last item
|
||||
if (currentQuestion) {
|
||||
items.push({
|
||||
id: `faq-${lastId}`,
|
||||
question: lastQuestion,
|
||||
answer,
|
||||
id: currentId,
|
||||
question: currentQuestion,
|
||||
answer: "",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,23 +274,28 @@ function extractFAQItems(faqContent: string): FAQItem[] {
|
||||
function buildTocItems(parsed: Partial<ParsedSpec>): TocItem[] {
|
||||
const items: TocItem[] = [];
|
||||
|
||||
// Main sections
|
||||
if (parsed.introduction) {
|
||||
items.push({ id: "introduction", title: "Introduction", level: 2 });
|
||||
}
|
||||
if (parsed.summary) {
|
||||
items.push({ id: "summary", title: "Summary", level: 2 });
|
||||
}
|
||||
if (parsed.terminology) {
|
||||
items.push({ id: "terminology", title: "Terminology", level: 2 });
|
||||
items.push({
|
||||
id: "terminology",
|
||||
title: parsed.terminologyTitle || "Terminology",
|
||||
level: 2,
|
||||
});
|
||||
}
|
||||
if (parsed.specification) {
|
||||
items.push({ id: "specification", title: "Specification", level: 2 });
|
||||
items.push({
|
||||
id: "specification",
|
||||
title: "Specification",
|
||||
level: 2,
|
||||
});
|
||||
|
||||
// Add spec subsections
|
||||
if (parsed.specSections) {
|
||||
for (const section of parsed.specSections) {
|
||||
items.push({ id: section.id, title: section.title, level: 3 });
|
||||
items.push({
|
||||
id: section.id,
|
||||
title: section.title,
|
||||
level: 3,
|
||||
clause: section.clause,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,75 +304,110 @@ function buildTocItems(parsed: Partial<ParsedSpec>): TocItem[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main parsing function - takes rendered HTML and returns structured content
|
||||
* Main parsing function - takes markdown content and returns structured content
|
||||
*/
|
||||
export function parseSpecContent(html: string, version: string): ParsedSpec {
|
||||
export async function parseSpecContent(
|
||||
markdown: string,
|
||||
version: string,
|
||||
): Promise<ParsedSpec> {
|
||||
const svgPath = `/spec/${version}.svg`;
|
||||
|
||||
// Remove the title (h1) and SVG from the content for parsing
|
||||
let content = html;
|
||||
// Parse markdown to AST
|
||||
const tree = unified().use(remarkParse).parse(markdown) as Root;
|
||||
|
||||
// Remove the h1 title
|
||||
content = content.replace(/<h1[^>]*>[\s\S]*?<\/h1>/i, "");
|
||||
// Remove title (h1) and SVG image from the tree
|
||||
const nodes = tree.children.filter((node) => {
|
||||
if (node.type === "heading" && (node as Heading).depth === 1) return false;
|
||||
if (node.type === "paragraph") {
|
||||
const text = extractText(node);
|
||||
if (text.includes(".svg")) return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// Remove the SVG img tag
|
||||
content = content.replace(/<img[^>]*\.svg[^>]*>/i, "");
|
||||
|
||||
// Extract each section
|
||||
const introduction = extractSection(content, "Introduction", [
|
||||
"Summary",
|
||||
"Terminology",
|
||||
"Git Common-Flow",
|
||||
"FAQ",
|
||||
"About",
|
||||
"License",
|
||||
]);
|
||||
|
||||
const summary = extractSection(content, "Summary", [
|
||||
"Terminology",
|
||||
"Git Common-Flow",
|
||||
"FAQ",
|
||||
"About",
|
||||
"License",
|
||||
]);
|
||||
|
||||
const terminology = extractSection(content, "Terminology", [
|
||||
"Git Common-Flow",
|
||||
"FAQ",
|
||||
"About",
|
||||
"License",
|
||||
]);
|
||||
|
||||
const specification = extractSection(
|
||||
content,
|
||||
// Get heading titles
|
||||
const terminologyTitle = getHeadingText(nodes, "Terminology");
|
||||
const specificationTitle = getHeadingText(
|
||||
nodes,
|
||||
"Git Common-Flow Specification",
|
||||
["FAQ", "About", "License"]
|
||||
);
|
||||
|
||||
const faqContent = extractSection(content, "FAQ", ["About", "License"]);
|
||||
// Extract section nodes
|
||||
const introNodes = extractSectionNodes(nodes, "Introduction");
|
||||
const summaryNodes = extractSectionNodes(nodes, "Summary");
|
||||
const terminologyNodes = extractSectionNodes(nodes, "Terminology");
|
||||
const specNodes = extractSectionNodes(nodes, "Git Common-Flow Specification");
|
||||
const faqNodes = extractSectionNodes(nodes, "FAQ");
|
||||
const licenseNodes = extractSectionNodes(nodes, "License");
|
||||
|
||||
const about = extractSection(content, "About", ["License"]);
|
||||
// Extract spec sections from the first ordered list
|
||||
const specSections = findSpecSections(specNodes);
|
||||
|
||||
const license = extractSection(content, "License", []);
|
||||
// Add anchor IDs to spec list items
|
||||
for (const node of specNodes) {
|
||||
if (node.type === "list" && (node as List).ordered) {
|
||||
addAnchorsToList(node as List, specSections);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse subsections
|
||||
const specSections = extractSpecSections(specification);
|
||||
const faq = extractFAQItems(faqContent);
|
||||
// Extract FAQ items structure
|
||||
const faqItems = extractFAQFromNodes(faqNodes);
|
||||
|
||||
// Collect FAQ answer nodes for each item
|
||||
const faqAnswerNodes: RootContent[][] = [];
|
||||
let currentAnswerNodes: RootContent[] = [];
|
||||
|
||||
for (const node of faqNodes) {
|
||||
if (node.type === "heading" && (node as Heading).depth === 3) {
|
||||
if (currentAnswerNodes.length > 0) {
|
||||
faqAnswerNodes.push(currentAnswerNodes);
|
||||
}
|
||||
currentAnswerNodes = [];
|
||||
} else {
|
||||
currentAnswerNodes.push(node);
|
||||
}
|
||||
}
|
||||
// Don't forget the last answer
|
||||
if (currentAnswerNodes.length > 0) {
|
||||
faqAnswerNodes.push(currentAnswerNodes);
|
||||
}
|
||||
|
||||
// Convert sections to HTML
|
||||
const [introduction, summary, terminology, specification, license] =
|
||||
await Promise.all([
|
||||
nodesToHtml(introNodes),
|
||||
nodesToHtml(summaryNodes),
|
||||
nodesToHtml(terminologyNodes),
|
||||
nodesToHtml(specNodes),
|
||||
nodesToHtml(licenseNodes),
|
||||
]);
|
||||
|
||||
// Convert FAQ answers to HTML
|
||||
const faqAnswers = await Promise.all(
|
||||
faqAnswerNodes.map((nodes) => nodesToHtml(nodes)),
|
||||
);
|
||||
|
||||
// Assign FAQ answers
|
||||
const faq = faqItems.map((item, i) => ({
|
||||
...item,
|
||||
answer: faqAnswers[i] || "",
|
||||
}));
|
||||
|
||||
const parsed: ParsedSpec = {
|
||||
svgPath,
|
||||
introduction,
|
||||
summary,
|
||||
terminology,
|
||||
terminologyTitle,
|
||||
specification,
|
||||
specificationTitle,
|
||||
specSections,
|
||||
faq,
|
||||
about,
|
||||
license,
|
||||
tocItems: [],
|
||||
};
|
||||
|
||||
// Build TOC
|
||||
parsed.tocItems = buildTocItems(parsed);
|
||||
|
||||
return parsed;
|
||||
|
||||
Reference in New Issue
Block a user