Redesign · codeday/web@ce713db · GitHub
Skip to content

Commit ce713db

Browse files
committed
Redesign
1 parent 118420b commit ce713db

349 files changed

Lines changed: 25349 additions & 10079 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/settings.json‎

Lines changed: 17 additions & 0 deletions
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Section leads — `StatementBlock`, or an `h1`/`h2` — title a page or a
2+
// page section, so they belong in `apps/www/src/pages/**`, rendered by the
3+
// page directly beside the component. A component under
4+
// `apps/www/src/components/**` renders only the thing below the lead (the
5+
// grid, the cards, the rows). `h3` and below title an item inside the thing
6+
// and are fine in a component. See AGENTS.md, "A section component renders
7+
// the thing, not the section."
8+
9+
const COMPONENTS_DIR = "/apps/www/src/components/";
10+
const ALLOWED_DIRS = ["/apps/www/src/components/Page/"];
11+
const SECTION_LEAD_COMPONENTS = new Set(["StatementBlock"]);
12+
const SECTION_HEADING_LEVELS = new Set(["h1", "h2"]);
13+
14+
function jsxName(node) {
15+
if (node.type === "JSXIdentifier") return node.name;
16+
if (node.type === "JSXMemberExpression") return jsxName(node.property);
17+
return null;
18+
}
19+
20+
function literalAttr(opening, attrName) {
21+
for (const attr of opening.attributes) {
22+
if (attr.type !== "JSXAttribute" || attr.name.name !== attrName) continue;
23+
if (!attr.value) return null;
24+
if (attr.value.type === "Literal") return attr.value.value;
25+
if (attr.value.type === "JSXExpressionContainer" && attr.value.expression.type === "Literal") {
26+
return attr.value.expression.value;
27+
}
28+
return null;
29+
}
30+
return null;
31+
}
32+
33+
const rule = {
34+
meta: {
35+
type: "problem",
36+
docs: {
37+
description:
38+
"Components under apps/www/src/components must not render a section lead (StatementBlock, h1, h2); the page owns those.",
39+
},
40+
schema: [],
41+
},
42+
create(context) {
43+
const filename = (context.physicalFilename ?? context.filename ?? "").replaceAll("\\", "/");
44+
if (!filename.includes(COMPONENTS_DIR)) return {};
45+
if (ALLOWED_DIRS.some((dir) => filename.includes(dir))) return {};
46+
47+
return {
48+
JSXOpeningElement(node) {
49+
const name = jsxName(node.name);
50+
if (!name) return;
51+
52+
if (SECTION_LEAD_COMPONENTS.has(name)) {
53+
context.report({
54+
node,
55+
message: `<${name}> is a section lead — render it in the page beside this component, not inside it.`,
56+
});
57+
return;
58+
}
59+
60+
const as = literalAttr(node, "as");
61+
if (typeof as === "string" && SECTION_HEADING_LEVELS.has(as)) {
62+
context.report({
63+
node,
64+
message: `<${name} as="${as}"> is a page/section heading — render it in the page beside this component. Use h3+ for headings that title an item inside the component.`,
65+
});
66+
}
67+
},
68+
};
69+
},
70+
};
71+
72+
export default {
73+
meta: { name: "codeday" },
74+
rules: { "no-section-lead-in-component": rule },
75+
};

‎.oxlintrc.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
"maxWarnings": 10
77
},
88
"plugins": ["typescript", "unicorn", "oxc"],
9+
"jsPlugins": ["./.oxlint/no-section-lead-in-component.mjs"],
910
"categories": {
1011
"correctness": "error"
1112
},
1213
"rules": {
14+
"codeday/no-section-lead-in-component": "error",
1315
"no-redundant-type-constituents": "off",
1416
"restrict-template-expressions": "off",
1517
"no-for-in-array": "off",

‎.zed/tasks.json‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Zed tasks for this monorepo. Each per-app task builds that app's
2+
// workspace-package dependencies (topo, topocons, utils, i18n) via
3+
// turbo's `^build` before starting the dev server (see turbo.json).
4+
[
5+
{
6+
"label": "Run: www",
7+
"command": "pnpm",
8+
"args": ["run", "dev:www"],
9+
"cwd": "$ZED_WORKTREE_ROOT",
10+
"use_new_terminal": true,
11+
"allow_concurrent_runs": false,
12+
"reveal": "always"
13+
},
14+
{
15+
"label": "Run: topo-gallery",
16+
"command": "pnpm",
17+
"args": ["run", "dev:topo-gallery"],
18+
"cwd": "$ZED_WORKTREE_ROOT",
19+
"use_new_terminal": true,
20+
"allow_concurrent_runs": false,
21+
"reveal": "always"
22+
},
23+
{
24+
"label": "Run: all apps",
25+
"command": "pnpm",
26+
"args": ["run", "dev"],
27+
"cwd": "$ZED_WORKTREE_ROOT",
28+
"use_new_terminal": true,
29+
"allow_concurrent_runs": false,
30+
"reveal": "always"
31+
}
32+
]

‎AGENTS.md‎

Lines changed: 144 additions & 0 deletions
Large diffs are not rendered by default.

‎README.md‎

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ Monorepo for CodeDay's web applications and shared packages.
44

55
## Structure
66

7-
| Path | Description |
8-
|---|---|
9-
| `apps/www` | Main CodeDay website (Next.js Pages Router) |
10-
| `packages/topo` | Shared design system (Chakra UI components, theme, region detection) |
11-
| `packages/i18n` | Shared internationalization (Paraglide JS messages + runtime) |
12-
| `packages/utils` | Shared utilities (GraphQL fetch, debug, etc.) |
13-
| `packages/topocons` | Icon library |
14-
| `packages/tsconfig` | Shared TypeScript configuration |
7+
| Path | Description |
8+
| ------------------- | -------------------------------------------------------------------- |
9+
| `apps/www` | Main CodeDay website (Next.js Pages Router) |
10+
| `packages/topo` | Shared design system (Chakra UI components, theme, region detection) |
11+
| `packages/i18n` | Shared internationalization (Paraglide JS messages + runtime) |
12+
| `packages/utils` | Shared utilities (GraphQL fetch, debug, etc.) |
13+
| `packages/topocons` | Icon library |
14+
| `packages/tsconfig` | Shared TypeScript configuration |
1515

1616
## Getting started
1717

@@ -25,10 +25,10 @@ pnpm run build
2525
The monorepo has two independent localization layers. Both are provided by
2626
shared packages so any app in the monorepo can use them.
2727

28-
| Layer | Purpose | Provided by | Example values |
29-
|---|---|---|---|
30-
| **Locale** (language) | UI string translations | `packages/i18n` | `en`, `es` |
31-
| **Region** | Domain-specific data (phone numbers, emails, legal) | `packages/topo` (Region) | `us`, `eu`, `uk`, `ca`, `in` |
28+
| Layer | Purpose | Provided by | Example values |
29+
| --------------------- | --------------------------------------------------- | ------------------------ | ---------------------------- |
30+
| **Locale** (language) | UI string translations | `packages/i18n` | `en`, `es` |
31+
| **Region** | Domain-specific data (phone numbers, emails, legal) | `packages/topo` (Region) | `us`, `eu`, `uk`, `ca`, `in` |
3232

3333
---
3434

@@ -93,11 +93,11 @@ export const getStaticProps = withLocaleStaticProps(async (ctx) => {
9393

9494
#### i18n package exports
9595

96-
| Import path | Contents |
97-
|---|---|
98-
| `@codeday/i18n/messages` | Type-safe message functions (`m.key()`) |
99-
| `@codeday/i18n/runtime` | `getLocale()`, `setLocale()`, `overwriteGetLocale()`, `baseLocale`, `locales`, `Locale` type |
100-
| `@codeday/i18n/next-pages` | `getLocaleFromContext()`, `withLocaleStaticProps()`, `withLocaleServerSideProps()` |
96+
| Import path | Contents |
97+
| -------------------------- | -------------------------------------------------------------------------------------------- |
98+
| `@codeday/i18n/messages` | Type-safe message functions (`m.key()`) |
99+
| `@codeday/i18n/runtime` | `getLocale()`, `setLocale()`, `overwriteGetLocale()`, `baseLocale`, `locales`, `Locale` type |
100+
| `@codeday/i18n/next-pages` | `getLocaleFromContext()`, `withLocaleStaticProps()`, `withLocaleServerSideProps()` |
101101

102102
---
103103

@@ -109,15 +109,15 @@ but can still view the site in English.
109109

110110
`@codeday/topo/Region` ships a built-in `TLD_REGION_MAP`:
111111

112-
| TLD | Region | | TLD | Region |
113-
|---|---|---|---|---|
114-
| `.org` | `us` | | `.ee` | `eu` |
115-
| `.us` | `us` | | `.se` | `eu` |
116-
| `.ca` | `ca` | | `.it` | `eu` |
117-
| `.co.uk` | `uk` | | `.fr` | `eu` |
118-
| `.in` | `in` | | `.es` | `eu` |
119-
| | | | `.ch` | `eu` |
120-
| | | | `.be` | `eu` |
112+
| TLD | Region | | TLD | Region |
113+
| -------- | ------ | --- | ----- | ------ |
114+
| `.org` | `us` | | `.ee` | `eu` |
115+
| `.us` | `us` | | `.se` | `eu` |
116+
| `.ca` | `ca` | | `.it` | `eu` |
117+
| `.co.uk` | `uk` | | `.fr` | `eu` |
118+
| `.in` | `in` | | `.es` | `eu` |
119+
| | | | `.ch` | `eu` |
120+
| | | | `.be` | `eu` |
121121

122122
Apps can pass an optional `overrides` map to add new TLDs or override
123123
specific full domain names.
@@ -155,7 +155,7 @@ Pass an `overrides` map to `getRegionFromHostname`. Full-domain keys take
155155
priority, then override TLD keys, then the built-in `TLD_REGION_MAP`.
156156

157157
```ts
158-
const overrides = { "staging.codeday.org": "eu", "dev": "us" };
158+
const overrides = { "staging.codeday.org": "eu", dev: "us" };
159159
const region = getRegionFromHostname("staging.codeday.org", overrides); // "eu"
160160
```
161161

@@ -191,10 +191,10 @@ No other files need to change.
191191

192192
#### Region package exports
193193

194-
| Import path | Contents |
195-
|---|---|
194+
| Import path | Contents |
195+
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
196196
| `@codeday/topo/Region/config` | `getRegionFromHostname()`, `TLD_REGION_MAP`, `DEFAULT_REGION`, `REGION_HEADER`, `RegionMap` type — Edge-safe, no React |
197-
| `@codeday/topo/Region` | Everything from config + `RegionProvider`, `useRegion()`, `getRegionFromContext()` |
197+
| `@codeday/topo/Region` | Everything from config + `RegionProvider`, `useRegion()`, `getRegionFromContext()` |
198198

199199
---
200200

‎apps/topo-gallery/.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ test-results/
22
playwright-report/
33
blob-report/
44
playwright/.cache/
5+
dist/
6+
storybook-static/
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import type { StorybookConfig } from "@storybook/react-vite";
2+
3+
// One story per component (not one route per component group, the old
4+
// Next.js gallery's shape). `docs` autodocs off by default; Alert/Modal/
5+
// Header etc. carry non-obvious constraints better explained in each
6+
// story's own description than an auto-generated props table.
7+
const config: StorybookConfig = {
8+
stories: ["../src/stories/**/*.stories.@(ts|tsx)"],
9+
addons: ["@storybook/addon-a11y", "@storybook/addon-docs"],
10+
framework: {
11+
name: "@storybook/react-vite",
12+
options: {},
13+
},
14+
staticDirs: [],
15+
};
16+
17+
export default config;
Lines changed: 78 additions & 0 deletions

‎apps/topo-gallery/next-env.d.ts‎

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)