Refactor: Standardize UI card styling and remove em-dashes

- Unified card headers: gap-3, Icon size 20, text-accent color
- PlansCard: collapsible sections, animated expand/collapse
- update-plans-data.ts: export all plans (no limit)
- Replaced all em-dashes with colons or full sentences
- Content text standardized to text-lg across all cards
- FeatureCard, ArchHighlight descriptions adjusted
This commit is contained in:
phranck
2026-02-07 00:24:19 +01:00
parent 0d10b0255d
commit cfa8b31631
70 changed files with 946 additions and 780 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* Prebuild script runs before `next build` via the `prebuild` npm script.
* Prebuild script: runs before `next build` via the `prebuild` npm script.
*
* 1. Generates terminal-data.ts from terminal-script.md
* 2. Counts Swift @Test and @Suite annotations to produce project-stats.json
+5 -9
View File
@@ -1,6 +1,6 @@
/**
* Extracts plan data from plans/open/ and plans/done/ directories.
* Generates plans.json with top 5 open and top 5 done plans.
* Generates plans.json with all open and done plans.
*
* Runs via GitHub Actions (hourly) or manual npm script.
* Output: docs/public/data/plans.json
@@ -97,20 +97,16 @@ function main() {
openPlans.sort(sortByDateDesc);
donePlans.sort(sortByDateDesc);
// Get top 5 of each
const topOpenPlans = openPlans.slice(0, 5);
const topDonePlans = donePlans.slice(0, 5);
// Build output
// Build output with all plans
const output = {
generated: new Date().toISOString(),
open: topOpenPlans.map(({ date, slug, title, preface }) => ({
open: openPlans.map(({ date, slug, title, preface }) => ({
date,
slug,
title,
preface,
})),
done: topDonePlans.map(({ date, slug, title, preface }) => ({
done: donePlans.map(({ date, slug, title, preface }) => ({
date,
slug,
title,
@@ -127,7 +123,7 @@ function main() {
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2));
console.log(
`✓ Generated plans.json (${topOpenPlans.length} open, ${topDonePlans.length} done)`
`✓ Generated plans.json (${openPlans.length} open, ${donePlans.length} done)`
);
console.log(` Location: ${outputPath}`);
}
+8 -8
View File
@@ -475,7 +475,7 @@ interface GitHubSocialAccount {
/**
* Fetches social accounts from GitHub's `/users/{login}/social_accounts` endpoint.
* These are user-provided and authoritative highest trust after manual overrides.
* These are user-provided and authoritative: highest trust after manual overrides.
*/
async function fetchGitHubSocialAccounts(login: string): Promise<ProfileSocialAccounts> {
const accounts: ProfileSocialAccounts = {};
@@ -615,7 +615,7 @@ async function searchMastodonByUsername(username: string, githubAvatarUrl: strin
if (response.ok) {
const data = (await response.json()) as { username: string; url: string; avatar: string };
// Avatar match is a bonus signal if it matches, we're confident immediately
// Avatar match is a bonus signal: if it matches, we're confident immediately
const avatarMatch = await avatarsMatch(githubAvatarUrl, data.avatar);
if (avatarMatch) {
console.log(` Found Mastodon @${username} on ${instance} (avatar verified ✓)`);
@@ -627,7 +627,7 @@ async function searchMastodonByUsername(username: string, githubAvatarUrl: strin
};
}
// No avatar match accept as unverified candidate.
// No avatar match: accept as unverified candidate.
// Cross-verification will check for back-links and either verify or remove it.
console.log(` Found Mastodon @${username} on ${instance} (pending cross-verification)`);
return {
@@ -764,7 +764,7 @@ async function searchBlueskyByUsername(username: string, githubAvatarUrl: string
if (response.ok) {
const data = (await response.json()) as { handle: string; avatar?: string };
// Avatar match is a bonus signal if it matches, we're confident immediately
// Avatar match is a bonus signal: if it matches, we're confident immediately
if (data.avatar) {
const avatarMatch = await avatarsMatch(githubAvatarUrl, data.avatar);
if (avatarMatch) {
@@ -778,7 +778,7 @@ async function searchBlueskyByUsername(username: string, githubAvatarUrl: string
}
}
// No avatar match accept as unverified candidate.
// No avatar match: accept as unverified candidate.
// Cross-verification will check for back-links and either verify or remove it.
console.log(` Found Bluesky @${data.handle} (pending cross-verification)`);
return {
@@ -899,7 +899,7 @@ async function crossPlatformVerify(accounts: ProfileSocialAccounts, user: GitHub
accounts.mastodon.verified = true;
validationResults.push("Mastodon→GitHub ✓");
} else if (accounts.mastodon.source === "username-match") {
// Unverified username-match without back-link remove to avoid false positives
// Unverified username-match without back-link: remove to avoid false positives
console.log(` Removing unverified Mastodon match (no back-link to GitHub)`);
delete accounts.mastodon;
}
@@ -912,7 +912,7 @@ async function crossPlatformVerify(accounts: ProfileSocialAccounts, user: GitHub
accounts.bluesky.verified = true;
validationResults.push("Bluesky→GitHub ✓");
} else if (accounts.bluesky.source === "username-match") {
// Unverified username-match without back-link remove
// Unverified username-match without back-link: remove
console.log(` Removing unverified Bluesky match (no back-link to GitHub)`);
delete accounts.bluesky;
}
@@ -1062,7 +1062,7 @@ async function main() {
// On full refresh, clear all entries so stale false positives don't survive
if (isFullRefresh) {
console.log("Full refresh clearing all cached entries");
console.log("Full refresh: clearing all cached entries");
cache.entries = {};
}