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
6 changes: 3 additions & 3 deletions apps/site/e2e/auth-docs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ test.describe("Auth and docs", () => {
await page.goto("/docs");

await expect(
page.getByRole("heading", { name: "Guidance for creator teams" }),
page.getByRole("heading", { name: "Getting started" }),
).toBeVisible();
await expect(
page.getByRole("heading", { name: "Authoring" }),
Expand All @@ -49,7 +49,7 @@ test.describe("Auth and docs", () => {
page.getByRole("heading", { name: "Operations" }),
).toBeVisible();
await expect(
page.getByRole("link", { name: "Open product docs" }),
).toHaveAttribute("href", "/docs");
page.getByRole("heading", { name: "Reference", exact: true }),
).toBeVisible();
});
});
2 changes: 1 addition & 1 deletion apps/site/e2e/home.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test.describe("Graspful site", () => {
await page.goto("/");

await expect(
page.getByRole("link", { name: /start building free/i }).first(),
page.getByRole("link", { name: /create free account/i }).first(),
).toHaveAttribute("href", /sign-up/);
});

Expand Down
111 changes: 85 additions & 26 deletions apps/site/src/app/(marketing)/docs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,91 @@
import Link from "next/link";
import { PageShell } from "@/components/site/page-shell";

const sections = [
{
title: "Authoring",
items: [
"Define course structure with concepts, sections, and dependencies.",
"Review generated content before it reaches learners.",
"Publish changes without rebuilding your own delivery platform.",
],
},
{
title: "Operations",
items: [
"Manage brands, API keys, and learner billing from the creator app.",
"Use one platform runtime for learner delivery and revenue operations.",
"Keep the flagship site separate from the white-label learner surfaces.",
],
},
];

const docLinks = [
{ title: "CLI Reference", href: "https://graspful.ai/docs/cli", description: "Install, authenticate, and run course commands from your terminal." },
{ title: "Course Schema", href: "https://graspful.ai/docs/course-schema", description: "YAML structure for courses, concepts, knowledge points, and problems." },
{ title: "Brand Schema", href: "https://graspful.ai/docs/brand-schema", description: "Configure your academy theme, domain, and landing page." },
{ title: "Glossary", href: "https://graspful.ai/docs/glossary", description: "Key terms: concepts, knowledge points, mastery, diagnostics, and more." },
];

export default function DocsPage() {
return (
<PageShell
eyebrow="Documentation"
title="Guidance for creator teams"
intro="Use Graspful with structured course definitions, source material, and AI-assisted authoring workflows."
>
<div>
<h2 className="section-heading">Authoring</h2>
<ul className="plain-list">
<li>Define course structure with concepts, sections, and dependencies.</li>
<li>Review generated content before it reaches learners.</li>
<li>Publish changes without rebuilding your own delivery platform.</li>
</ul>
</div>
<div>
<h2 className="section-heading">Operations</h2>
<ul className="plain-list">
<li>Manage brands, API keys, and learner billing from the creator app.</li>
<li>Use one platform runtime for learner delivery and revenue operations.</li>
<li>Keep the flagship site separate from the white-label learner surfaces.</li>
</ul>
<Link href="/docs" className="button">
Open product docs
</Link>
</div>
</PageShell>
<main id="main-content" className="pt-24">
<section className="py-16 bg-muted/50">
<div className="mx-auto max-w-6xl px-6">
<p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
Documentation
</p>
<h1 className="text-4xl font-bold tracking-tight text-foreground mb-4">
Getting started
</h1>
<p className="text-lg text-muted-foreground max-w-2xl">
Everything you need to build and publish adaptive courses with
Graspful.
</p>
</div>
</section>
<section className="py-16">
<div className="mx-auto max-w-6xl px-6">
<div className="grid gap-5 sm:grid-cols-2 mb-12">
{sections.map((section) => (
<div
key={section.title}
className="rounded-2xl border border-border/50 bg-card p-10 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-lg"
>
<h2 className="text-lg font-semibold text-foreground mb-4">
{section.title}
</h2>
<ul className="space-y-2 text-muted-foreground text-sm leading-relaxed list-none p-0 m-0">
{section.items.map((item) => (
<li key={item} className="flex gap-2">
<span className="text-primary shrink-0">&#10003;</span>
{item}
</li>
))}
</ul>
</div>
))}
</div>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-6">
Reference
</h2>
<div className="grid gap-5 sm:grid-cols-2">
{docLinks.map((doc) => (
<Link
key={doc.href}
href={doc.href}
className="rounded-2xl border border-border/50 bg-card p-8 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-lg no-underline group"
>
<h3 className="text-base font-semibold text-foreground mb-1 group-hover:text-primary transition-colors">
{doc.title} &rarr;
</h3>
<p className="text-sm text-muted-foreground leading-relaxed">
{doc.description}
</p>
</Link>
))}
</div>
</div>
</section>
</main>
);
}
98 changes: 64 additions & 34 deletions apps/site/src/app/(marketing)/how-graspful-works/page.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,69 @@
import { PageShell } from "@/components/site/page-shell";
const steps = [
{
number: "1",
title: "Find out what they already know",
description:
"Every course starts with a diagnostic. The platform figures out what the learner can prove they understand and skips the rest. No one sits through material they've already mastered.",
},
{
number: "2",
title: "Teach what actually matters next",
description:
"The sequence changes based on gaps. If a learner is weak on prerequisites, the platform handles that first. If they're strong, it moves them forward. The path is different for everyone.",
},
{
number: "3",
title: "Prove mastery before moving on",
description:
"Progress is gated on evidence. Learners solve problems that test real understanding. Clicking through slides doesn't count.",
},
{
number: "4",
title: "Keep what you learned",
description:
"Spaced review brings knowledge back at the right time. It's built into the product, not a feature you have to turn on. Students retain what they learned instead of losing it.",
},
];

export default function HowItWorksPage() {
return (
<PageShell
eyebrow="How it works"
title="How Graspful works"
intro="Diagnosis, mastery, and spaced review. Not a video player with a progress bar."
>
<div>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-4">1. Find out what they already know</h2>
<p className="text-muted-foreground">
Every course starts with a diagnostic. The platform figures out what
the learner can prove they understand and skips the rest. No one sits
through material they&apos;ve already mastered.
</p>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-4">2. Teach what actually matters next</h2>
<p className="text-muted-foreground">
The sequence changes based on gaps. If a learner is weak on
prerequisites, the platform handles that first. If they&apos;re strong, it
moves them forward. The path is different for everyone.
</p>
</div>
<div>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-4">3. Prove mastery before moving on</h2>
<p className="text-muted-foreground">
Progress is gated on evidence. Learners solve problems that test real
understanding. Clicking through slides doesn&apos;t count.
</p>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-4">4. Keep what you learned</h2>
<p className="text-muted-foreground">
Spaced review brings knowledge back at the right time. It&apos;s built into
the product, not a feature you have to turn on. Students retain what
they learned instead of losing it.
</p>
</div>
</PageShell>
<main id="main-content" className="pt-24">
<section className="py-16 bg-muted/50">
<div className="mx-auto max-w-6xl px-6">
<p className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
How it works
</p>
<h1 className="text-4xl font-bold tracking-tight text-foreground mb-4">
How Graspful works
</h1>
<p className="text-lg text-muted-foreground max-w-2xl">
Diagnosis, mastery, and spaced review. Not a video player with a
progress bar.
</p>
</div>
</section>
<section className="py-16">
<div className="mx-auto max-w-6xl px-6">
<div className="grid gap-5 sm:grid-cols-2">
{steps.map((step) => (
<div
key={step.number}
className="group rounded-2xl border border-border/50 bg-card p-10 shadow-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-lg"
>
<p className="text-sm font-semibold text-primary mb-2">
Step {step.number}
</p>
<h2 className="text-lg font-semibold text-foreground mb-2">
{step.title}
</h2>
<p className="text-muted-foreground leading-relaxed">
{step.description}
</p>
</div>
))}
</div>
</div>
</section>
</main>
);
}
10 changes: 5 additions & 5 deletions apps/site/src/app/(marketing)/pricing/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function PricingPage() {
>
<div>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-4">What creators pay</h2>
<p className="text-muted-foreground">
<p className="text-muted-foreground mb-6">
No platform subscription. No setup fee. Graspful takes 30% of learner
revenue and runs the infrastructure. You keep the rest.
</p>
Expand All @@ -29,19 +29,19 @@ export default function PricingPage() {
</div>
<div>
<h2 className="text-2xl font-bold tracking-tight text-foreground mb-4">What learners pay</h2>
<p className="text-muted-foreground">
<p className="text-muted-foreground mb-6">
You set the price. Graspful handles checkout, access control, and
subscription management through Stripe.
</p>
<ul className="text-sm space-y-2 list-none p-0 mb-6">
<ul className="space-y-2 list-none p-0 mb-6">
{[
"Monthly and annual plans",
"Checkout and payouts handled by Stripe",
"Your own branded academy site",
"One platform for course, billing, and learner access",
].map((item) => (
<li key={item} className="flex gap-2">
<span className="text-primary">&#10003;</span> {item}
<li key={item} className="flex items-center gap-2 text-sm">
<span className="text-primary shrink-0">&#10003;</span> {item}
</li>
))}
</ul>
Expand Down
6 changes: 3 additions & 3 deletions apps/site/src/app/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion apps/site/src/components/auth/auth-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function AuthForm({ mode }: AuthFormProps) {
? `Sign in to ${brand.name}`
: isConfirmationPending
? "Check your email for a confirmation link."
: `Start building courses on ${brand.name}`;
: "Next step: run graspful register from your editor to connect the CLI.";
const submitText = isSignIn ? "Sign In" : "Create Account";
const switchText = isSignIn ? "Don't have an account?" : "Already have an account?";
const switchHref = isSignIn ? "/sign-up" : "/sign-in";
Expand Down
4 changes: 2 additions & 2 deletions apps/site/src/components/site/__tests__/home-page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ describe("HomePage", () => {
screen.getByRole("heading", { name: /what we do for you/i }),
).toBeVisible();
expect(
screen.getByRole("heading", { name: /how it works/i }),
screen.getByRole("heading", { name: /three commands/i }),
).toBeVisible();
});

it("renders hero calls to action", () => {
render(<HomePage />);

expect(
screen.getAllByRole("link", { name: /start building free/i }).length,
screen.getAllByRole("link", { name: /create free account/i }).length,
).toBeGreaterThanOrEqual(1);
});
});
6 changes: 3 additions & 3 deletions apps/site/src/components/site/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Link from "next/link";
import { useTheme } from "@/lib/theme";

const navigationItems = [
{ href: "/how-graspful-works", label: "Agents" },
{ href: "/how-graspful-works", label: "How It Works" },
{ href: "/pricing", label: "Pricing" },
{ href: "/docs", label: "Docs" },
];
Expand Down Expand Up @@ -78,9 +78,9 @@ export function SiteHeader() {
</Link>
<Link
href="/sign-up"
className="btn-gradient px-5 py-2 text-sm font-medium"
className="btn-gradient px-5 py-2.5 text-sm font-medium shadow-md"
>
Get Started
Create Free Account
</Link>
</div>
</div>
Expand Down
Loading
Loading