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
11 changes: 11 additions & 0 deletions apps/web/src/app/example/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { Metadata } from 'next';

export const metadata: Metadata = {
title: 'Live example · LearnKit AI',
description:
'See <LearningPath /> render a real AI learning path in your browser — no backend, no LLM, fully deterministic.',
};

export default function ExampleLayout({ children }: { children: React.ReactNode }) {
return children;
}
112 changes: 112 additions & 0 deletions apps/web/src/app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { Nav } from '@/components/layout/Nav';
import { Footer } from '@/components/layout/Footer';

export const metadata: Metadata = {
title: '404 — Page not found · LearnKit AI',
};

export default function NotFound() {
return (
<main
className="paper-grain"
style={{ background: 'var(--paper)', minHeight: '100vh', display: 'flex', flexDirection: 'column' }}
>
<Nav />
<div
style={{
flex: 1,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '80px 56px',
textAlign: 'center',
}}
>
<div
style={{
fontFamily: 'var(--mono)',
fontSize: 11,
color: 'var(--accent)',
textTransform: 'uppercase',
letterSpacing: '0.12em',
marginBottom: 20,
}}
>
404
</div>
<h1
className="serif"
style={{
fontSize: 56,
lineHeight: 1.05,
letterSpacing: '-0.03em',
fontWeight: 400,
margin: '0 0 18px',
}}
>
Page not found.
</h1>
<p
style={{
fontSize: 17,
color: 'var(--ink-soft)',
lineHeight: 1.55,
maxWidth: 440,
margin: '0 0 36px',
}}
>
The path you followed doesn&apos;t exist — but a learning path does. Try one of these instead.
</p>
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', justifyContent: 'center' }}>
<Link
href="/demo"
style={{
background: 'var(--ink)',
color: 'var(--paper)',
padding: '11px 22px',
borderRadius: 8,
fontSize: 14,
fontWeight: 500,
textDecoration: 'none',
}}
>
Build your path
</Link>
<Link
href="/docs"
style={{
background: 'transparent',
color: 'var(--ink)',
padding: '11px 22px',
borderRadius: 8,
fontSize: 14,
fontWeight: 500,
border: '1px solid var(--rule-strong)',
textDecoration: 'none',
}}
>
Read the docs
</Link>
<Link
href="/"
style={{
background: 'transparent',
color: 'var(--ink-soft)',
padding: '11px 22px',
borderRadius: 8,
fontSize: 14,
fontWeight: 450,
textDecoration: 'none',
}}
>
Home
</Link>
</div>
</div>
<Footer />
</main>
);
}
19 changes: 9 additions & 10 deletions apps/web/src/app/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ImageResponse } from 'next/og';

export const runtime = 'edge';
export const alt = 'LearnKit AI — The AI workbench for teams that ship';
export const alt = 'LearnKit AI — Open-source AI learning paths for every role';
export const size = { width: 1200, height: 630 };
export const contentType = 'image/png';

Expand Down Expand Up @@ -35,16 +35,15 @@ export default function OGImage() {
<div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
<div
style={{
fontSize: 84,
fontSize: 80,
lineHeight: 1.0,
letterSpacing: '-0.035em',
fontWeight: 400,
}}
>
Make your team
Personalized AI paths
<br />
good at AI by{' '}
<span style={{ fontStyle: 'italic', color: '#C8472A' }}>Friday</span>.
for <span style={{ fontStyle: 'italic', color: '#C8472A' }}>every role</span>.
</div>
<div
style={{
Expand All @@ -54,8 +53,8 @@ export default function OGImage() {
lineHeight: 1.35,
}}
>
The AI workbench for teams that ship. Learn Claude, Cursor, ChatGPT and 40+ tools by
building real things at work.
Open-source TypeScript engine for embedding role-aware AI learning paths in any product.
No API key. No backend. No paid tier.
</div>
</div>

Expand All @@ -70,11 +69,11 @@ export default function OGImage() {
>
<div>learnkit-ai.com</div>
<div style={{ display: 'flex', gap: 24 }}>
<span>Open source</span>
<span>·</span>
<span>Apache-2.0</span>
<span>·</span>
<span>TypeScript + Next.js</span>
<span>@learnkit-ai/core</span>
<span>·</span>
<span>@learnkit-ai/react</span>
</div>
</div>
</div>
Expand Down
16 changes: 13 additions & 3 deletions apps/web/src/components/developers/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,20 @@ function highlight(line: string) {
export function CodeBlock() {
const [tab, setTab] = useState<Lang>('install');
const [step, setStep] = useState(0);
const [copied, setCopied] = useState(false);

useEffect(() => {
const id = setInterval(() => setStep((s) => (s + 1) % 4), 2200);
return () => clearInterval(id);
}, []);

function handleCopy() {
navigator.clipboard.writeText(SNIPPETS[tab]).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 1800);
}).catch(() => undefined);
}

return (
<div
style={{
Expand Down Expand Up @@ -121,18 +129,20 @@ export function CodeBlock() {
{tab === 'install' ? 'shell' : `${tab === 'core' ? '@learnkit-ai/core' : '@learnkit-ai/react'} · v0.1.0`}
</span>
<button
onClick={handleCopy}
style={{
background: 'rgba(255,255,255,0.06)',
background: copied ? 'rgba(107,143,110,0.25)' : 'rgba(255,255,255,0.06)',
border: 'none',
color: 'rgba(244,239,227,0.7)',
color: copied ? 'rgba(107,200,113,0.9)' : 'rgba(244,239,227,0.7)',
padding: '4px 10px',
borderRadius: 6,
fontSize: 11,
fontFamily: 'var(--mono)',
cursor: 'pointer',
transition: 'background 0.2s, color 0.2s',
}}
>
copy
{copied ? 'copied!' : 'copy'}
</button>
</div>
</div>
Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/components/layout/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ const LINKS: FooterCol[] = [
{
h: 'Developers',
l: [
{ label: 'Docs', href: '/developers' },
{ label: 'API reference', href: '/developers#endpoints' },
{ label: 'SDKs · GitHub', href: 'https://github.com/learnkit-ai/learnkit' },
{ label: 'Docs', href: '/docs' },
{ label: 'API reference', href: '/developers' },
{ label: 'GitHub', href: 'https://github.com/learnkit-ai/learnkit' },
{ label: 'Blog', href: '/blog' },
],
},
Expand Down Expand Up @@ -69,7 +69,7 @@ export function Footer() {
maxWidth: 280,
}}
>
The AI workbench for teams that ship.
Open-source TypeScript engine for embedding personalized AI learning paths. Apache-2.0.
</p>
</div>
{LINKS.map((col) => (
Expand Down Expand Up @@ -113,9 +113,9 @@ export function Footer() {
<span style={{ fontSize: 12, color: 'var(--muted)' }}>© 2026 LearnKit AI, Inc. · learnkit-ai.com</span>
</div>
<div style={{ display: 'flex', gap: 16, fontSize: 12, color: 'var(--muted)' }}>
{['Privacy', 'Terms', 'Security', 'Apache-2.0'].map((item) => (
<a key={item} href="#" style={{ color: 'inherit', textDecoration: 'none' }}>{item}</a>
))}
<a href="https://github.com/learnkit-ai/learnkit/blob/main/SECURITY.md" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'none' }}>Security</a>
<a href="https://github.com/learnkit-ai/learnkit/blob/main/LICENSE" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'none' }}>Apache-2.0</a>
<a href="https://github.com/learnkit-ai/learnkit/blob/main/CONTRIBUTING.md" target="_blank" rel="noopener noreferrer" style={{ color: 'inherit', textDecoration: 'none' }}>Contributing</a>
</div>
</div>
</div>
Expand Down
Loading