Community Page Editorial Redesign Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Replace the noisy Community dashboard with a responsive editorial library that makes independent FlyEnv stories easy to discover and retains a clear Join the Community section.
Architecture: Keep the two pages and their static JSON datasets intact. Rebuild AppCommunityPosts as the page’s content library, preserving the existing posts and locale contract while deriving all display values locally. Restyle the two supporting components and remove the redundant scenario-map placement from both Markdown pages. A small static Node test protects the intended page composition.
Tech Stack: VitePress 1, Vue 3 Composition API, TypeScript, scoped CSS, Node.js built-in test runner, Playwright.
File structure
- Create
tests/community-page-redesign.test.mjs— checks both locale pages use the redesigned library and keep the Community join and contribution surfaces. - Modify
docs/components/AppCommunityPosts/index.vue— editorial masthead, lead article, accessible filters, article library, dataset-derived counters, and light/dark responsive styles. - Modify
docs/components/AppCommunityChannels/index.vue— accurate Community destination cards in the shared visual language. - Modify
docs/components/AppCommunityCTA/index.vue— contribution close without unsupported engagement claims. - Modify
docs/community.mdanddocs/zh/community.md— simplify component order and removeScenarioMapimports.
Task 1: Add a page-composition regression test
Files:
Create:
tests/community-page-redesign.test.mjsTest:
tests/community-page-redesign.test.mjs[ ] Step 1: Write the failing test
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import test from 'node:test'
const read = (path) => readFileSync(resolve(process.cwd(), path), 'utf8')
for (const page of ['docs/community.md', 'docs/zh/community.md']) {
test(`${page} composes the editorial community library`, () => {
const source = read(page)
assert.match(source, /import AppCommunityPosts/)
assert.match(source, /<AppCommunityPosts :posts="posts"/)
assert.match(source, /<AppCommunityChannels title=/)
assert.match(source, /<AppCommunityCTA :posts="posts"/)
assert.doesNotMatch(source, /AppCommunityScenarioMap/)
})
}
test('the post library has the editorial interaction hooks', () => {
const source = read('docs/components/AppCommunityPosts/index.vue')
for (const hook of ['community-library', 'story-masthead', 'aria-pressed', 'showMore']) {
assert.ok(source.includes(hook), `missing ${hook}`)
}
})- [ ] Step 2: Run the new test before implementation
Run: node --test tests/community-page-redesign.test.mjs
Expected: the two locale tests fail because both pages still import AppCommunityScenarioMap; the component-hook test fails because the new library does not exist yet.
Task 2: Rebuild the content surface around real developer stories
Files:
Modify:
docs/components/AppCommunityPosts/index.vueTest:
tests/community-page-redesign.test.mjs[ ] Step 1: Replace the existing template with the editorial hierarchy
Render these semantic regions in this exact order:
<section class="community-library">
<header class="story-masthead">...</header>
<section v-if="leadPost" class="lead-story">...</section>
<nav class="story-filters" :aria-label="t.filterLabel">...</nav>
<section class="story-library" :aria-live="'polite'">...</section>
</section>The masthead must contain a localized title, a plain-language explanation that public stories are gathered in one place, and four counters derived from the input data. The lead story must use a real post, its external URL, source, author, date, summary, and no more than two tags. The library must not repeat the lead post while all is selected.
- [ ] Step 2: Add typed, derived view state
Use this data shape and state logic:
interface Post {
id: string
title: string
url: string
author?: string
platform: string
language: string
date: string
summary: string
tags: string[]
featured?: boolean
quality_score?: number
relevance_score?: number
}
const activeFilter = ref('all')
const showMore = ref(false)
const orderedPosts = computed(() => [...props.posts].sort((a, b) => b.date.localeCompare(a.date)))
const leadPost = computed(() => orderedPosts.value[0])
const filteredPosts = computed(() => {
const source = activeFilter.value === 'all'
? orderedPosts.value.filter((post) => post.id !== leadPost.value?.id)
: orderedPosts.value.filter((post) => post.tags.includes(activeFilter.value))
return showMore.value ? source : source.slice(0, 9)
})
function selectFilter(value: string) {
activeFilter.value = value
showMore.value = false
}Define only filters represented by existing tag data; render each as a native button with :aria-pressed="activeFilter === filter.value" and call selectFilter(filter.value).
- [ ] Step 3: Implement locale helpers and safe fallbacks
Provide English and Chinese labels for all headings, actions, filter labels, empty states, and dates. Compute article, author, language, and platform counts with Set; filter blank authors. Render an unknown platform as text, rather than injecting HTML. Use new Intl.DateTimeFormat with the page locale. Use target="_blank" rel="noopener noreferrer ugc" for all article links.
- [ ] Step 4: Implement the shared visual system
Use scoped CSS custom properties with a warm white/ink base and one teal accent. The desktop masthead must be asymmetric (copy left, a typographic count panel right), while mobile becomes one column below 768px. Use rules and negative space for grouping; only the lead story and each article should have a bordered surface. Avoid emoji, rainbow gradients, fabricated metrics, and colored “type badge” taxonomy. Add :focus-visible, a conservative hover translation, and this motion fallback:
@media (prefers-reduced-motion: reduce) {
.community-library *,
.community-library *::before,
.community-library *::after {
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}- [ ] Step 5: Run the regression test
Run: node --test tests/community-page-redesign.test.mjs
Expected: the component-hook test passes; locale composition tests still fail until Task 4 removes ScenarioMap.
Task 3: Bring community destinations and the closing invitation into the same system
Files:
Modify:
docs/components/AppCommunityChannels/index.vueModify:
docs/components/AppCommunityCTA/index.vue[ ] Step 1: Rebuild the channel component around accurate calls to action
Keep the existing four destination names and URLs. Remove numerical status text such as member counts and online counts because it is not live data. Each card needs an icon, name, localized “Open community”/“进入社区” action label, and the existing external-link safety attributes when an URL exists. The QQ card must be explicitly marked as “Group number: 540738893”/“群号:540738893” and remain non-clickable because no join URL is provided.
- [ ] Step 2: Restyle channels
Use a four-column grid at desktop, two columns on compact screens, and one column below 480px. Give the section a subtle top rule, retain the supplied title as the visible h2, and use the same ink/teal tokens, focus state, and dark-mode overrides as the story library.
- [ ] Step 3: Simplify the contribution CTA
Keep the locale-aware existing license route. Change the message to explain that a public FlyEnv article can be surfaced here for other developers, then show only dataset-derived author/language/platform coverage. Use a neutral bordered close rather than a multi-color gradient banner, and retain the external-arrow affordance in the action.
Task 4: Assemble the two localized pages
Files:
Modify:
docs/community.mdModify:
docs/zh/community.mdTest:
tests/community-page-redesign.test.mjs[ ] Step 1: Remove the redundant scenario-map imports and render calls
For both pages, remove:
import AppCommunityScenarioMap from '../components/AppCommunityEvidence/ScenarioMap.vue'
<AppCommunityScenarioMap :posts="posts" :evidence="communityEvidence.zh" locale="zh" />Use the locale-correct relative import in the English page, and also remove the now-unused communityEvidence import. Leave this component sequence:
<AppCommunityPosts :posts="posts" locale="en" />
<AppCommunityChannels title="Join the Community" locale="en" />
<AppCommunityCTA :posts="posts" locale="en" />Use the existing Chinese titles and locale="zh" on the Chinese page.
- [ ] Step 2: Run the static tests
Run: node --test tests/community-page-redesign.test.mjs tests/community-content-refresh.test.mjs
Expected: all Community tests pass.
Task 5: Build and inspect the shipped pages
Files:
Verify:
docs/.vitepress/dist/community.htmlVerify:
docs/.vitepress/dist/zh/community.html[ ] Step 1: Build VitePress
Run: yarn docs:build
Expected: VitePress completes successfully and writes both locale pages.
- [ ] Step 2: Run a Playwright visual audit
Start the preview server and use a temporary Playwright script to capture community-en-light.png, community-en-dark.png, community-en-mobile.png, community-zh-light.png, and community-zh-mobile.png. At each locale, click an available topic filter and assert that the visible story count changes or the selected state changes; assert no browser console error occurs. Capture at 1440×1100 and 390×844.
- [ ] Step 3: Review screenshots and correct visual defects
Inspect every capture for clipped copy, contrast problems, inconsistent dark-mode backgrounds, horizontal overflow, unclear action targets, empty cards, and a lost Join the Community heading. Make focused CSS/template corrections, then rerun the relevant screenshot capture and yarn docs:build.
- [ ] Step 4: Verify scope and commit only redesign files
Run: git status --short and confirm existing task/ and .superpowers/ changes remain untouched. Stage only the five implementation files and the new regression test, then commit:
git add tests/community-page-redesign.test.mjs \
docs/components/AppCommunityPosts/index.vue \
docs/components/AppCommunityChannels/index.vue \
docs/components/AppCommunityCTA/index.vue \
docs/community.md docs/zh/community.md \
docs/superpowers/plans/2026-07-29-community-page-editorial-redesign.md
git commit -m "feat: redesign community story library"Plan self-review
- Spec coverage: Task 2 covers the masthead, data-derived lead proof, filterable article library, localized copy, responsive behavior, and motion/accessibility. Task 3 preserves and corrects the Join section plus closing CTA. Task 4 removes the competing ScenarioMap hierarchy. Task 5 covers visual verification in both locales, theme variants, desktop and mobile.
- Placeholder scan: No unresolved placeholder, ambiguous implementation instruction, or invented data remains in the plan.
- Type consistency:
Post,activeFilter,showMore,orderedPosts,leadPost,filteredPosts, andselectFilteruse the same names throughout the plan.