Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
},
"devDependencies": {
"@forgekit/typescript-config": "workspace:*",
"@tailwindcss/vite": "^4.3.3",
"@tanstack/router-cli": "^1.167.19",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.3",
"jsdom": "^29.1.1",
"tailwindcss": "^4.3.3",
"vite": "^8.1.5"
}
}
3 changes: 2 additions & 1 deletion apps/web/src/__tests__/home.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import { describe, expect, it } from "vitest";
import { HomePage } from "../components/home-page";

describe("HomePage", () => {
it("renders the placeholder and UI package version", () => {
it("renders the placeholder, UI action, and package version", () => {
render(<HomePage />);

expect(screen.getByText("ForgeKit web is running.")).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Get started" })).toBeInTheDocument();
expect(screen.getByText(`UI package version: ${UI_VERSION}`)).toBeInTheDocument();
});
});
5 changes: 3 additions & 2 deletions apps/web/src/components/home-page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Defines the placeholder home page component.

import { UI_VERSION } from "@forgekit/ui";
import { Button, UI_VERSION } from "@forgekit/ui";

import type React from "react";

Expand All @@ -9,8 +9,9 @@ import type React from "react";
*/
export function HomePage(): React.JSX.Element {
return (
<section>
<section className="text-foreground">
<p>ForgeKit web is running.</p>
<Button type="button">Get started</Button>
<p>UI package version: {UI_VERSION}</p>
</section>
);
Expand Down
2 changes: 2 additions & 0 deletions apps/web/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { Outlet, createRootRoute } from "@tanstack/react-router";

import "../styles.css";

import type React from "react";

import { Document } from "../components/document";
Expand Down
6 changes: 6 additions & 0 deletions apps/web/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* App stylesheet: Tailwind base plus the ForgeKit theme, scanning the compiled UI package. */

@import "tailwindcss";
@import "@forgekit/ui/theme.css";

@source "../node_modules/@forgekit/ui/dist";
2 changes: 2 additions & 0 deletions apps/web/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Ambient Vite client types: import.meta.env, and asset and CSS module imports.
/// <reference types="vite/client" />
2 changes: 2 additions & 0 deletions apps/web/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Configures Vite and TanStack Start for the web app.

import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import tailwindcss from "@tailwindcss/vite";
import viteReact from "@vitejs/plugin-react";
import { defineConfig } from "vite";

Expand All @@ -11,6 +12,7 @@ const config = defineConfig({
plugins: [
// Start injects the framework entries that the React plugin then compiles.
tanstackStart(),
tailwindcss(),
viteReact()
]
});
Expand Down
4 changes: 2 additions & 2 deletions docs/ui/component-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ An app stylesheet must import Tailwind before the ForgeKit theme and source the
@import "tailwindcss";
@import "@forgekit/ui/theme.css";

@source "../../../packages/ui/dist";
@source "../node_modules/@forgekit/ui/dist";
```

The `@source` path is application-stylesheet-relative. The example fits a stylesheet under `apps/web/src`; use the equivalent path to the compiled `@forgekit/ui/dist` in another app. This wiring belongs to the later app integration chunk.
The `@source` path is application-stylesheet-relative. The example fits a stylesheet under `apps/web/src`; use the equivalent path to the compiled `@forgekit/ui/dist` in another app. This wiring belongs in each application stylesheet that consumes UI components.

`src/theme.css` is the source of truth for semantic tokens and radii. It defines light values on `:root` and dark values under `.dark`. A `.dark` ancestor flips the tokens for all descendants. The later `ThemeProvider` applies or removes that class on `<html>`.

Expand Down
14 changes: 12 additions & 2 deletions docs/web/app-skeleton.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

`apps/web` is a TanStack Start React app. It server-renders the placeholder home page and hydrates the same route tree on the client.

This is the booting frontend shell. Later feature chunks attach UI, a typed API client, theming, and auth to the same app boundary.
This is the booting frontend shell. Later feature chunks attach a typed API client, a `ThemeProvider`, and auth to the same app boundary.

## Routing and the document shell

Expand All @@ -24,6 +24,16 @@ tsr generate && tsc -p tsconfig.typecheck.json --noEmit

A clean checkout rebuilds the generated route tree during build or before type checking. No separate manual step is needed for those gates.

## Styling

`apps/web/vite.config.ts` compiles Tailwind v4 through the first-party `@tailwindcss/vite` plugin. `apps/web/src/styles.css` imports `tailwindcss` first, then `@forgekit/ui/theme.css`, so the application receives Tailwind utilities and the ForgeKit semantic theme in one global stylesheet. The stylesheet enters the app through a side-effect import in `apps/web/src/routes/__root.tsx`; TanStack Start injects it during server rendering and hydration, so every route receives it.

The stylesheet includes `@source "../node_modules/@forgekit/ui/dist"`. Tailwind does not scan `node_modules` by default, so this points at pnpm's symlinked compiled UI package and generates the utility classes used inside UI components.

The `.dark` class flips the semantic theme tokens for its descendants. A later chunk adds the `ThemeProvider` that toggles that class on the document root.

The UI package must be built before the app can import it and before `@source` can scan its component output, so every task that consumes UI depends on Turborepo's `^build`, including `dev`. `turbo dev` therefore builds UI once before starting the watchers, then runs the UI package's `tsc -p tsconfig.json --watch --preserveWatchOutput` script so its `dist` stays current while the web development server runs.

## Gates for a Vite app

`apps/web/package.json` defines the web workspace gates:
Expand All @@ -47,7 +57,7 @@ A clean checkout rebuilds the generated route tree during build or before type c

## Dependency edge

`apps/web/src/components/home-page.tsx` imports `UI_VERSION` from `@forgekit/ui` and renders it in the placeholder. The `@forgekit/web` package declares `@forgekit/ui` as a workspace dependency, and `@forgekit/dependency-flow` allows that as the only internal runtime edge from web. Because the import is compiled into the app, Turborepo's `^build` dependency ordering has a real package edge to follow.
`apps/web/src/components/home-page.tsx` imports `Button` and `UI_VERSION` from `@forgekit/ui` and renders them in the placeholder. The `@forgekit/web` package declares `@forgekit/ui` as a workspace dependency, and `@forgekit/dependency-flow` allows that as the only internal runtime edge from web. Because the import is compiled into the app, Turborepo's `^build` dependency ordering has a real package edge to follow.

## Running it

Expand Down
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"sideEffects": ["./src/theme.css"],
"scripts": {
"build": "tsc -p tsconfig.json",
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput",
"lint": "eslint . --max-warnings 0",
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
"test": "vitest run"
Expand Down
Loading