snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
This commit is contained in:
93
apps/docs/components/navigation/footer.tsx
Normal file
93
apps/docs/components/navigation/footer.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { PrivacySettingsLink } from '@/app/analytics'
|
||||
import { Logo } from '@/components/common/logo'
|
||||
import { TldrawLink } from '../common/tldraw-link'
|
||||
import { SocialLink } from './social-link'
|
||||
|
||||
const menus = [
|
||||
{
|
||||
heading: 'Product',
|
||||
items: [
|
||||
{ caption: 'Whiteboard', href: '/features/out-of-the-box-whiteboard' },
|
||||
{ caption: 'Starter kits', href: '/starter-kits/overview' },
|
||||
{ caption: 'Pricing', href: '/pricing' },
|
||||
{ caption: 'FAQ', href: '/faq' },
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: 'Developers',
|
||||
items: [
|
||||
{ caption: 'Quick start guide', href: '/quick-start' },
|
||||
{ caption: 'Starter kits', href: '/starter-kits/overview' },
|
||||
{ caption: 'Examples', href: '/examples/basic' },
|
||||
{ caption: 'Releases', href: '/releases' },
|
||||
{ caption: 'Docs', href: '/quick-start' },
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: 'Community',
|
||||
items: [
|
||||
{ caption: 'GitHub', href: 'https://github.com/tldraw/tldraw' },
|
||||
{
|
||||
caption: 'Discord',
|
||||
href: 'https://discord.tldraw.com/?utm_source=docs&utm_medium=organic&utm_campaign=sociallink',
|
||||
},
|
||||
{ caption: 'X/Twitter', href: 'https://x.com/tldraw/' },
|
||||
{ caption: 'LinkedIn', href: 'https://www.linkedin.com/company/tldraw/' },
|
||||
{ caption: 'Bluesky', href: 'https://bsky.app/profile/tldraw.com' },
|
||||
{ caption: 'Mastodon', href: 'https://mas.to/@tldraw' },
|
||||
],
|
||||
},
|
||||
{
|
||||
heading: 'Company',
|
||||
items: [
|
||||
{ caption: 'Videos', href: '/blog/events' },
|
||||
{ caption: 'Careers', href: '/careers' },
|
||||
{ caption: 'License', href: '/community/license' },
|
||||
{ caption: 'Trademarks', href: '/legal/trademark-guidelines' },
|
||||
{ caption: 'CLA', href: '/legal/contributor-license-agreement' },
|
||||
{ caption: 'Privacy settings', href: '#', isCookieSetting: true },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="pt-16 pb-36 bg-zinc-950 text-white">
|
||||
<div className="flex flex-col w-full max-w-screen-2xl gap-12 px-5 mx-auto sm:flex-row sm:justify-between">
|
||||
<div className="flex-[2]">
|
||||
<TldrawLink href="/" className="w-28">
|
||||
<Logo className="h-6" forceWhite />
|
||||
</TldrawLink>
|
||||
<p className="mt-2 text-sm">The infinite canvas SDK</p>
|
||||
<div className="mt-4 flex gap-5">
|
||||
<SocialLink caption="GitHub" icon="github" href="https://github.com/tldraw/tldraw" />
|
||||
<SocialLink caption="X/Twitter" icon="twitter" href="https://x.com/tldraw/" />
|
||||
<SocialLink caption="Discord" icon="discord" href="https://discord.tldraw.com/" />
|
||||
<SocialLink
|
||||
caption="LinkedIn"
|
||||
icon="linkedin"
|
||||
href="https://www.linkedin.com/company/tldraw/"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{menus.map(({ heading, items }, index) => (
|
||||
<div key={index} className="flex-1">
|
||||
<h4 className="font-medium text-sm text-zinc-400">{heading}</h4>
|
||||
<ul className="flex flex-col gap-4 mt-4 text-sm">
|
||||
{items.map(({ caption, href, isCookieSetting }, index) => (
|
||||
<li key={index}>
|
||||
{isCookieSetting ? (
|
||||
<PrivacySettingsLink />
|
||||
) : (
|
||||
<TldrawLink href={href}>{caption}</TldrawLink>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<p className="mt-8 px-5 text-xs">© {new Date().getFullYear()} tldraw</p>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
62
apps/docs/components/navigation/header.tsx
Normal file
62
apps/docs/components/navigation/header.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
'use client'
|
||||
|
||||
import { motion, useScroll, useTransform } from 'framer-motion'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { type IconName } from '@/components/common/icon'
|
||||
import { Logo } from '@/components/common/logo'
|
||||
import { SocialLink } from '@/components/navigation/social-link'
|
||||
import { SearchButton } from '@/components/search/SearchButton'
|
||||
import { ThemeSwitch } from '../common/theme-switch'
|
||||
|
||||
const socialLinks = [
|
||||
{
|
||||
caption: 'Twitter/X',
|
||||
icon: 'twitter' as IconName,
|
||||
href: 'https://x.com/tldraw/',
|
||||
},
|
||||
{
|
||||
caption: 'Discord',
|
||||
icon: 'discord' as IconName,
|
||||
href: 'https://discord.tldraw.com/?utm_source=docs&utm_medium=organic&utm_campaign=sociallink',
|
||||
},
|
||||
{
|
||||
caption: 'GitHub',
|
||||
icon: 'github' as IconName,
|
||||
href: 'https://github.com/tldraw/tldraw',
|
||||
},
|
||||
]
|
||||
|
||||
export function Header() {
|
||||
const pathname = usePathname()
|
||||
const { scrollY } = useScroll()
|
||||
const navOpacity = useTransform(scrollY, [0, 32], [1, 0])
|
||||
const socialsOpacityEffect = pathname === '/search'
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 w-full bg-white dark:bg-zinc-950 z-10">
|
||||
<nav className="w-full max-w-screen-2xl mx-auto px-5 h-14 md:h-[4.5rem] flex justify-between items-center text-zinc-800 dark:text-zinc-200 border-b border-zinc-100 dark:border-zinc-800 dark:md:border-transparent md:border-transparent">
|
||||
<Link href="/" className="w-28">
|
||||
<Logo className="h-6" />
|
||||
</Link>
|
||||
<motion.ul
|
||||
style={{ opacity: socialsOpacityEffect ? navOpacity : 1 }}
|
||||
className="hidden sm:flex w-28 gap-4 justify-end xl:!opacity-100"
|
||||
>
|
||||
{socialLinks.map((item, index) => (
|
||||
<li key={index}>
|
||||
<SocialLink {...item} />
|
||||
</li>
|
||||
))}
|
||||
<ThemeSwitch />
|
||||
</motion.ul>
|
||||
<div className="flex items-center sm:hidden -mr-2">
|
||||
{!pathname?.startsWith('/search') && (
|
||||
<SearchButton type={pathname?.startsWith('/blog') ? 'blog' : 'docs'} layout="mobile" />
|
||||
)}
|
||||
<ThemeSwitch />
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
53
apps/docs/components/navigation/headings-menu.tsx
Normal file
53
apps/docs/components/navigation/headings-menu.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { ArticleHeading } from '@/types/content-types'
|
||||
import { cn } from '@/utils/cn'
|
||||
|
||||
export function HeadingsMenu({ headings }: { headings: ArticleHeading[] }) {
|
||||
const [activeSlug, setActiveSlug] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
let current = ''
|
||||
for (const { slug } of headings) {
|
||||
const element = document.getElementById(slug)
|
||||
if (element && element.getBoundingClientRect().top < 100) current = slug
|
||||
}
|
||||
setActiveSlug(current)
|
||||
}
|
||||
handleScroll()
|
||||
window.addEventListener('scroll', handleScroll, { passive: true })
|
||||
return () => window.removeEventListener('scroll', handleScroll)
|
||||
}, [headings])
|
||||
|
||||
if (headings.length === 0) return null
|
||||
|
||||
return (
|
||||
<div className="relative overflow-y-auto shrink mb-12">
|
||||
<div className="sticky top-0">
|
||||
<h4 className="block text-xs font-semibold text-black uppercase bg-white dark:bg-zinc-950 dark:text-white">
|
||||
On this page
|
||||
</h4>
|
||||
<div className="w-full h-2 bg-gradient-to-b from-white dark:from-zinc-950" />
|
||||
</div>
|
||||
<ul className="flex flex-col gap-2 text-sm break-words">
|
||||
{headings.map(({ title, level, slug }, index) => (
|
||||
<li key={index} style={{ paddingLeft: `${(level - 2) * 0.75}rem` }}>
|
||||
<Link
|
||||
href={`#${slug}`}
|
||||
className={cn(
|
||||
slug === activeSlug
|
||||
? 'text-black dark:text-white font-semibold'
|
||||
: 'hover:text-zinc-800 dark:hover:text-zinc-100'
|
||||
)}
|
||||
>
|
||||
{title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
47
apps/docs/components/navigation/link.tsx
Normal file
47
apps/docs/components/navigation/link.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { cn } from '@/utils/cn'
|
||||
|
||||
export function NavigationLink({
|
||||
caption,
|
||||
icon,
|
||||
href,
|
||||
active,
|
||||
}: {
|
||||
caption: string
|
||||
icon?: any
|
||||
href?: string
|
||||
active: boolean
|
||||
}) {
|
||||
const Icon = icon
|
||||
|
||||
if (href)
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className={cn(
|
||||
'flex items-center gap-3',
|
||||
active
|
||||
? 'font-semibold text-black dark:text-white'
|
||||
: 'hover:text-zinc-600 dark:hover:text-zinc-100'
|
||||
)}
|
||||
>
|
||||
{icon && (
|
||||
<div
|
||||
className={cn(
|
||||
'h-6 w-6 rounded-md flex items-center justify-center',
|
||||
active
|
||||
? 'bg-black text-white dark:bg-white dark:text-black'
|
||||
: 'bg-zinc-100 dark:bg-zinc-700 dark:text-zinc-300'
|
||||
)}
|
||||
>
|
||||
<Icon className="h-4" />
|
||||
</div>
|
||||
)}
|
||||
<span>{caption}</span>
|
||||
</Link>
|
||||
)
|
||||
|
||||
return null
|
||||
}
|
||||
19
apps/docs/components/navigation/social-link.tsx
Normal file
19
apps/docs/components/navigation/social-link.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import Link from 'next/link'
|
||||
import { Icon, IconName } from '@/components/common/icon'
|
||||
|
||||
export function SocialLink({
|
||||
caption,
|
||||
icon,
|
||||
href,
|
||||
}: {
|
||||
caption: string
|
||||
icon: IconName
|
||||
href: string
|
||||
}) {
|
||||
return (
|
||||
<Link href={href} target="_blank" rel="noreferrer">
|
||||
<span className="sr-only">{caption}</span>
|
||||
<Icon icon={icon} className="h-4" />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user