Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f0b43b8
Add design spec for the propel-docs Astro app
sriramveeraghanta Jul 14, 2026
f4fd2c1
Add implementation plan for the propel-docs Astro app
sriramveeraghanta Jul 15, 2026
10162ce
Scaffold apps/propel-docs Astro app
sriramveeraghanta Jul 15, 2026
aa038a0
Ignore Astro build cache (.astro) across the workspace
sriramveeraghanta Jul 15, 2026
12a489b
Wire Tailwind v4 + propel design tokens into propel-docs
sriramveeraghanta Jul 15, 2026
346767a
Add layouts, sidebar nav, and installation page to propel-docs
sriramveeraghanta Jul 15, 2026
1b953bd
Add props-table/demo plumbing and the Button doc page
sriramveeraghanta Jul 15, 2026
02a17a9
Resolve propel via built dist in docs check/build, not tsconfig sourc…
sriramveeraghanta Jul 15, 2026
837ab3b
Fix props-schema propel-root resolution for the production build
sriramveeraghanta Jul 15, 2026
2d2f54d
Add Input Field doc page
sriramveeraghanta Jul 15, 2026
e030d0b
Add Select doc page
sriramveeraghanta Jul 15, 2026
2078264
Add Dialog doc page
sriramveeraghanta Jul 15, 2026
7b1e188
Add Table doc page
sriramveeraghanta Jul 15, 2026
824d68c
Add Accordion doc page
sriramveeraghanta Jul 15, 2026
856e599
Fix formatting/lint issues across propel-docs
sriramveeraghanta Jul 15, 2026
70cb2bc
Restore @ts-check pragma to first line of astro.config.mjs
sriramveeraghanta Jul 15, 2026
efccbf1
Add PropsTable build-time warning and app README with deploy notes
sriramveeraghanta Jul 15, 2026
cda0789
Format docs/superpowers spec + plan to satisfy the oxfmt CI gate
sriramveeraghanta Jul 16, 2026
8749016
Address PR review: memoize props parsing, type CodeBlock lang
sriramveeraghanta Jul 16, 2026
ee27ea5
Build propel before the workspace check in CI
sriramveeraghanta Jul 16, 2026
3476567
Address PR review: dev-safe props cache + sidebar aria-current
sriramveeraghanta Jul 16, 2026
a0a7e1f
Gate props cache on NODE_ENV, not import.meta.env
sriramveeraghanta Jul 16, 2026
b3d1ee9
chore: remove docs
sriramveeraghanta Jul 16, 2026
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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ jobs:
restore-keys: |
vite-task-${{ runner.os }}-${{ runner.arch }}-

# apps/propel-docs type-checks its demos against @makeplane/propel's built
# dist (its published `exports`), and dist is gitignored — so pack propel
# before the workspace check, or those imports can't resolve (TS2307).
- run: vp run @makeplane/propel#build

- run: vp run -w check
# Storybook stories run as browser tests (Vitest + Playwright), so CI needs
# the Chromium binary + its system deps. `pnpm` isn't on PATH under
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ dist-ssr
# Storybook build output
storybook-static

# Astro build cache
.astro

# Test coverage
coverage

# Playwright MCP output
.playwright-mcp

docs/superpowers/*
55 changes: 55 additions & 0 deletions apps/propel-docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# @makeplane/propel-docs

The documentation site for `@makeplane/propel`'s components. Built with Astro 7,
React islands (via `@astrojs/react`), and MDX for the component pages, styled
with propel's own Tailwind v4 tokens (`@makeplane/propel/styles`).

## Commands

Run these from the repo root:

- `pnpm --filter @makeplane/propel-docs dev` — starts the dev server. In dev
mode, `astro.config.mjs` aliases `@makeplane/propel/components/*` and
`@makeplane/propel/styles` directly to propel's `src`, so editing a propel
component hot-reloads this site instantly — no propel build needed.
- `pnpm --filter @makeplane/propel-docs build` — production build. This first
runs `vp pack` on `@makeplane/propel` (to produce its `dist`), then runs
`astro build`, so the site resolves propel through its real, published
`dist` exports — the same way a consumer of the package would.
- `pnpm --filter @makeplane/propel-docs typecheck` — runs `astro check` (this
also packs propel first, for the same reason as `build`).
- `pnpm --filter @makeplane/propel-docs preview` — serves the built `dist`
output locally for a final check before deploying.

## IMPORTANT: the deploy seam

The production build resolves `@makeplane/propel` through its built `dist`,
and `packages/propel/dist` is gitignored — it is not committed. Any CI or
Cloudflare build **must build propel before the site**. Use this package's
`build` script (`pnpm --filter @makeplane/propel-docs build`, which packs
propel first) rather than invoking `astro build` directly. A bare
`astro build` on a fresh checkout will fail to resolve
`@makeplane/propel/components/*`, since no `dist` exists yet.

## Deployment placeholders

`astro.config.mjs`'s `site` and `wrangler.jsonc`'s `account_id` / `routes` are
intentional TODO placeholders, to be filled in once a real domain and
Cloudflare account are assigned. The sitemap integration (`@astrojs/sitemap`)
reads `site` to generate absolute URLs, so update `site` and rebuild once the
domain is set.

## Adding a component page

1. Create `src/demos/<name>/<variant>.tsx` — a small React demo that imports
only from `@makeplane/propel/components/<name>` and `lucide-react`, and
passes every required prop.
2. Create `src/pages/components/<name>.mdx` following the existing pages:
frontmatter with `layout: ~/layouts/ComponentLayout.astro` plus `title` and
`description`; import each demo twice (once as the live component with
`client:visible`, once with a `?raw` suffix for the source snippet);
render it inside `<ComponentExample>`, add an "Installation" snippet, and
render `<PropsTable parts={[{ source, component }]} />` for the props
table.
3. Add the page's entry (`slug`, `title`, `description`) to
`src/lib/components-registry.ts`.
42 changes: 42 additions & 0 deletions apps/propel-docs/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @ts-check

import { resolve } from "node:path";
import { fileURLToPath } from "node:url";

import mdx from "@astrojs/mdx";
import react from "@astrojs/react";
import sitemap from "@astrojs/sitemap";
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "astro/config";

const __dirname = fileURLToPath(new URL(".", import.meta.url));

// Dev-mode alias to propel's real source, so editing a component hot-reloads
// this docs site without needing `vp pack --watch` running in parallel.
// Production builds resolve `@makeplane/propel` through its normal workspace
// package + dist exports instead (no alias).
const isDev = process.argv.includes("dev");
const propelSrc = resolve(__dirname, "../../packages/propel/src");

export default defineConfig({
// TODO: replace with the real deployed domain once one is assigned.
site: "https://propel-docs.example.com",
integrations: [mdx(), react(), sitemap()],
vite: {
plugins: [tailwindcss()],
resolve: isDev
? {
alias: [
{
find: /^@makeplane\/propel\/components\/(.*)$/,
replacement: resolve(propelSrc, "components/$1/index.tsx"),
},
{
find: "@makeplane/propel/styles",
replacement: resolve(propelSrc, "styles/propel.css"),
},
],
}
: undefined,
},
});
33 changes: 33 additions & 0 deletions apps/propel-docs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@makeplane/propel-docs",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "astro dev",
"build": "vp run @makeplane/propel#build && astro build",
"preview": "astro preview",
"typecheck": "vp run @makeplane/propel#build && astro check"
},
"dependencies": {
"@astrojs/mdx": "^7.0.3",
"@astrojs/react": "^6.0.1",
"@astrojs/sitemap": "^3.7.3",
"@makeplane/propel": "workspace:*",
"@tailwindcss/vite": "catalog:",
"astro": "^7.0.9",
"lucide-react": "catalog:",
"react": "^19.2.7",
"react-dom": "^19.2.7",
"tailwindcss": "catalog:"
},
"devDependencies": {
"@astrojs/check": "^0.9.9",
"@types/node": "catalog:",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"react-docgen-typescript": "^2.4.0",
"typescript": "catalog:",
"wrangler": "^4.110.0"
}
}
4 changes: 4 additions & 0 deletions apps/propel-docs/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions apps/propel-docs/src/components/CodeBlock.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
import { Code } from "astro:components";
import type { CodeLanguage } from "astro";

type Props = {
code: string;
lang?: CodeLanguage;
};

const { code, lang = "tsx" } = Astro.props;
---

<Code code={code.trimEnd()} lang={lang} theme="github-dark" />
22 changes: 22 additions & 0 deletions apps/propel-docs/src/components/ComponentExample.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
import CodeBlock from "~/components/CodeBlock.astro";

type Props = {
code: string;
};

const { code } = Astro.props;
---

<div class="overflow-hidden rounded-lg border border-subtle">
<div class="flex items-center justify-center border-b border-subtle bg-surface-1 p-8">
<slot />
</div>
<details class="group">
<summary class="cursor-pointer list-none px-4 py-2 text-sm text-secondary select-none">
<span class="group-open:hidden">Show code</span>
<span class="hidden group-open:inline">Hide code</span>
</summary>
<CodeBlock code={code} />
</details>
</div>
70 changes: 70 additions & 0 deletions apps/propel-docs/src/components/PropsTable.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
import type { PropItemType } from "react-docgen-typescript";

import { getComponentDoc } from "~/lib/props-schema";

type Part = {
source: string;
component: string;
};

type Props = {
parts: Part[];
};

const { parts } = Astro.props;

// `shouldExtractLiteralValuesFromEnum` (props-schema.ts) puts a string-literal union's members in
// `type.value` (each `{ value: '"primary"' }`) while `type.name` stays the generic `"enum"` — join
// them back into the `"primary" | "secondary" | …` form so the table shows the real union, not the
// bare word "enum".
function formatType(type: PropItemType): string {
if (type.name === "enum" && Array.isArray(type.value)) {
return type.value.map((entry: { value: string }) => entry.value).join(" | ");
}
return type.name;
}
---

<div class="flex flex-col gap-8">
{
parts.map(({ source, component }) => {
const doc = getComponentDoc(source, component);
if (!doc || Object.keys(doc.props).length === 0) {
console.warn(
`[PropsTable] No component doc found for "${component}" at source "${source}" — the props table will be empty. Check the source path (relative to packages/propel/src) and the exported component name.`,
);
}
const props = doc ? Object.values(doc.props) : [];
return (
<div>
<h3 class="mb-3 font-mono text-sm font-medium text-primary">{component}</h3>
<div class="overflow-x-auto rounded-lg border border-subtle">
<table class="w-full border-collapse text-sm">
<thead>
<tr class="border-b border-subtle bg-surface-1 text-left">
<th class="px-4 py-2 font-medium text-secondary">Prop</th>
<th class="px-4 py-2 font-medium text-secondary">Type</th>
<th class="px-4 py-2 font-medium text-secondary">Required</th>
<th class="px-4 py-2 font-medium text-secondary">Description</th>
</tr>
</thead>
<tbody>
{props.map((prop) => (
<tr class="border-b border-subtle last:border-0">
<td class="px-4 py-2 font-mono text-primary">{prop.name}</td>
<td class="max-w-xs px-4 py-2 font-mono text-xs text-secondary">
{formatType(prop.type)}
</td>
<td class="px-4 py-2 text-secondary">{prop.required ? "Yes" : "No"}</td>
<td class="px-4 py-2 text-secondary">{prop.description}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
})
}
</div>
32 changes: 32 additions & 0 deletions apps/propel-docs/src/components/SidebarNav.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
import { COMPONENTS } from "~/lib/components-registry";

const currentPath = Astro.url.pathname.replace(/\/$/, "");
---

<nav class="w-56 shrink-0">
<p class="mb-3 text-xs font-medium tracking-wide text-tertiary uppercase">Components</p>
<ul class="flex flex-col gap-1">
{
COMPONENTS.map((entry) => {
const href = `/components/${entry.slug}`;
const isActive = currentPath === href;
return (
<li>
<a
href={href}
aria-current={isActive ? "page" : undefined}
class={`block rounded-md px-3 py-1.5 text-sm ${
isActive
? "bg-surface-2 text-primary"
: "text-secondary hover:bg-surface-1 hover:text-primary"
}`}
>
Comment thread
sriramveeraghanta marked this conversation as resolved.
{entry.title}
</a>
</li>
);
})
}
</ul>
</nav>
35 changes: 35 additions & 0 deletions apps/propel-docs/src/demos/accordion/basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
Accordion,
AccordionHeader,
AccordionItem,
AccordionPanel,
AccordionTrigger,
} from "@makeplane/propel/components/accordion";

const ITEMS = [
{
value: "what",
label: "What is Plane?",
body: "Plane is an open-source project management tool for tracking issues, sprints, and product roadmaps.",
},
{
value: "pricing",
label: "How does pricing work?",
body: "Plane is free to self-host. Managed plans add hosting, backups, and support.",
},
];

export default function BasicDemo() {
return (
<Accordion defaultValue={["what"]}>
{ITEMS.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionHeader>
<AccordionTrigger label={item.label} />
</AccordionHeader>
<AccordionPanel>{item.body}</AccordionPanel>
</AccordionItem>
))}
</Accordion>
);
}
5 changes: 5 additions & 0 deletions apps/propel-docs/src/demos/button/basic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Button } from "@makeplane/propel/components/button";

export default function BasicDemo() {
return <Button label="Button" prominence="primary" tone="neutral" magnitude="md" sizing="hug" />;
}
15 changes: 15 additions & 0 deletions apps/propel-docs/src/demos/button/with-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Button } from "@makeplane/propel/components/button";
import { Plus } from "lucide-react";

export default function WithIconDemo() {
return (
<Button
label="New"
prominence="primary"
tone="neutral"
magnitude="md"
sizing="hug"
startIcon={<Plus />}
/>
);
}
Loading