From 1af9ff12a4fe4f4dbe618b2edf39b51de88e34d5 Mon Sep 17 00:00:00 2001
From: heggria
Date: Mon, 6 Jul 2026 22:31:10 +0800
Subject: [PATCH] feat(website): make the docs site visible + complete the
favicon set
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Two things that got under-served by the release-prep work:
1. README → docs site CTA. The docs site (heggria.github.io/taskflow)
was invisible from the README — the top badge row had npm/license/CI
badges but no link to the site we built. Add a prominent
for-the-badge '📖 Read the docs' CTA between the language switcher
and the tagline, in both README.md (→ /en) and README.zh-CN.md (→
/zh-cn). It's the only for-the-badge badge in the header, so it pops.
2. Complete favicon / icon set. The site had only favicon.svg, and
worse: under output:export + basePath, Next.js doesn't prefix
/, so favicon.svg was 404'ing on
GitHub Pages (/favicon.svg vs the real /taskflow/favicon.svg). Fix:
- app/icon.tsx + app/apple-icon.tsx: ImageResponse PNGs (180²) reusing
the orange-tile + white-DAG brand motif (same as favicon.svg /
opengraph-image / plugin icons).
- app/manifest.ts: PWA manifest (theme color, any + maskable icons).
- layout.tsx: read TASKFLOW_BASE_PATH and prefix icon/manifest paths
explicitly (the real fix for the 404); add themeColor, appleWebApp.
- all three new routes export dynamic='force-static' (output:export).
Verified build emits /icon, /apple-icon, /manifest.webmanifest with
correct /taskflow-prefixed paths; icons are valid 180² RGBA PNGs.
3. Fix CHANGELOG: the release-prep edit accidentally renamed the
existing [0.1.5] heading to a second [0.1.6] (the defineFile/JSONC
insertion used it as an anchor). Restore 0.1.5 — now exactly one
0.1.6 and one 0.1.5, in descending order.
---
CHANGELOG.md | 2 +-
README.md | 4 ++
README.zh-CN.md | 4 ++
website/app/[lang]/layout.tsx | 23 +++++++++-
website/app/apple-icon.tsx | 75 ++++++++++++++++++++++++++++++++
website/app/icon.tsx | 82 +++++++++++++++++++++++++++++++++++
website/app/manifest.ts | 42 ++++++++++++++++++
7 files changed, 230 insertions(+), 2 deletions(-)
create mode 100644 website/app/apple-icon.tsx
create mode 100644 website/app/icon.tsx
create mode 100644 website/app/manifest.ts
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d3f511..917cf7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -91,7 +91,7 @@ All notable changes to taskflow are documented here. This project follows [Keep
and saved flows from the library. `safeParse()` for LLM output remains
strict. Re-exported from the `taskflow-core` barrel as `parseJsonc`.
-## [0.1.6] — 2026-07-06
+## [0.1.5] — 2026-07-03
### Added
- **Scoring gates (`score` on `gate` phases).** Deterministic, composable,
diff --git a/README.md b/README.md
index 5ea022d..8030be4 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,10 @@
简体中文
+
+
+
+
A declarative, verifiable graph of tasks for coding-agent subagents.
Not a workflow you script — a DAG you declare. Fan out · gate · loop · tournament · resume · save as a command — intermediate results stay out of your context.
Runs on the Pi coding agent, on OpenAI Codex, on Claude Code, and on OpenCode.
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 03a3db5..addb2e9 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -24,6 +24,10 @@
Русский
+
diff --git a/website/app/[lang]/layout.tsx b/website/app/[lang]/layout.tsx
index 8f15cd3..3c6fdae 100644
--- a/website/app/[lang]/layout.tsx
+++ b/website/app/[lang]/layout.tsx
@@ -24,6 +24,13 @@ const site = {
// Example: 'abc123...'
const GOOGLE_SITE_VERIFICATION = process.env.GOOGLE_SITE_VERIFICATION || '';
+// The site is deployed under a GitHub Pages subpath (/taskflow), so every
+// metadata asset URL (favicon, apple-touch-icon, manifest, icon PNGs) must be
+// prefixed with the configured basePath. Next.js does NOT apply basePath to
+// / under `output: export`, so we do
+// it explicitly here. Locally (TASKFLOW_BASE_PATH unset) this is just ''.
+const base = process.env.TASKFLOW_BASE_PATH || '';
+
export async function generateMetadata({
params,
}: {
@@ -48,8 +55,22 @@ export async function generateMetadata({
},
},
icons: {
- icon: [{ url: '/favicon.svg', type: 'image/svg+xml' }],
+ // Explicit basePath — Next.js omits it for under output:export.
+ icon: [{ url: `${base}/favicon.svg`, type: 'image/svg+xml' }],
+ apple: [{ url: `${base}/apple-icon`, sizes: '180x180', type: 'image/png' }],
+ },
+ // themeColor + appleWebApp pair with app/manifest.ts and app/apple-icon.tsx
+ // so Safari/iOS/Android render a branded tab, splash, and home-screen icon.
+ themeColor: [
+ { media: '(prefers-color-scheme: light)', color: '#fff7ed' },
+ { media: '(prefers-color-scheme: dark)', color: '#1c1917' },
+ ],
+ appleWebApp: {
+ title: 'taskflow',
+ statusBarStyle: 'default',
+ capable: true,
},
+ manifest: `${base}/manifest.webmanifest`,
verification: GOOGLE_SITE_VERIFICATION
? { google: GOOGLE_SITE_VERIFICATION }
: undefined,
diff --git a/website/app/apple-icon.tsx b/website/app/apple-icon.tsx
new file mode 100644
index 0000000..751ad61
--- /dev/null
+++ b/website/app/apple-icon.tsx
@@ -0,0 +1,75 @@
+// Apple touch icon (Next.js metadata file route → ).
+// Used by iOS Safari bookmarks, "Add to Home Screen", and Safari pinned tabs.
+// iOS renders this full-bleed then masks it to the platform's squircle itself,
+// so we fill the whole canvas (no rounded corners here) and keep the DAG motif
+// generously inset so it isn't clipped by the mask. Same orange gradient as
+// icon.tsx / favicon.svg for brand consistency.
+import { ImageResponse } from 'next/og';
+
+// `output: export` requires routes to be statically renderable.
+export const dynamic = 'force-static';
+
+export const size = { width: 180, height: 180 };
+export const contentType = 'image/png';
+export const alt = 'taskflow';
+
+export default function AppleIcon() {
+ return new ImageResponse(
+ (
+
+
+
+ ),
+ {
+ ...size,
+ },
+ );
+}
diff --git a/website/app/icon.tsx b/website/app/icon.tsx
new file mode 100644
index 0000000..7d16f5d
--- /dev/null
+++ b/website/app/icon.tsx
@@ -0,0 +1,82 @@
+// Favicon / browser-tab icon (Next.js metadata file route).
+// Emits /icon (with basePath applied automatically) as a PNG that modern
+// browsers pick up via the injected . We also keep
+// public/favicon.svg as an SVG fallback; this PNG is the canonical tab icon
+// (renders identically in Safari, which still prefers PNG over SVG favicons).
+//
+// The DAG motif matches favicon.svg and the plugin icons: an orange rounded
+// tile with three white nodes joined into a downward graph.
+import { ImageResponse } from 'next/og';
+
+// `output: export` requires routes to be statically renderable.
+export const dynamic = 'force-static';
+
+export const size = { width: 180, height: 180 };
+export const contentType = 'image/png';
+export const alt = 'taskflow';
+
+export default function Icon() {
+ return new ImageResponse(
+ (
+
+
+
+ ),
+ {
+ ...size,
+ },
+ );
+}
diff --git a/website/app/manifest.ts b/website/app/manifest.ts
new file mode 100644
index 0000000..b7ee687
--- /dev/null
+++ b/website/app/manifest.ts
@@ -0,0 +1,42 @@
+// Web App Manifest (Next.js metadata file route → /manifest.webmanifest).
+// Enables install-to-home-screen, the Android "maskable" adaptive icon, and a
+// branded splash color when the site is added to a device. Icon srcs point at
+// the metadata file routes (app/icon.tsx, app/apple-icon.tsx); Next.js applies
+// the configured basePath automatically, so no manual prefix here.
+import type { MetadataRoute } from 'next';
+
+// `output: export` requires routes to be statically renderable.
+export const dynamic = 'force-static';
+
+export default function manifest(): MetadataRoute.Manifest {
+ // basePath must be prepended manually — manifest is emitted as a static
+ // asset under output:export, so icon srcs won't get the prefix otherwise.
+ const base = process.env.TASKFLOW_BASE_PATH || '';
+ return {
+ name: 'taskflow — declarative agent orchestration',
+ short_name: 'taskflow',
+ description:
+ 'A declarative, verifiable graph of task nodes for coding-agent subagents. Fan out, gate, loop, resume, and save as a command.',
+ start_url: `${base}/`,
+ display: 'standalone',
+ background_color: '#fff7ed',
+ theme_color: '#ea580c',
+ icons: [
+ {
+ // any-purpose icon (browser tab + Android standard)
+ src: `${base}/icon`,
+ sizes: '180x180',
+ type: 'image/png',
+ purpose: 'any',
+ },
+ {
+ // maskable: Android adaptive icon — the orange tile fills the
+ // safe zone so the platform mask yields a clean squircle.
+ src: `${base}/apple-icon`,
+ sizes: '180x180',
+ type: 'image/png',
+ purpose: 'maskable',
+ },
+ ],
+ };
+}