Skip to main content

build-app-page

Construct a new app page from scratch using this repo's component system. Use when the user says "build a new page for X", "create a settings page", "add a dashboard for Y", "scaffold an app screen", or otherwise wants a Next.js page assembled from the project's elements/components/patterns. Produces a route under pages/, picks the right Page shell + chrome + layout, wires up modals if needed, and (if it's a gallery showcase) registers it in common/constants.ts.

来源信息

仓库
internet-development/nextjs-css-agent-components
最近来源活动
2026年4月27日 05:29
检测到的 SKILL.md 语言
英语
星标
217
分支
24

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
build-app-page
description
Construct a new app page from scratch using this repo's component system. Use when the user says "build a new page for X", "create a settings page", "add a dashboard for Y", "scaffold an app screen", or otherwise wants a Next.js page assembled from the project's elements/components/patterns. Produces a route under pages/, picks the right Page shell + chrome + layout, wires up modals if needed, and (if it's a gallery showcase) registers it in common/constants.ts.
# Build an app page This skill walks an empty `.tsx` file to a working app page that uses this repo's three-tier system correctly. The end state: a page that boots in `npm run dev`, renders with the right chrome and layout, has the right SEO metadata, and follows the import-tier rules from `AGENTS.md`. ## When to use - "Build a settings page for X" - "Create a new dashboard for Y" - "Add a documents page for Z" - "Scaffold a new authenticated app screen" - "Make a marketing landing page using our components" - Any time the user wants a new route under `pages/` that uses the design system ## When NOT to use - The user just wants to modify an existing page (use direct edits). - The user wants a non-page React component (use the component conventions in `AGENTS.md` instead). - The user wants App Router (`app/`) page work — this repo's routes live under Pages Router (`pages/`). Stop and ask before introducing App Router. ## Pre-flight: pin down what you're building Before writing anything, ask yourself (or the user) four questions: 1. **What's the page's purpose?** Marketing/landing, authenticated app screen, document viewer, dashboard, form, or gallery showcase? Each has a canonical layout pattern below. 2. **Does it need a session/API key?** If yes, use `KeyHeader` and the `getServerSideProps` → `Server.setup(context)` pattern (see "Authenticated app pages" below). If no, plain `Navigation` + `getServerSideProps` returning `{ props: {} }` is enough. 3. **Does it open modals?** If yes, you must render `<GlobalModalManager />` and import `useModals` from `@runtime/modals/ModalContext`. 4. **Is it a gallery showcase?** If yes, you'll register it in `common/constants.ts` after writing. ## Pick the page shape Match the page to one of these canonical shapes. Each is taken straight from a working file in `pages/examples/`. ### Shape A — Marketing / showcase page (Navigation + content + Footer) Use when: landing pages, "show off this component" pages, content pages. Reference: `pages/examples/components/application-site.tsx`. ```tsx import * as React from 'react'; import Footer from '@components/Footer'; import GlobalModalManager from '@runtime/modals/GlobalModalManager'; import Navigation from '@patterns/chrome/Navigation'; import Page from '@patterns/chrome/Page'; function ExampleMarketingPage(props) { return ( <Page title="wireframes.internet.dev ➝ components ➝ <something>" description="A lightweight website template to test our design system. You can view this template on GitHub and see how we write websites." url="https://wireframes.internet.dev/examples/components/<slug>" > <Navigation /> {/* page body — Demo*, sections, charts, etc. */} <Footer /> <GlobalModalManager /> </Page> ); } export async function getServerSideProps(context) { return { props: {} }; } export default ExampleMarketingPage; ``` ### Shape B — Form page (Navigation + GridLayout + ThinAppLayout) Use when: a single-purpose form, settings pane, sign-up flow. Reference: `pages/examples/components/forms.tsx`. ```tsx import * as React from 'react'; import Button from '@components/Button'; import GlobalModalManager from '@runtime/modals/GlobalModalManager'; import GridLayout from '@elements/layouts/GridLayout'; import Input from '@elements/controls/Input'; import Navigation from '@patterns/chrome/Navigation'; import Page from '@patterns/chrome/Page'; import ThinAppLayout from '@elements/layouts/ThinAppLayout'; import { FormHeading, FormParagraph, InputLabel } from '@elements/type/forms'; function ExampleFormPage(props) { return ( <Page title="wireframes.internet.dev ➝ <area> ➝ <name>" description="..." url="https://wireframes.internet.dev/examples/<area>/<slug>" > <Navigation /> <GridLayout> <ThinAppLayout style={{ background: `var(--theme-background)`, borderTop: `1px solid var(--theme-border)` }}> <FormHeading>...</FormHeading> <FormParagraph>...</FormParagraph> <InputLabel style={{ marginTop: 24 }}>Field</InputLabel> <Input style={{ marginTop: 8 }} /> <Button style={{ marginTop: 48, width: '100%' }}>Submit</Button> </ThinAppLayout> </GridLayout> <GlobalModalManager /> </Page> ); } export async function getServerSideProps(context) { return { props: {} }; } export default ExampleFormPage; ``` ### Shape C — Dashboard (Navigation + DashboardWithSidebarLayout) Use when: an app dashboard with a left sidebar of nav and a main canvas. Reference: `pages/examples/components/dashboard.tsx`. ```tsx import * as React from 'react'; import DashboardWithSidebarLayout from '@elements/layouts/DashboardWithSidebarLayout'; import GlobalModalManager from '@runtime/modals/GlobalModalManager'; import Navigation from '@patterns/chrome/Navigation'; import Page from '@patterns/chrome/Page'; function ExampleDashboardPage(props) { const sidebarElement = <div>{/* nav items */}</div>; return ( <Page title="..." description="..." url="..."> <Navigation /> <DashboardWithSidebarLayout sidebar={sidebarElement}> {/* main canvas */} </DashboardWithSidebarLayout> <GlobalModalManager /> </Page> ); } export async function getServerSideProps(context) { return { props: {} }; } export default ExampleDashboardPage; ``` ### Shape D — Authenticated app page (KeyHeader + ThinAppLayout, with session key) Use when: the page needs the user's API key / session to function (settings, document editors, anything that talks to `@common/queries`). Reference: `pages/examples/empty/application-template-page.tsx`. ```tsx import * as React from 'react'; import * as Server from '@common/server'; import * as Utilities from '@common/utilities'; import Cookies from '@modules/cookies'; import GlobalModalManager from '@runtime/modals/GlobalModalManager'; import KeyHeader from '@patterns/chrome/KeyHeader'; import Page from '@patterns/chrome/Page'; import ThinAppLayout from '@elements/layouts/ThinAppLayout'; import ThinAppLayoutHeader from '@elements/layouts/ThinAppLayoutHeader'; function ExampleAppPage(props) { const [key, setKey] = React.useState<string>(props.sessionKey); return ( <Page title="..." description="..." url="..."> <KeyHeader onInputChange={setKey} value={key} viewer={props.viewer} /> <ThinAppLayout> <ThinAppLayoutHeader token={key} onSignOut={() => { const confirm = window.confirm('Are you sure you want to sign out?'); if (!confirm) return; setKey(''); Cookies.remove('sitekey'); window.location.reload(); }} /> {/* page body */} </ThinAppLayout> <GlobalModalManager /> </Page> ); } export async function getServerSideProps(context) { const { sessionKey, viewer } = await Server.setup(context); return { props: { sessionKey, viewer } }; } export default ExampleAppPage; ``` ### Shape E — Three-column document workspace (sidebar + details list + editor canvas) Use when: an app where a sidebar drives a list, the list drives a detail view (e.g. statement-of-work editor, invoice editor). Reference: `pages/examples/features/statement-of-work/index.tsx`. ```tsx import KeyHeader from '@patterns/chrome/KeyHeader'; import ThreeColumnAppLayout from '@elements/layouts/ThreeColumnAppLayout'; // ... <ThreeColumnAppLayout sidebar={sidebar} details={details}> {/* main editor */} </ThreeColumnAppLayout> ``` ## Step-by-step procedure ### Step 1 — pick the file path Routes live under `pages/`. Match the existing groupings: - `pages/examples/components/<slug>.tsx` — UI showcase (marketing, components, layouts) - `pages/examples/empty/<slug>.tsx` — blank starter templates - `pages/examples/features/<slug>.tsx` — feature demos with backend (auth, files, documents) - `pages/examples/system/<slug>.tsx` — design-system reference (typography, colors) - `pages/examples/animations/<slug>.tsx` — motion/animation demos - `pages/examples/fonts/<slug>.tsx` — font specimens For dynamic routes use `[id].tsx`. For new top-level areas, ask the user before creating. ### Step 2 — drop in the right shape Copy the matching shape from above (A–E). Replace the placeholder title/description/url with real values. The `url` should be the absolute URL on `wireframes.internet.dev` matching the file path. ### Step 3 — apply the import-tier rules From `AGENTS.md`: - Import atoms from `@elements/<bucket>/Foo` (icons, type, controls, marks, layouts, sections, scroll, charts, visuals, motion, diagrams, shells) - Import molecules from `@components/Foo` (Button, Checkbox, Select, Table, Footer, FormUpload, MonospacePreview, BlockFade, FadeManager, CheckmarkItem, FormChangePassword, FormSettingsPrivacy) - Import patterns from `@patterns/<bucket>/Foo` (chrome, modals, demos) - Import runtime from `@runtime/<bucket>/Foo` (modals, detectors, testing) - Never use `../../` across top-level dirs. Use `./Foo` only for siblings in the same folder. - Group imports: styles → React → utilities (`@common`, `@root`) → in-repo components (lowest tier first) → typography from `@elements/type`. ### Step 4 — choose layouts deliberately Layouts live in `@elements/layouts/`: | Layout | Width | Use for | |---|---|---| | `AppLayout` | 768px | Standard app body with side borders | | `ThinAppLayout` | 512px | Forms, document editors, narrow flows | | `WideAppLayout` | wider than 768 | Marketing canvas with breathing room | | `GridLayout` | full width | Wireframe-grid background; usually wraps another layout | | `Content` | constrained | Documentation/text content | | `TwoColumnLayout` / `TwoColumnLayoutFull` / `TwoColumnLayoutSidebar` | full width | Asymmetric two-column splits | | `ThreeColumnAppLayout` | full width | Sidebar + details + canvas (Shape E) | | `DashboardWithSidebarLayout` | full width | Dashboards (Shape C) | | `IsometricGridLayout` | full width | Decorative isometric grid | | `CardHandLayout` | full width | Fanned-card display | | `InvoiceLayout` | document-shaped | Invoice/SOW print layout | All full-height layouts use `min-height: calc(100dvh - 48px)` (the 48 accounts for the Navigation row). If your page has no `<Navigation />`, override with `style={{ minHeight: '100dvh' }}` on the layout. ### Step 5 — sections (for vertical rhythm) If your page has multiple stacked "screens" of content (landing-page hero, features, CTA, etc.), wrap each in: - `@elements/sections/SectionFullHeight` — fills the viewport - `@elements/sections/SectionHalfHeight` — half-viewport - `@elements/sections/SectionHorizontalStack` — horizontal panels ### Step 6 — wire modals (only if needed) If the page opens any modal (auth flow, error popup, color picker, navigation menu, etc.): ```tsx import { useModals } from '@runtime/modals/ModalContext'; import ModalError from '@patterns/modals/ModalError'; const modals = useModals(); modals.open(ModalError, { message: '...' }); ``` You **must** render `<GlobalModalManager />` somewhere in the page tree (typically just before `</Page>`). Without it, modals open in state but never render. Already included in shapes A–E above. The modal context is provided globally by `<Providers>` in `pages/_app.tsx` — you don't wrap the page yourself. ### Step 7 — typography - Marketing/large copy: `H1, H2, H3, H4, H5, Lead, SubLead, P` from `@elements/type` (modular `rem` scale, shrinks on mobile). - Form labels and form copy: `FormHeading, FormSubHeading, FormParagraph, InputLabel` from `@elements/type/forms`. - UI chrome (table cells, button labels, tooltips): `Title, Text, SubTitle, SubText, UnitLabel` from `@elements/type` (fixed `px` scale, doesn't shrink). Don't use raw `<h1>`/`<p>` tags — they get the global reset (zero margin, no scale). ### Step 8 — spacing Use inline `style={{ marginTop: 16 }}` for one-off spacing. Stick to multiples of 4 (`4, 8, 12, 16, 24, 32, 48, 64`). Don't add new CSS rules in the page file — pages are composition, not styling. ### Step 9 — `getServerSideProps` Every page in this repo exports `getServerSideProps`, even when no data is fetched. The empty form is `{ props: {} }`. Match the convention. For authenticated pages, use: ```tsx export async function getServerSideProps(context) { const { sessionKey, viewer } = await Server.setup(context); return { props: { sessionKey, viewer } }; } ``` ### Step 10 — register in `common/constants.ts` (if it's a gallery page) If the page belongs in the example gallery on `/examples`, add an entry to the matching `TEMPLATE_EXAMPLES_*` array in `common/constants.ts`: - `TEMPLATE_EXAMPLES_ANIMATIONS` — for `pages/examples/animations/*` - `TEMPLATE_EXAMPLES_COMPONENTS` — for `pages/examples/components/*` - `TEMPLATE_EXAMPLES_EMPTY` — for `pages/examples/empty/*` - `TEMPLATE_EXAMPLES_FEATURES` — for `pages/examples/features/*` - `TEMPLATE_EXAMPLES_SYSTEM` — for `pages/examples/system/*` Entry shape: ```ts { name: 'Components ➝ navigation, <thing>', href: '/examples/components/<slug>', label: '<short label>', // optional: isWIP: true, internal: true } ```
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看