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

This commit is contained in:
upstream-mirror
2026-09-23 16:12:52 +05:00
commit a774ac673a
4541 changed files with 770499 additions and 0 deletions

View 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">&copy; {new Date().getFullYear()} tldraw</p>
</footer>
)
}

View 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>
)
}

View 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>
)
}

View 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
}

View 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>
)
}