Skip to content
Merged
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: 1 addition & 1 deletion .claude/format-hook.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
file_path=$(jq -r '.tool_input.file_path')

# Check if file matches JS/TS extensions
if [[ "$file_path" =~ \.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$ ]]; then
if [[ "$file_path" =~ \.(ts|tsx|js|jsx|mjs|cjs|mts|cts|css|mdx)$ ]]; then
pnpm exec prettier --write "$file_path"
fi
8 changes: 5 additions & 3 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
"dependencies": {
"@funstack/router": "0.0.3-alpha.1",
"@funstack/static": "workspace:*",
"@shikijs/rehype": "^3.21.0",
"@types/node": "catalog:",
"react": "catalog:",
"react-dom": "catalog:"
"react-dom": "catalog:",
"shiki": "^3.21.0"
},
"devDependencies": {
"@mdx-js/rollup": "^3.1.0",
Expand All @@ -24,7 +26,7 @@
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "latest",
"rsc-html-stream": "^0.0.7",
"vite": "catalog:",
"typescript": "catalog:"
"typescript": "catalog:",
"vite": "catalog:"
}
}
26 changes: 23 additions & 3 deletions packages/docs/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
import { Router } from "@funstack/router";
import { route, type RouteDefinition } from "@funstack/router/server";
import { defer } from "@funstack/static/server";
import { Layout } from "./components/Layout/Layout";
import DeferApi from "./pages/api/Defer.mdx";
import FunstackStaticApi from "./pages/api/FunstackStatic.mdx";
import RSCConcept from "./pages/concepts/RSC.mdx";
import GettingStarted from "./pages/GettingStarted.mdx";
import { Home } from "./pages/Home";
import { defer } from "@funstack/static/server";

const routes: RouteDefinition[] = [
route({
path: "/",
component: <Home />,
component: (
<Layout variant="home">
<Home />
</Layout>
),
}),
route({
path: "/getting-started",
component: defer(GettingStarted),
component: <Layout>{defer(GettingStarted)}</Layout>,
}),
route({
path: "/api/funstack-static",
component: <Layout>{defer(FunstackStaticApi)}</Layout>,
}),
route({
path: "/api/defer",
component: <Layout>{defer(DeferApi)}</Layout>,
}),
route({
path: "/concepts/rsc",
component: <Layout>{defer(RSCConcept)}</Layout>,
}),
];

Expand Down
49 changes: 49 additions & 0 deletions packages/docs/src/components/CodeBlock/CodeBlock.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.codeBlock {
position: relative;
margin: var(--spacing-lg) 0;
border-radius: var(--radius-lg);
overflow: hidden;
}

.codeContent {
font-size: var(--text-sm);
line-height: 1.6;
}

/* Style Shiki's generated pre element */
.codeContent :global(pre) {
margin: 0;
padding: var(--spacing-lg);
overflow-x: auto;
border-radius: var(--radius-lg);
}

.codeContent :global(code) {
font-family: var(--font-mono);
}

/* Shiki code styling */
.codeContent :global(.shiki code) {
background: transparent;
}

/* Dark mode: override Shiki's default light colors */
@media (prefers-color-scheme: dark) {
.codeContent :global(.shiki) {
background-color: var(--shiki-dark-bg) !important;
}

.codeContent :global(.shiki span) {
color: var(--shiki-dark) !important;
}
}

/* Inline code */
.inlineCode {
font-family: var(--font-mono);
font-size: 0.9em;
padding: 0.15em 0.4em;
background-color: var(--color-bg-tertiary);
border-radius: var(--radius-sm);
color: var(--color-accent);
}
37 changes: 37 additions & 0 deletions packages/docs/src/components/CodeBlock/CodeBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { codeToHtml } from "shiki";
import styles from "./CodeBlock.module.css";

interface CodeBlockProps {
children: string;
language?: string;
}

export async function CodeBlock({
children,
language = "typescript",
}: CodeBlockProps) {
const html = await codeToHtml(children.trim(), {
lang: language,
themes: {
light: "github-light",
dark: "github-dark",
},
});

return (
<div className={styles.codeBlock}>
<div
className={styles.codeContent}
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
);
}

interface InlineCodeProps {
children: React.ReactNode;
}

export function InlineCode({ children }: InlineCodeProps) {
return <code className={styles.inlineCode}>{children}</code>;
}
142 changes: 142 additions & 0 deletions packages/docs/src/components/Header/Header.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
height: var(--header-height);
background-color: var(--color-bg);
border-bottom: 1px solid var(--color-border);
z-index: 100;
backdrop-filter: blur(8px);
background-color: rgba(255, 255, 255, 0.9);
}

@media (prefers-color-scheme: dark) {
.header {
background-color: rgba(15, 15, 26, 0.9);
}
}

.container {
max-width: var(--page-max-width);
margin: 0 auto;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 var(--spacing-xl);
}

.logo {
display: flex;
align-items: center;
gap: var(--spacing-sm);
font-weight: 700;
font-size: var(--text-lg);
color: var(--color-text);
text-decoration: none;
}

.logo:hover {
color: var(--color-text);
}

.logoIcon {
width: 32px;
height: 32px;
background: var(--gradient-accent);
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: 700;
font-size: var(--text-sm);
}

.logoText {
background: var(--gradient-accent);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}

.nav {
display: flex;
align-items: center;
gap: var(--spacing-lg);
}

.navLink {
font-size: var(--text-sm);
font-weight: 500;
color: var(--color-text-secondary);
text-decoration: none;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-md);
transition:
color var(--transition-fast),
background-color var(--transition-fast);
}

.navLink:hover {
color: var(--color-text);
background-color: var(--color-bg-tertiary);
}

.navLinkActive {
color: var(--color-accent);
}

.navLinkActive:hover {
color: var(--color-accent-dark);
}

.githubLink {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: var(--radius-md);
color: var(--color-text-secondary);
transition:
color var(--transition-fast),
background-color var(--transition-fast);
}

.githubLink:hover {
color: var(--color-text);
background-color: var(--color-bg-tertiary);
}

.githubLink svg {
width: 20px;
height: 20px;
}

/* Mobile menu button */
.menuButton {
display: none;
width: 40px;
height: 40px;
align-items: center;
justify-content: center;
border-radius: var(--radius-md);
color: var(--color-text-secondary);
}

.menuButton:hover {
background-color: var(--color-bg-tertiary);
color: var(--color-text);
}

@media (max-width: 768px) {
.nav {
display: none;
}

.menuButton {
display: flex;
}
}
56 changes: 56 additions & 0 deletions packages/docs/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import styles from "./Header.module.css";

export const Header: React.FC = () => {
return (
<header className={styles.header}>
<div className={styles.container}>
<a href="/" className={styles.logo}>
<span className={styles.logoIcon}>F</span>
<span className={styles.logoText}>FUNSTACK Static</span>
</a>

<nav className={styles.nav}>
<a href="/getting-started" className={styles.navLink}>
Docs
</a>
<a href="/api/funstack-static" className={styles.navLink}>
API
</a>
<a href="/concepts/rsc" className={styles.navLink}>
Concepts
</a>
<a
href="https://github.com/user/funstack-static"
target="_blank"
rel="noopener noreferrer"
className={styles.githubLink}
aria-label="GitHub repository"
>
<svg viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
</svg>
</a>
</nav>

<button
className={styles.menuButton}
aria-label="Open menu"
type="button"
>
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
>
<line x1="3" y1="6" x2="21" y2="6" />
<line x1="3" y1="12" x2="21" y2="12" />
<line x1="3" y1="18" x2="21" y2="18" />
</svg>
</button>
</div>
</header>
);
};
Loading