Merge branch 'master' into chore/move-policies

This commit is contained in:
Saxon Fletcher committed 2026-05-15 14:39:54 +10:00
commit 6da91309ca
2752 files changed
+195264 -131909

No files matched your search

+14 -2
View File
@@ -83,18 +83,30 @@ jobs:
if: steps.filter.outputs.studio == 'true'
run: rm -rf supabase && pnpm exec supabase init && mkdir supabase/functions
- name: Pre-start diagnostics
run: |
docker ps -a
sudo ss -tlnp | grep 5432 || echo "5432 free"
- name: Start supabase
if: steps.filter.outputs.studio == 'true'
run: SKIP_ASSET_UPLOAD=1 pnpm run e2e:setup:cli
- name: Failure diagnostics
if: failure()
run: |
docker ps -a
sudo ss -tlnp | grep 5432
docker logs $(docker ps -aq) 2>&1 || true
- name: Build studio
if: steps.filter.outputs.studio == 'true'
run: SKIP_ASSET_UPLOAD=1 NODE_ENV=test NODE_OPTIONS="--max-old-space-size=4096" pnpm run build:studio
- name: 🚀 Run Playwright tests against Vercel Preview
- name: 🚀 Run Playwright tests against local studio build
if: steps.filter.outputs.studio == 'true'
id: playwright
run: pnpm e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
run: PWTEST_SHARD_WEIGHTS=62:38 pnpm e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
- name: Upload blob report to GitHub Actions Artifacts
if: always() && steps.filter.outputs.studio == 'true'
+3
View File
@@ -8,6 +8,9 @@ apps/**/out
**/supabase/migrations/*.sql
apps/www/schema.sql
apps/www/public/images/*
# Generated by apps/www/scripts/generateStaticContent.mjs (GitHub discussion bodies)
apps/www/public/changelog.md
apps/www/public/changelog/*.md
apps/www/.generated/*
apps/docs/**/generated/*
apps/docs/examples/*
@@ -71,7 +71,7 @@ export default function ChartComposedMetrics() {
</ChartHeader>
<ChartContent
className="p-0"
loadingState={<Skeleton className="w-full h-[6rem] rounded-none mt-4" />}
loadingState={<Skeleton className="w-full h-24 rounded-none mt-4" />}
>
<ChartSparkline data={data} dataKey="value" />
</ChartContent>
@@ -89,7 +89,7 @@ export default function ChartComposedMetrics() {
</ChartHeader>
<ChartContent
className="p-0"
loadingState={<Skeleton className="w-full h-[6rem] rounded-none mt-4" />}
loadingState={<Skeleton className="w-full h-24 rounded-none mt-4" />}
>
<ChartSparkline data={data} dataKey="value" />
</ChartContent>
+33
View File
@@ -126,6 +126,17 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"admonition-description-only": {
name: "admonition-description-only",
type: "components:example",
registryDependencies: ["admonition"],
component: React.lazy(() => import("@/registry/default/example/admonition-description-only")),
source: "",
files: ["registry/default/example/admonition-description-only.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"admonition-warning": {
name: "admonition-warning",
type: "components:example",
@@ -137,6 +148,17 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"admonition-success": {
name: "admonition-success",
type: "components:example",
registryDependencies: ["admonition"],
component: React.lazy(() => import("@/registry/default/example/admonition-success")),
source: "",
files: ["registry/default/example/admonition-success.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"admonition-destructive": {
name: "admonition-destructive",
type: "components:example",
@@ -2568,6 +2590,17 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"multi-select-in-dialog": {
name: "multi-select-in-dialog",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/multi-select-in-dialog")),
source: "",
files: ["registry/default/example/multi-select-in-dialog.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"tree-view-demo": {
name: "tree-view-demo",
type: "components:example",
+4 -5
View File
@@ -1,20 +1,19 @@
'use client'
import { ThemeProvider } from 'common'
import { Provider as JotaiProvider } from 'jotai'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
import { ThemeProviderProps } from 'next-themes/dist/types'
import { TooltipProvider } from 'ui'
import { MobileSidebarProvider } from '@/context/mobile-sidebar-context'
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
export function Providers({ children }: { children: React.ReactNode }) {
return (
<JotaiProvider>
<NextThemesProvider {...props}>
<ThemeProvider>
<TooltipProvider delayDuration={0}>
<MobileSidebarProvider>{children}</MobileSidebarProvider>
</TooltipProvider>
</NextThemesProvider>
</ThemeProvider>
</JotaiProvider>
)
}
-29
View File
@@ -1,29 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* :root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
} */
body {
/* color: rgb(var(--foreground-rgb));
background: linear-gradient(to bottom, transparent, rgb(var(--background-end-rgb)))
rgb(var(--background-start-rgb)); */
}
/*
@layer utilities {
.text-balance {
text-wrap: balance;
}
} */
+4 -8
View File
@@ -1,10 +1,10 @@
import 'react-data-grid/lib/styles.css'
import '@/styles/globals.css'
import '../../studio/styles/typography.css'
import type { Metadata, Viewport } from 'next'
import { customFont, sourceCodePro } from './fonts'
import { ThemeProvider } from './Providers'
import { Providers } from './Providers'
import { Toaster } from './toaster'
const className = `${customFont.variable} ${sourceCodePro.variable}`
@@ -131,16 +131,12 @@ export default async function Layout({ children }: RootLayoutProps) {
/>
</head>
<body>
<ThemeProvider
themes={['dark', 'light', 'classic-dark']}
defaultTheme="system"
enableSystem
>
<Providers>
<div vaul-drawer-wrapper="">
<div className="relative flex min-h-screen flex-col bg-background">{children}</div>
</div>
<Toaster />
</ThemeProvider>
</Providers>
</body>
</html>
)
@@ -5,7 +5,7 @@ const ClassLabel = React.forwardRef<HTMLSpanElement, { children: React.ReactNode
return (
<span
ref={ref}
className="bg-surface-100 rounded-full border px-2 font-mono text-xs text-foreground-lighter group-data-[state=open]:text-foreground"
className="bg-surface-100 rounded-full border px-2 font-mono text-xs text-foreground-lighter group-data-open:text-foreground"
>
{children}
</span>
@@ -36,7 +36,7 @@ export function CodeBlockWrapper({
</CollapsibleContent>
<div
className={cn(
'absolute flex items-center justify-center bg-gradient-to-b from-zinc-700/30 to-zinc-950/90 p-2',
'absolute flex items-center justify-center bg-linear-to-b from-zinc-700/30 to-zinc-950/90 p-2',
isOpened ? 'inset-x-0 bottom-0 h-12' : 'inset-0'
)}
>
@@ -51,7 +51,7 @@ export function CodeFragment({
return (
<p className="text-sm text-muted-foreground">
Code fragment{' '}
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
<code className="relative rounded-sm bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
{name}
</code>{' '}
not found in registry.
@@ -94,10 +94,10 @@ export function CodeFragment({
)}
>
{showGrid && (
<div className="pointer-events-none absolute h-full w-full bg-[linear-gradient(to_right,hsla(var(--foreground-default)/0.02)_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:24px_24px]"></div>
<div className="pointer-events-none absolute h-full w-full bg-[linear-gradient(to_right,hsla(var(--foreground-default)/0.02)_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-size-[24px_24px]"></div>
)}
{showDottedGrid && (
<div className="z-0 pointer-events-none absolute h-full w-full bg-[radial-gradient(hsla(var(--foreground-default)/0.02)_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
<div className="z-0 pointer-events-none absolute h-full w-full bg-[radial-gradient(hsla(var(--foreground-default)/0.02)_1px,transparent_1px)] bg-size-[16px_16px] mask-[radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
)}
<div className="z-10 relative">{ComponentPreview}</div>
</div>
@@ -0,0 +1,84 @@
'use client'
import { useState } from 'react'
const colorNames = [
'Amber',
'Blue',
'Brand',
'Crimson',
'Gold',
'Gray',
'Green',
'Indigo',
'Orange',
'Pink',
'Purple',
'Red',
'Scale',
'Slate',
'Tomato',
'Violet',
'Yellow',
]
const SCALE_STEPS = Array.from({ length: 12 }, (_, i) => i + 1)
const GRID_COLS = 'grid-cols-[6rem_repeat(12,minmax(0,1fr))]'
const ColorPalette = () => {
const [copied, setCopied] = useState<string | null>(null)
const handleCopy = async (value: string) => {
try {
await navigator.clipboard.writeText(value)
setCopied(value)
setTimeout(() => setCopied(null), 1500)
} catch (err) {
console.error('Failed to copy text: ', err)
}
}
return (
<div className="my-6 w-full">
<div className="flex min-w-[640px] flex-col gap-1">
<div className={`grid gap-1 ${GRID_COLS}`}>
<div />
{SCALE_STEPS.map((step) => (
<div key={step} className="text-center font-mono text-[10px] text-foreground-lighter">
{step}
</div>
))}
</div>
{colorNames.map((name) => {
const slug = name.toLowerCase()
return (
<div key={slug} className={`grid items-center gap-1 ${GRID_COLS}`}>
<div className="pr-2 text-sm font-medium text-foreground">{name}</div>
{SCALE_STEPS.map((step) => {
const reference = `var(--color-${slug}-${step * 100})`
const isCopied = copied === reference
return (
<button
key={step * 100}
type="button"
onClick={() => handleCopy(reference)}
className="group relative flex aspect-square w-full items-center justify-center rounded-sm border border-overlay/40 transition hover:scale-[1.05] focus:outline-none focus-visible:ring-2 focus-visible:ring-foreground"
style={{ backgroundColor: reference }}
title={reference}
>
<span className="rounded-xs bg-surface-100/90 px-1 font-mono text-[10px] text-foreground-light opacity-0 transition group-hover:opacity-100">
{isCopied ? 'Copied!' : step * 100}
</span>
</button>
)
})}
</div>
)
})}
</div>
</div>
)
}
export { ColorPalette }
+1 -1
View File
@@ -70,7 +70,7 @@ const Colors = ({
onClick={() => handleCopy(x, i)}
>
<Example x={x} />
<span className="bg-surface-100 rounded-full border px-2 font-mono text-xs text-foreground-lighter group-data-[state=open]:text-foreground text-center">
<span className="bg-surface-100 rounded-full border px-2 font-mono text-xs text-foreground-lighter group-data-open:text-foreground text-center">
{copiedIndex === i ? 'Copied!' : x}
</span>
</GridItem>
@@ -56,7 +56,7 @@ export function CommandMenu({ ...props }: DialogProps) {
<Button
type="outline"
className={cn(
`lg:flex hidden relative h-8 w-full justify-start rounded-[0.5rem] bg-background text-sm font-normal text-foreground-muted shadow-none sm:pr-12 md:w-40 lg:w-64 hover:border-foreground-muted hover:bg-surface-100 hover:text-foreground-lighter
`lg:flex hidden relative h-8 w-full justify-start rounded-lg bg-background text-sm font-normal text-foreground-muted shadow-none sm:pr-12 md:w-40 lg:w-64 hover:border-foreground-muted hover:bg-surface-100 hover:text-foreground-lighter
`
)}
onClick={() => setOpen(true)}
@@ -64,7 +64,7 @@ export function CommandMenu({ ...props }: DialogProps) {
>
<span className="hidden lg:inline-flex">Search Design System...</span>
<span className="inline-flex lg:hidden">Search...</span>
<kbd className="pointer-events-none absolute right-[0.3rem] top-[0.3rem] hidden h-5 select-none items-center gap-1 rounded border bg-surface-200 px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex text-foreground-light">
<kbd className="pointer-events-none absolute right-[0.3rem] top-[0.3rem] hidden h-5 select-none items-center gap-1 rounded-sm border bg-surface-200 px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex text-foreground-light">
<span className="text-sm">⌘</span>K
</kbd>
</Button>
@@ -55,7 +55,7 @@ export function ComponentPreview({
return (
<p className="text-sm text-muted-foreground">
Component{' '}
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
<code className="relative rounded-sm bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm">
{name}
</code>{' '}
not found in registry.
@@ -99,10 +99,10 @@ export function ComponentPreview({
)}
>
{showGrid && (
<div className="pointer-events-none absolute h-full w-full bg-[linear-gradient(to_right,hsla(var(--foreground-default)/0.02)_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:24px_24px]"></div>
<div className="pointer-events-none absolute h-full w-full bg-[linear-gradient(to_right,hsla(var(--foreground-default)/0.02)_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-size-[24px_24px]"></div>
)}
{showDottedGrid && (
<div className="z-0 pointer-events-none absolute h-full w-full bg-[radial-gradient(hsla(var(--foreground-default)/0.02)_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
<div className="z-0 pointer-events-none absolute h-full w-full bg-[radial-gradient(hsla(var(--foreground-default)/0.02)_1px,transparent_1px)] bg-size-[16px_16px] mask-[radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
)}
<div className="z-10 relative">{ComponentPreview}</div>
{/* <div className="preview-grid-background"></div> */}
@@ -144,10 +144,10 @@ export function ComponentPreview({
})}
>
{showGrid && (
<div className="pointer-events-none absolute h-full w-full bg-[linear-gradient(to_right,hsla(var(--foreground-default)/0.02)_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:24px_24px]"></div>
<div className="pointer-events-none absolute h-full w-full bg-[linear-gradient(to_right,hsla(var(--foreground-default)/0.02)_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-size-[24px_24px]"></div>
)}
{showDottedGrid && (
<div className="z-0 pointer-events-none absolute h-full w-full bg-[radial-gradient(hsla(var(--foreground-default)/0.02)_1px,transparent_1px)] [background-size:16px_16px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
<div className="z-0 pointer-events-none absolute h-full w-full bg-[radial-gradient(hsla(var(--foreground-default)/0.02)_1px,transparent_1px)] bg-size-[16px_16px] mask-[radial-gradient(ellipse_50%_50%_at_50%_50%,#000_70%,transparent_100%)]"></div>
)}
<div className="z-10 relative">{ComponentPreview}</div>
</div>
@@ -164,12 +164,12 @@ export function ComponentPreview({
px-4 py-4
border border-r
group
data-[state=closed]:rounded-bl-md data-[state=closed]:rounded-br-md
data-closed:rounded-bl-md data-closed:rounded-br-md
`}
>
<ChevronRight
className="transition-all group-data-[state=open]:rotate-90 text-foreground-lighter"
className="transition-all group-data-open:rotate-90 text-foreground-lighter"
size={14}
/>
View code
+2 -2
View File
@@ -47,8 +47,8 @@ const GridItem = forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
transition
group-hover:border
group-hover:border-foreground-muted
group-data-[state=open]:border
group-data-[state=open]:border-foreground-muted
group-data-open:border
group-data-open:border-foreground-muted
"
></div>
{children}
+2 -5
View File
@@ -18,11 +18,8 @@ function Icons() {
<DropdownMenu key={i} modal={false}>
<DropdownMenuTrigger asChild>
<GridItem>
<icon.component
size={21}
className="group-data-[state=open]:scale-125 transition-all"
/>
<span className="bg-surface-100 rounded-full border px-2 font-mono text-xs text-foreground-lighter group-data-[state=open]:text-foreground">
<icon.component size={21} className="group-data-open:scale-125 transition-all" />
<span className="bg-surface-100 rounded-full border px-2 font-mono text-xs text-foreground-lighter group-data-open:text-foreground">
{icon.name}
</span>
</GridItem>
@@ -31,6 +31,7 @@ import { StyleWrapper } from './style-wrapper'
import { Callout } from '@/components/callout'
import { CodeBlockWrapper } from '@/components/code-block-wrapper'
import { CodeFragment } from '@/components/code-fragment'
import { ColorPalette } from '@/components/color-palette'
import { Colors } from '@/components/colors'
import { ComponentExample } from '@/components/component-example'
import { ComponentPreview } from '@/components/component-preview'
@@ -92,10 +93,7 @@ const components = {
/>
),
p: ({ className, ...props }: React.HTMLAttributes<HTMLParagraphElement>) => (
<p
className={cn('leading-7 [&:not(:first-child)]:mt-6 text-foreground-light', className)}
{...props}
/>
<p className={cn('leading-7 not-first:mt-6 text-foreground-light', className)} {...props} />
),
ul: ({ className, ...props }: React.HTMLAttributes<HTMLUListElement>) => (
<ul className={cn('my-6 ml-6 list-disc', className)} {...props} />
@@ -127,7 +125,7 @@ const components = {
th: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<th
className={cn(
'border px-4 py-2 text-left font-normal [&[align=center]]:text-center [&[align=right]]:text-right',
'border px-4 py-2 text-left font-normal [[align=center]]:text-center [[align=right]]:text-right',
className
)}
{...props}
@@ -136,7 +134,7 @@ const components = {
td: ({ className, ...props }: React.HTMLAttributes<HTMLTableCellElement>) => (
<td
className={cn(
'border text-foreground-light px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right',
'border text-foreground-light px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right',
className
)}
{...props}
@@ -199,7 +197,7 @@ const components = {
code: ({ className, ...props }: React.HTMLAttributes<HTMLElement>) => (
<code
className={cn(
'relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm',
'relative rounded-sm bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm',
className
)}
{...props}
@@ -261,13 +259,14 @@ const components = {
LinkedCard: ({ className, ...props }: React.ComponentProps<typeof Link>) => (
<Link
className={cn(
'flex w-full flex-col items-center rounded-xl border bg-card p-6 text-card-foreground shadow transition-colors hover:bg-muted/50 sm:p-10',
'flex w-full flex-col items-center rounded-xl border bg-card p-6 text-card-foreground shadow-sm transition-colors hover:bg-muted/50 sm:p-10',
className
)}
{...props}
/>
),
Colors,
ColorPalette,
Icons,
ThemeSettings,
CodeFragment,
@@ -3,7 +3,7 @@
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
import SVG from 'react-inlinesvg'
import { RadioGroup_Shadcn_, RadioGroupLargeItem_Shadcn_, singleThemes, Theme } from 'ui'
import { RadioGroup, RadioGroupLargeItem, singleThemes, Theme } from 'ui'
const ThemeSettings = () => {
const [mounted, setMounted] = useState(false)
@@ -25,7 +25,7 @@ const ThemeSettings = () => {
function SingleThemeSelection() {
return (
<form className="py-8">
<RadioGroup_Shadcn_
<RadioGroup
name="theme"
onValueChange={setTheme}
aria-label="Choose a theme"
@@ -34,11 +34,11 @@ const ThemeSettings = () => {
className="flex flex-wrap gap-3"
>
{singleThemes.map((theme: Theme) => (
<RadioGroupLargeItem_Shadcn_ key={theme.value} value={theme.value} label={theme.name}>
<RadioGroupLargeItem key={theme.value} value={theme.value} label={theme.name}>
<SVG src={`${process.env.NEXT_PUBLIC_BASE_PATH}/img/themes/${theme.value}.svg`} />
</RadioGroupLargeItem_Shadcn_>
</RadioGroupLargeItem>
))}
</RadioGroup_Shadcn_>
</RadioGroup>
</form>
)
}
@@ -33,7 +33,7 @@ const ThemeSwitcherDropdown = () => {
return null
}
const iconClasses = 'text-foreground-lighter group-data-[state=open]:text-foreground'
const iconClasses = 'text-foreground-lighter group-data-open:text-foreground'
return (
<>
@@ -13,7 +13,7 @@ export const TopNavigation = () => {
const { toggle } = useMobileSidebar()
return (
<header className="sticky top-0 z-50 w-full bg-studio/95 backdrop-blur supports-[backdrop-filter]:bg-studio/60 border-b border-l border-r">
<header className="sticky top-0 z-50 w-full bg-studio/95 backdrop-blur-sm supports-backdrop-filter:bg-studio/60 border-b border-l border-r">
<nav className="py-3 w-full flex">
<div className="max-w-site w-full flex flex-row items-center gap-6 mx-auto md:px-6 px-4 justify-between">
<div className="flex items-center gap-2">
@@ -69,3 +69,12 @@ This is not to be confused with `Dialogs`, they require to use the same app back
These can also be accessed with `foreground`. Like `text-foreground-light`.
<Colors definition={'colors'} />
## Color palette
Every Radix scale exposed via `--colors-{name}{1..12}`. Click a swatch to copy the CSS variable reference. The colors are taken
from `@radix-ui/colors` v0.1.9 except the `Brand` and `Scale` colors.
The `Brand` colors issue of not being uniform across the whole scale is known, they need to be refactored. The `brand-200` variable in the dark themes is also bad.
<ColorPalette />
@@ -417,7 +417,7 @@ const chartData = [
#### Tailwind
```tsx
<LabelList className="fill-[--color-desktop]" />
<LabelList className="fill-(--color-desktop)" />
```
## Tooltip
@@ -108,47 +108,47 @@ See the [Form](/docs/forms) documentation for building forms with the `Field` co
### Input
<ComponentPreview name="field-input" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-input" className="mb-4! [&_.preview]:p-6" />
### Textarea
<ComponentPreview name="field-textarea" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-textarea" className="mb-4! [&_.preview]:p-6" />
### Select
<ComponentPreview name="field-select" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-select" className="mb-4! [&_.preview]:p-6" />
### Slider
<ComponentPreview name="field-slider" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-slider" className="mb-4! [&_.preview]:p-6" />
### Fieldset
<ComponentPreview name="field-fieldset" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-fieldset" className="mb-4! [&_.preview]:p-6" />
### Checkbox
<ComponentPreview name="field-checkbox" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-checkbox" className="mb-4! [&_.preview]:p-6" />
### Radio
<ComponentPreview name="field-radio" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-radio" className="mb-4! [&_.preview]:p-6" />
### Switch
<ComponentPreview name="field-switch" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-switch" className="mb-4! [&_.preview]:p-6" />
### Choice Card
Wrap `Field` components inside `FieldLabel` to create selectable field groups. This works with `RadioItem`, `Checkbox` and `Switch` components.
<ComponentPreview name="field-choice-card" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-choice-card" className="mb-4! [&_.preview]:p-6" />
### Field Group
Stack `Field` components with `FieldGroup`. Add `FieldSeparator` to divide them.
<ComponentPreview name="field-group" className="!mb-4 [&_.preview]:p-6" />
<ComponentPreview name="field-group" className="mb-4! [&_.preview]:p-6" />
## Responsive Layout
@@ -158,7 +158,7 @@ Stack `Field` components with `FieldGroup`. Add `FieldSeparator` to divide them.
<ComponentPreview
name="field-responsive"
className="!mb-4 [&_.preview]:h-[650px] [&_.preview]:p-6 [&_.preview]:md:h-[500px] [&_.preview]:md:p-10"
className="mb-4! [&_.preview]:h-[650px] [&_.preview]:p-6 [&_.preview]:md:h-[500px] [&_.preview]:md:p-10"
/>
## Validation and Errors
@@ -241,7 +241,7 @@ That's it. You now have a fully accessible form that is type-safe with client-si
<ComponentPreview
name="input-form"
className="[&_[role=tablist]]:hidden [&>div>div:first-child]:hidden"
className="**:[[role=tablist]]:hidden [&>div>div:first-child]:hidden"
/>
</Steps>
@@ -571,7 +571,7 @@ The following example adds a `<DropdownMenu>` to the `SidebarHeader`.
<ChevronDown className="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-[--radix-popper-anchor-width]">
<DropdownMenuContent className="w-(--radix-popper-anchor-width)">
<DropdownMenuItem>
<span>Acme Inc</span>
</DropdownMenuItem>
@@ -622,7 +622,7 @@ export function AppSidebar() {
<ChevronUp className="ml-auto" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent side="top" className="w-[--radix-popper-anchor-width]">
<DropdownMenuContent side="top" className="w-(--radix-popper-anchor-width)">
<DropdownMenuItem>
<span>Account</span>
</DropdownMenuItem>
@@ -724,7 +724,7 @@ export function AppSidebar() {
<SidebarGroupLabel asChild>
<CollapsibleTrigger>
Help
<ChevronDown className="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180" />
<ChevronDown className="ml-auto transition-transform group-data-open/collapsible:rotate-180" />
</CollapsibleTrigger>
</SidebarGroupLabel>
<CollapsibleContent>
@@ -6,7 +6,7 @@ source:
shadcn: true
---
<ComponentPreview name="typography-demo" className="[&>div.min-h-[350px]]:p-6" peekCode wide />
<ComponentPreview name="typography-demo" peekCode wide />
## h1
@@ -15,6 +15,12 @@ Admonition provides focus for situations that require a callout.
Use Admonition instead of [Alert](../components/alert) unless you specifically need the primitives. If in doubt, stick with Admonition.
Use `title` for the heading slot when the callout needs its own heading. `title` is optional: short callouts may use `description` without a title when nearby content already provides enough context.
Avoid title-only Admonitions in new code. A callout with `title` should also include `description` or `children` so it does not read like an incomplete heading.
`label` is still supported for older Docs content, but new code should use `title`.
## Usage
```tsx
@@ -72,6 +78,24 @@ There are several components that wrap the `warning` Admonition type with reusab
AlertError for example rolls up consistent error handling and support contact methods.
### Description only
Use description-only Admonitions for short callouts that sit near a heading or form label with enough context.
<ComponentPreview
name="admonition-description-only"
className="[&_.preview>[data-orientation=vertical]]:sm:max-w-[70%]"
/>
### Success
Use `success` for positive, completed states where the user does not need to take corrective action.
<ComponentPreview
name="admonition-success"
className="[&_.preview>[data-orientation=vertical]]:sm:max-w-[70%]"
/>
### Destructive
<ComponentPreview
@@ -78,3 +78,9 @@ Add the `deletableBadge` prop on the `MultiSelectorTrigger` component to enable
Use `mode="inline-combobox"` on the `MultiSelectorTrigger` component to add an inline search input.
<ComponentPreview name="multi-select-inline-search-input" />
### Inside a dialog
Use `mode="inline-combobox"` on the `MultiSelectorTrigger` component to add an inline search input.
<ComponentPreview name="multi-select-in-dialog" />
+4 -4
View File
@@ -20,6 +20,7 @@
"@hookform/resolvers": "^3.1.1",
"@tanstack/react-table": "^8.21.3",
"contentlayer2": "0.4.6",
"common": "workspace:*",
"date-fns": "^2.30.0",
"dayjs": "1.11.13",
"eslint-config-supabase": "workspace:*",
@@ -29,7 +30,7 @@
"markdown-wasm": "^1.2.0",
"next": "catalog:",
"next-contentlayer2": "0.4.6",
"next-themes": "^0.3.0",
"next-themes": "catalog:",
"react": "catalog:",
"react-data-grid": "7.0.0-beta.47",
"react-day-picker": "^9.11.1",
@@ -53,14 +54,13 @@
},
"devDependencies": {
"@shikijs/compat": "^1.1.7",
"@tailwindcss/container-queries": "^0.1.1",
"@types/lodash.template": "4.5.0",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"concurrently": "^8.2.2",
"config": "workspace:^",
"config": "workspace:*",
"mdast-util-toc": "^6.1.1",
"postcss": "^8.5.3",
"postcss": "catalog:",
"rimraf": "^4.1.3",
"shiki": "^1.1.7",
"tailwindcss": "catalog:",
@@ -71,7 +71,7 @@ export default function ChartComposedMetrics() {
</ChartHeader>
<ChartContent
className="p-0"
loadingState={<Skeleton className="w-full h-[6rem] rounded-none mt-4" />}
loadingState={<Skeleton className="w-full h-24 rounded-none mt-4" />}
>
<ChartSparkline data={data} dataKey="value" />
</ChartContent>
@@ -89,7 +89,7 @@ export default function ChartComposedMetrics() {
</ChartHeader>
<ChartContent
className="p-0"
loadingState={<Skeleton className="w-full h-[6rem] rounded-none mt-4" />}
loadingState={<Skeleton className="w-full h-24 rounded-none mt-4" />}
>
<ChartSparkline data={data} dataKey="value" />
</ChartContent>
@@ -0,0 +1,10 @@
import { Admonition } from 'ui-patterns/admonition'
export default function AdmonitionDescriptionOnly() {
return (
<Admonition
type="default"
description="Changes to these settings can take a few minutes to appear across all projects."
/>
)
}
@@ -0,0 +1,11 @@
import { Admonition } from 'ui-patterns/admonition'
export default function AdmonitionSuccess() {
return (
<Admonition
type="success"
title="Connection confirmed"
description="You can now close this tab."
/>
)
}
@@ -46,7 +46,7 @@ export default function AssistantChatCommands() {
/>
</AssistantCommandsPopover>
<p className="text-xs mt-3 text-foreground-lighter">
Press <span className="bg-surface-300 px-[3px] py-[2px] border rounded">/</span> to open
Press <span className="bg-surface-300 px-[3px] py-[2px] border rounded-sm">/</span> to open
commands
</p>
</div>
@@ -35,11 +35,11 @@ export default function Component() {
{ name: 'Desktop', value: 186, fill: 'hsl(var(--chart-1))' },
{ name: 'Mobile', value: 80, fill: 'hsl(var(--chart-2))' },
]}
className="w-[8rem]"
className="w-32"
/>
</div>
<div className="items-end">
<div className="absolute left-[122px] top-[0px] z-10 text-sm font-medium">Name</div>
<div className="absolute left-[122px] top-0 z-10 text-sm font-medium">Name</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="35"
@@ -68,25 +68,25 @@ export default function Component() {
{ name: 'Firefox', value: 1000, fill: 'hsl(var(--chart-4))' },
]}
indicator="dashed"
className="w-[8rem]"
className="w-32"
/>
</div>
<div className="!hidden md:!flex">
<div className="hidden! md:flex!">
<TooltipDemo
label="Page Views"
payload={[{ name: 'Desktop', value: 12486, fill: 'hsl(var(--chart-3))' }]}
className="w-[9rem]"
className="w-36"
indicator="line"
/>
</div>
<div className="!items-start !justify-start">
<div className="items-start! justify-start!">
<div className="absolute left-[50px] top-[60px] z-10 text-sm font-medium">Indicator</div>
<TooltipDemo
label="Browser"
hideLabel
payload={[{ name: 'Chrome', value: 1286, fill: 'hsl(var(--chart-1))' }]}
indicator="dot"
className="w-[8rem]"
className="w-32"
/>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -144,7 +144,7 @@ function TooltipDemo({
return (
<div
className={cn(
'grid min-w-[8rem] items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out hover:-translate-y-0.5',
'grid min-w-32 items-start gap-1.5 rounded-lg border border-border/50 bg-background px-2.5 py-1.5 text-xs shadow-xl transition-all ease-in-out hover:-translate-y-0.5',
className
)}
>
@@ -165,7 +165,7 @@ function TooltipDemo({
{!hideIndicator && (
<div
className={cn(
'shrink-0 rounded-[2px] border-[--color-border] bg-[--color-bg]',
'shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)',
{
'h-2.5 w-2.5': indicator === 'dot',
'w-1': indicator === 'line',
@@ -1,11 +1,11 @@
'use client'
import { Checkbox_Shadcn_ } from 'ui'
import { Checkbox } from 'ui'
export default function CheckboxDemo() {
return (
<div className="flex items-center space-x-2">
<Checkbox_Shadcn_ id="terms" />
<Checkbox id="terms" />
<label
htmlFor="terms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
@@ -1,9 +1,9 @@
import { Checkbox_Shadcn_ } from 'ui'
import { Checkbox } from 'ui'
export default function CheckboxDisabled() {
return (
<div className="flex items-center space-x-2">
<Checkbox_Shadcn_ id="terms2" disabled />
<Checkbox id="terms2" disabled />
<label
htmlFor="terms2"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
@@ -5,7 +5,7 @@ import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
Button,
Checkbox_Shadcn_,
Checkbox,
Form,
FormControl,
FormDescription,
@@ -93,7 +93,7 @@ export default function CheckboxReactHookFormMultiple() {
className="flex flex-row items-start space-x-3 space-y-0"
>
<FormControl>
<Checkbox_Shadcn_
<Checkbox
checked={field.value?.includes(item.id)}
onCheckedChange={(checked) => {
return checked
@@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
Button,
Checkbox_Shadcn_,
Checkbox,
Form,
FormControl,
FormDescription,
@@ -47,7 +47,7 @@ export default function CheckboxReactHookFormSingle() {
render={({ field }) => (
<FormItem className="flex flex-row items-start space-x-3 space-y-0 rounded-md border p-4">
<FormControl>
<Checkbox_Shadcn_ checked={field.value} onCheckedChange={field.onChange} />
<Checkbox checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
<div className="space-y-1 leading-none">
<FormLabel>Use different settings for my mobile devices</FormLabel>
@@ -1,11 +1,11 @@
'use client'
import { Checkbox_Shadcn_ } from 'ui'
import { Checkbox } from 'ui'
export default function CheckboxWithText() {
return (
<div className="items-top flex space-x-2">
<Checkbox_Shadcn_ id="terms1" />
<Checkbox id="terms1" />
<div className="grid gap-1.5 leading-none">
<label
htmlFor="terms1"
@@ -6,35 +6,35 @@ import { ExampleLabel } from '@/components/example-label'
export default function Demo() {
return (
<div className="bg-studio w-full h-[320px] flex flex-col items-center border border-dashed rounded-md overflow-hidden">
<div className="bg-surface-200 border h-12 w-full rounded-t-md flex justify-center gap-3 items-center shadow">
<div className="bg-surface-200 border h-12 w-full rounded-t-md flex justify-center gap-3 items-center shadow-sm">
<div className="flex gap-3">
<ExampleLabel>grid header</ExampleLabel>
<ClassLabel>bg-surface-200</ClassLabel>
<ClassLabel>border</ClassLabel>
</div>
</div>
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow">
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow-sm">
<div className="flex gap-3">
<ExampleLabel>content row</ExampleLabel>
<ClassLabel>bg-200</ClassLabel>
<ClassLabel>border-secondary</ClassLabel>
</div>
</div>
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow">
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow-sm">
<div className="flex gap-3">
<ExampleLabel>content row</ExampleLabel>
<ClassLabel>bg-200</ClassLabel>
<ClassLabel>border-secondary</ClassLabel>
</div>
</div>
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow">
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow-sm">
<div className="flex gap-3">
<ExampleLabel>content row</ExampleLabel>
<ClassLabel>bg-200</ClassLabel>
<ClassLabel>border-secondary</ClassLabel>
</div>
</div>
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow">
<div className="bg-200 border-b border-r border-l border-secondary h-14 w-full flex justify-center gap-3 items-center shadow-sm">
<div className="flex gap-3">
<ExampleLabel>content row</ExampleLabel>
<ClassLabel>bg-200</ClassLabel>
@@ -32,7 +32,7 @@ export default function CommandDialogDemo() {
<>
<p className="text-sm text-muted-foreground">
Press{' '}
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded-sm border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs">⌘</span>J
</kbd>
</p>
@@ -1,9 +1,6 @@
import { useState } from 'react'
import DataGrid, { Column, useRowSelection } from 'react-data-grid'
import 'react-data-grid/lib/styles.css'
import { Checkbox_Shadcn_, cn } from 'ui'
import { Checkbox, cn } from 'ui'
type User = {
id: string
@@ -37,7 +34,7 @@ export default function DataGridDemo() {
return (
<div className="flex items-center justify-center h-full">
<Checkbox_Shadcn_
<Checkbox
checked={isRowSelected}
onClick={(e) => {
e.stopPropagation()
@@ -141,7 +138,7 @@ export default function DataGridDemo() {
return (
<div className="h-full w-full flex flex-col relative min-h-[400px] rounded-md border overflow-hidden">
<DataGrid
className="flex-grow border-t-0 bg-dash-canvas"
className="grow border-t-0 bg-dash-canvas"
rowHeight={44}
headerRowHeight={36}
columns={columns}
@@ -153,7 +150,7 @@ export default function DataGridDemo() {
return cn(
'bg-surface-75',
isSelected && 'bg-surface-200',
'[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none',
'[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-hidden [&>.rdg-cell]:shadow-none',
'[&>.rdg-cell]:border-secondary [&>.rdg-cell:not(:last-child)]:border-r',
!isLastRow && '[&>.rdg-cell]:border-b',
'[&>.rdg-cell:nth-child(2)>div]:ml-8'
@@ -1,8 +1,5 @@
import { Users } from 'lucide-react'
import DataGrid, { Column } from 'react-data-grid'
import 'react-data-grid/lib/styles.css'
import { cn } from 'ui'
/**
@@ -24,7 +21,7 @@ export default function DataGridEmptyState() {
return (
<div className="h-full w-full flex flex-col relative min-h-[400px] rounded-md border overflow-hidden">
<DataGrid
className="flex-grow border-t-0 bg-dash-canvas"
className="grow border-t-0 bg-dash-canvas"
rowHeight={44}
headerRowHeight={36}
columns={columns}
@@ -33,7 +30,7 @@ export default function DataGridEmptyState() {
rowClass={() => {
return cn(
'bg-surface-200 cursor-pointer',
'[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none',
'[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-hidden [&>.rdg-cell]:shadow-none',
'[&>.rdg-cell:first-child>div]:ml-8'
)
}}
@@ -17,14 +17,14 @@ import * as React from 'react'
import {
Button,
Card,
Checkbox_Shadcn_,
Checkbox,
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
Input,
Input_Shadcn_ as Input,
Table,
TableBody,
TableCell,
@@ -78,7 +78,7 @@ export const columns: ColumnDef<Payment>[] = [
{
id: 'select',
header: ({ table }) => (
<Checkbox_Shadcn_
<Checkbox
checked={
table.getIsAllPageRowsSelected() ||
(table.getIsSomePageRowsSelected() ? 'indeterminate' : false)
@@ -88,7 +88,7 @@ export const columns: ColumnDef<Payment>[] = [
/>
),
cell: ({ row }) => (
<Checkbox_Shadcn_
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
@@ -196,7 +196,7 @@ export default function DataTableDemo() {
placeholder="Filter by email"
value={(table.getColumn('email')?.getFilterValue() as string) ?? ''}
onChange={(event) => table.getColumn('email')?.setFilterValue(event.target.value)}
className="max-w-sm"
className="max-w-xs"
/>
<DropdownMenu>
<DropdownMenuTrigger asChild>
@@ -1,4 +1,4 @@
import { Checkbox_Shadcn_ as Checkbox } from 'ui'
import { Checkbox } from 'ui'
import {
Field,
FieldContent,
@@ -1,4 +1,4 @@
import { Button, Checkbox_Shadcn_ as Checkbox, Input, Textarea } from 'ui'
import { Button, Checkbox, Input_Shadcn_ as Input, Textarea } from 'ui'
import {
Field,
FieldDescription,
@@ -1,4 +1,4 @@
import { Input } from 'ui'
import { Input_Shadcn_ as Input } from 'ui'
import {
Field,
FieldDescription,
@@ -1,4 +1,4 @@
import { Checkbox_Shadcn_ as Checkbox } from 'ui'
import { Checkbox } from 'ui'
import {
Field,
FieldDescription,
@@ -1,4 +1,4 @@
import { Card, CardContent, Checkbox_Shadcn_ as Checkbox } from 'ui'
import { Card, CardContent, Checkbox } from 'ui'
import {
Field,
FieldDescription,
@@ -42,16 +42,16 @@ export function FieldHear() {
</FieldDescription>
<FieldGroup className="flex flex-row flex-wrap gap-2 [--radius:9999rem]">
{options.map((option) => (
<FieldLabel htmlFor={option.value} key={option.value} className="!w-fit">
<FieldLabel htmlFor={option.value} key={option.value} className="w-fit!">
<Field
orientation="horizontal"
className="gap-1.5 overflow-hidden !px-3 !py-1.5 transition-all duration-100 ease-linear group-has-data-[state=checked]/field-label:!px-2"
className="gap-1.5 overflow-hidden px-3! py-1.5! transition-all duration-100 ease-linear group-has-data-checked/field-label:px-2!"
>
<Checkbox
value={option.value}
id={option.value}
defaultChecked={option.value === 'social-media'}
className="-ml-6 -translate-x-1 rounded-full transition-all duration-100 ease-linear data-[state=checked]:ml-0 data-[state=checked]:translate-x-0"
className="-ml-6 -translate-x-1 rounded-full transition-all duration-100 ease-linear data-checked:ml-0 data-checked:translate-x-0"
/>
<FieldTitle>{option.label}</FieldTitle>
</Field>
@@ -1,4 +1,4 @@
import { Input } from 'ui'
import { Input_Shadcn_ as Input } from 'ui'
import {
Field,
FieldDescription,
@@ -1,4 +1,4 @@
import { Button, Input, Textarea } from 'ui'
import { Button, Input_Shadcn_ as Input, Textarea } from 'ui'
import {
Field,
FieldContent,
@@ -1,6 +1,6 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { Button, Checkbox_Shadcn_, Form, FormControl, FormField } from 'ui'
import { Button, Checkbox, Form, FormControl, FormField } from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { z } from 'zod'
@@ -77,7 +77,7 @@ export default function FormItemLayoutDemo() {
hideMessage
>
<FormControl>
<Checkbox_Shadcn_
<Checkbox
checked={field.value?.includes(item.id)}
onCheckedChange={(checked) => {
return checked
@@ -1,6 +1,6 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { useForm } from 'react-hook-form'
import { Badge, Button, Checkbox_Shadcn_, Form, FormControl, FormField } from 'ui'
import { Badge, Button, Checkbox, Form, FormControl, FormField } from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { z } from 'zod'
@@ -34,7 +34,7 @@ export default function FormItemLayoutDemo() {
layout="flex"
>
<FormControl>
<Checkbox_Shadcn_ checked={field.value} onCheckedChange={field.onChange} />
<Checkbox checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItemLayout>
)}
@@ -9,7 +9,7 @@ import {
Card,
CardContent,
CardFooter,
Checkbox_Shadcn_,
Checkbox,
Form,
FormControl,
FormField,
@@ -439,7 +439,7 @@ export default function FormPatternsPageLayout() {
{uploadedFiles.map((file, idx) => (
<div
key={`${file.name}-${idx}`}
className="flex items-center justify-between gap-2 p-2 bg rounded border"
className="flex items-center justify-between gap-2 p-2 bg rounded-sm border"
>
<span className="text-sm text-foreground-light truncate flex-1">
{file.name}
@@ -499,7 +499,7 @@ export default function FormPatternsPageLayout() {
render={({ field }) => (
<div className="flex items-center w-full justify-start space-x-2">
<FormControl>
<Checkbox_Shadcn_
<Checkbox
id="enable-rls"
checked={field.value}
onCheckedChange={field.onChange}
@@ -520,7 +520,7 @@ export default function FormPatternsPageLayout() {
render={({ field }) => (
<div className="flex items-center w-full justify-start space-x-2">
<FormControl>
<Checkbox_Shadcn_
<Checkbox
id="enable-notifications"
checked={field.value}
onCheckedChange={field.onChange}
@@ -541,7 +541,7 @@ export default function FormPatternsPageLayout() {
render={({ field }) => (
<div className="flex items-center w-full justify-start space-x-2">
<FormControl>
<Checkbox_Shadcn_
<Checkbox
id="enable-analytics"
checked={field.value}
onCheckedChange={field.onChange}
@@ -6,7 +6,7 @@ import { useForm } from 'react-hook-form'
import {
Button,
Calendar,
Checkbox_Shadcn_,
Checkbox,
Form,
FormControl,
FormField,
@@ -139,7 +139,7 @@ export default function FormPatternsSidePanel() {
<form
id={formId}
onSubmit={form.handleSubmit(onSubmit)}
className="overflow-auto flex-grow px-0"
className="overflow-auto grow px-0"
>
{/* Text Input */}
<SheetSection>
@@ -424,7 +424,7 @@ export default function FormPatternsSidePanel() {
{uploadedFiles.map((file, idx) => (
<div
key={`${file.name}-${idx}`}
className="flex items-center justify-between gap-2 p-2 bg rounded border"
className="flex items-center justify-between gap-2 p-2 bg rounded-sm border"
>
<span className="text-sm text-foreground-light truncate flex-1">
{file.name}
@@ -484,7 +484,7 @@ export default function FormPatternsSidePanel() {
render={({ field }) => (
<div className="flex items-center w-full justify-start space-x-2">
<FormControl>
<Checkbox_Shadcn_
<Checkbox
id="enable-rls"
checked={field.value}
onCheckedChange={field.onChange}
@@ -505,7 +505,7 @@ export default function FormPatternsSidePanel() {
render={({ field }) => (
<div className="flex items-center w-full justify-start space-x-2">
<FormControl>
<Checkbox_Shadcn_
<Checkbox
id="enable-notifications"
checked={field.value}
onCheckedChange={field.onChange}
@@ -526,7 +526,7 @@ export default function FormPatternsSidePanel() {
render={({ field }) => (
<div className="flex items-center w-full justify-start space-x-2">
<FormControl>
<Checkbox_Shadcn_
<Checkbox
id="enable-analytics"
checked={field.value}
onCheckedChange={field.onChange}
@@ -607,7 +607,7 @@ export default function FormPatternsSidePanel() {
badgeLimit="wrap"
showIcon={false}
deletableBadge
className="w-full !min-w-lg"
className="w-full min-w-lg!"
/>
<MultiSelectorContent>
<MultiSelectorList>
@@ -55,7 +55,7 @@ export default function InnerSideMenuEmpty() {
<Heart className="text-light" size={13} />
</div>
<Pointer
className="absolute -right-[6px] -bottom-2 text-lighter"
className="absolute right-[-6px] -bottom-2 text-lighter"
strokeWidth={1.5}
size={16}
/>
@@ -12,7 +12,7 @@ import {
FormItem,
FormLabel,
FormMessage,
Input,
Input_Shadcn_ as Input,
} from 'ui'
import { z } from 'zod'
@@ -1,10 +1,10 @@
import { Checkbox_Shadcn_, Label_Shadcn_ } from 'ui'
import { Checkbox, Label_Shadcn_ } from 'ui'
export default function LabelDemo() {
return (
<div>
<div className="flex items-center space-x-2">
<Checkbox_Shadcn_ id="terms" />
<Checkbox id="terms" />
<Label_Shadcn_ htmlFor="terms">Accept terms and conditions</Label_Shadcn_>
</div>
</div>
@@ -0,0 +1,71 @@
import { useState } from 'react'
import {
Button,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
DialogTrigger,
Label_Shadcn_,
} from 'ui'
import {
MultiSelector,
MultiSelectorContent,
MultiSelectorItem,
MultiSelectorList,
MultiSelectorTrigger,
} from 'ui-patterns/multi-select'
export default function MultiSelectDemo() {
const [selectedValues, setSelectedValues] = useState<string[]>([])
const fruits = [
{ value: 'Apple', isDisabled: false },
{ value: 'Banana', isDisabled: false },
{ value: 'Cherry', isDisabled: false },
{ value: 'Date', isDisabled: false },
{ value: 'Elderberrie', isDisabled: false },
{ value: 'Fig', isDisabled: false },
{ value: 'Grape', isDisabled: false },
{ value: 'Kiwi', isDisabled: true },
{ value: 'Mango', isDisabled: false },
{ value: 'Strawberry', isDisabled: false },
]
return (
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Choose your fruits</DialogTitle>
<DialogDescription>Select the fruits you like.</DialogDescription>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="space-y-4">
<div>
<Label_Shadcn_ htmlFor="fruits">Fruits</Label_Shadcn_>
<MultiSelector id="fruits" values={selectedValues} onValuesChange={setSelectedValues}>
<MultiSelectorTrigger label="Select fruits" badgeLimit="wrap" showIcon={false} />
<MultiSelectorContent>
<MultiSelectorList>
{fruits.map(({ value, isDisabled }) => (
<MultiSelectorItem key={value} value={value} disabled={isDisabled}>
{value}
</MultiSelectorItem>
))}
</MultiSelectorList>
</MultiSelectorContent>
</MultiSelector>
</div>
</DialogSection>
<DialogFooter>
<Button>Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
@@ -65,7 +65,7 @@ export default function NavigationMenuDemo() {
<li className="row-span-3">
<NavigationMenuLink asChild>
<a
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b border from-background-surface-100/20 to-background-surface-100 p-6 no-underline outline-none focus:shadow-md"
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-linear-to-b border from-background-surface-100/20 to-background-surface-100 p-6 no-underline outline-hidden focus:shadow-md"
href="/"
>
{/* <Icons.logo className="h-6 w-6" /> */}
@@ -125,7 +125,7 @@ const ListItem = React.forwardRef<React.ElementRef<'a'>, React.ComponentPropsWit
<a
ref={ref}
className={cn(
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-surface-100/50 hover:text-foreground focus:bg-surface-100/50 focus:text-foreground',
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-hidden transition-colors hover:bg-surface-100/50 hover:text-foreground focus:bg-surface-100/50 focus:text-foreground',
className
)}
{...props}
@@ -66,7 +66,7 @@ export default function NavigationMenuDemo() {
<li className="row-span-3">
<NavigationMenuLink asChild>
<a
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md"
className="flex h-full w-full select-none flex-col justify-end rounded-md bg-linear-to-b from-muted/50 to-muted p-6 no-underline outline-hidden focus:shadow-md"
href="/"
>
{/* <Icons.logo className="h-6 w-6" /> */}
@@ -170,7 +170,7 @@ const ListItem = React.forwardRef<React.ElementRef<'a'>, React.ComponentPropsWit
<a
ref={ref}
className={cn(
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-surface-100 hover:text-accent-foreground focus:bg-surface-100 focus:text-accent-foreground',
'block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-hidden transition-colors hover:bg-surface-100 hover:text-accent-foreground focus:bg-surface-100 focus:text-accent-foreground',
className
)}
{...props}
@@ -8,7 +8,9 @@ import {
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
Input,
InputGroup,
InputGroupAddon,
InputGroupInput,
Table,
TableBody,
TableCell,
@@ -68,12 +70,16 @@ export default function PageLayoutList() {
<div className="w-full space-y-4">
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-2 flex-wrap">
<div className="flex flex-col lg:flex-row lg:items-center gap-2">
<Input
placeholder="Search for a function"
size="tiny"
icon={<Search />}
className="w-full lg:w-52"
/>
<InputGroup>
<InputGroupInput
placeholder="Search for a function"
size="tiny"
className="w-full lg:w-52"
/>
<InputGroupAddon>
<Search />
</InputGroupAddon>
</InputGroup>
</div>
<Button type="primary">Create a new function</Button>
</div>
@@ -1,20 +1,20 @@
import { Label_Shadcn_, RadioGroup_Shadcn_, RadioGroupItem_Shadcn_ } from 'ui'
import { Label_Shadcn_, RadioGroup, RadioGroupItem } from 'ui'
export default function RadioGroupDemo() {
return (
<RadioGroup_Shadcn_ defaultValue="comfortable">
<RadioGroup defaultValue="comfortable">
<div className="flex items-center space-x-2">
<RadioGroupItem_Shadcn_ value="default" id="r1" />
<RadioGroupItem value="default" id="r1" />
<Label_Shadcn_ htmlFor="r1">Default</Label_Shadcn_>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem_Shadcn_ value="comfortable" id="r2" />
<RadioGroupItem value="comfortable" id="r2" />
<Label_Shadcn_ htmlFor="r2">Comfortable</Label_Shadcn_>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem_Shadcn_ value="compact" id="r3" />
<RadioGroupItem value="compact" id="r3" />
<Label_Shadcn_ htmlFor="r3">Compact</Label_Shadcn_>
</div>
</RadioGroup_Shadcn_>
</RadioGroup>
)
}
@@ -11,8 +11,8 @@ import {
FormItem,
FormLabel,
FormMessage,
RadioGroup_Shadcn_,
RadioGroupItem_Shadcn_,
RadioGroup,
RadioGroupItem,
} from 'ui'
import { z } from 'zod'
@@ -47,30 +47,30 @@ export default function RadioGroupForm() {
<FormItem className="space-y-3">
<FormLabel>Notify me about...</FormLabel>
<FormControl>
<RadioGroup_Shadcn_
<RadioGroup
onValueChange={field.onChange}
defaultValue={field.value}
className="flex flex-col space-y-1"
>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem_Shadcn_ value="all" />
<RadioGroupItem value="all" />
</FormControl>
<FormLabel className="font-normal">All new messages</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem_Shadcn_ value="mentions" />
<RadioGroupItem value="mentions" />
</FormControl>
<FormLabel className="font-normal">Direct messages and mentions</FormLabel>
</FormItem>
<FormItem className="flex items-center space-x-3 space-y-0">
<FormControl>
<RadioGroupItem_Shadcn_ value="none" />
<RadioGroupItem value="none" />
</FormControl>
<FormLabel className="font-normal">Nothing</FormLabel>
</FormItem>
</RadioGroup_Shadcn_>
</RadioGroup>
</FormControl>
<FormMessage />
</FormItem>
@@ -32,7 +32,7 @@ export default function ScrollAreaHorizontalDemo() {
<Image
src={artwork.art}
alt={`Photo by ${artwork.artist}`}
className="aspect-[3/4] h-fit w-fit object-cover"
className="aspect-3/4 h-fit w-fit object-cover"
width={300}
height={400}
/>
@@ -24,7 +24,7 @@ export default function SheetDemo() {
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>Make changes to your profile here.</SheetDescription>
</SheetHeader>
<div className="overflow-auto flex-grow px-0">
<div className="overflow-auto grow px-0">
<SheetSection>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
@@ -20,7 +20,7 @@ export default function SheetNonmodal() {
<SheetHeader>
<SheetTitle>Log details</SheetTitle>
</SheetHeader>
<div className="overflow-auto flex-grow px-0">
<div className="overflow-auto grow px-0">
<SheetSection>
<p className="text-sm text-foreground-lighter">
This sheet does not block the underlying content, but it does overlap it.
@@ -149,7 +149,7 @@ const TocComponent = () => {
<h3 className="inline-flex items-center gap-1.5 font-mono text-xs uppercase text-foreground pl-[calc(1.5rem+6px)]">
On this page
</h3>
<TOCScrollArea className="-ml-[2px]">
<TOCScrollArea className="ml-[-2px]">
<TOCItems items={toc} />
</TOCScrollArea>
</Toc>
@@ -149,7 +149,7 @@ const TocComponent = () => {
<h3 className="inline-flex items-center gap-1.5 font-mono text-xs uppercase text-foreground pl-[calc(1.5rem+6px)]">
On this page
</h3>
<TOCScrollArea className="-ml-[2px]">
<TOCScrollArea className="ml-[-2px]">
<TOCItems items={toc} />
</TOCScrollArea>
</Toc>
@@ -4,7 +4,7 @@ export default function TypographyDemo() {
<h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
The Joke Tax Chronicles
</h1>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
Once upon a time, in a far-off land, there was a very lazy king who spent all day lounging
on his throne. One day, his advisors came to him with a problem: the kingdom was running out
of money.
@@ -12,7 +12,7 @@ export default function TypographyDemo() {
<h2 className="mt-10 scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0">
The King&apos;s Plan
</h2>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
The king thought long and hard, and finally came up with{' '}
<a href="#" className="font-medium text-primary underline underline-offset-4">
a brilliant plan
@@ -24,7 +24,7 @@ export default function TypographyDemo() {
that they should pay for the privilege.&quot;
</blockquote>
<h3 className="mt-8 scroll-m-20 text-2xl font-semibold tracking-tight">The Joke Tax</h3>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
The king&apos;s subjects were not amused. They grumbled and complained, but the king was
firm:
</p>
@@ -33,7 +33,7 @@ export default function TypographyDemo() {
<li>2nd level of jokes: 10 gold coins</li>
<li>3rd level of one-liners : 20 gold coins</li>
</ul>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
As a result, people stopped telling jokes, and the kingdom fell into a gloom. But there was
one person who refused to let the king&apos;s foolishness get him down: a court jester named
Jokester.
@@ -41,12 +41,12 @@ export default function TypographyDemo() {
<h3 className="mt-8 scroll-m-20 text-2xl font-semibold tracking-tight">
Jokester&apos;s Revolt
</h3>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
Jokester began sneaking into the castle in the middle of the night and leaving jokes all
over the place: under the king&apos;s pillow, in his soup, even in the royal toilet. The
king was furious, but he couldn&apos;t seem to stop Jokester.
</p>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
And then, one day, the people of the kingdom discovered that the jokes left by Jokester were
so funny that they couldn&apos;t help but laugh. And once they started laughing, they
couldn&apos;t stop.
@@ -54,7 +54,7 @@ export default function TypographyDemo() {
<h3 className="mt-8 scroll-m-20 text-2xl font-semibold tracking-tight">
The People&apos;s Rebellion
</h3>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
The people of the kingdom, feeling uplifted by the laughter, started to tell jokes and puns
again, and soon the entire kingdom was in on the joke.
</p>
@@ -62,48 +62,48 @@ export default function TypographyDemo() {
<table className="w-full">
<thead>
<tr className="m-0 border-t p-0 even:bg-muted">
<th className="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right">
<th className="border px-4 py-2 text-left font-bold [[align=center]]:text-center [[align=right]]:text-right">
King&apos;s Treasury
</th>
<th className="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right">
<th className="border px-4 py-2 text-left font-bold [[align=center]]:text-center [[align=right]]:text-right">
People&apos;s happiness
</th>
</tr>
</thead>
<tbody>
<tr className="m-0 border-t p-0 even:bg-muted">
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Empty
</td>
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Overflowing
</td>
</tr>
<tr className="m-0 border-t p-0 even:bg-muted">
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Modest
</td>
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Satisfied
</td>
</tr>
<tr className="m-0 border-t p-0 even:bg-muted">
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Full
</td>
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Ecstatic
</td>
</tr>
</tbody>
</table>
</div>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
The king, seeing how much happier his subjects were, realized the error of his ways and
repealed the joke tax. Jokester was declared a hero, and the kingdom lived happily ever
after.
</p>
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
The moral of the story is: never underestimate the power of a good laugh and always be
careful of bad ideas.
</p>
@@ -1,6 +1,6 @@
export default function TypographyInlineCode() {
return (
<code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
<code className="relative rounded-sm bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
@radix-ui/react-alert-dialog
</code>
)
@@ -1,6 +1,6 @@
export default function TypographyP() {
return (
<p className="leading-7 [&:not(:first-child)]:mt-6">
<p className="leading-7 not-first:mt-6">
The king, seeing how much happier his subjects were, realized the error of his ways and
repealed the joke tax.
</p>
@@ -4,36 +4,36 @@ export default function TypographyTable() {
<table className="w-full">
<thead>
<tr className="m-0 border-t p-0 even:bg-muted">
<th className="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right">
<th className="border px-4 py-2 text-left font-bold [[align=center]]:text-center [[align=right]]:text-right">
King&apos;s Treasury
</th>
<th className="border px-4 py-2 text-left font-bold [&[align=center]]:text-center [&[align=right]]:text-right">
<th className="border px-4 py-2 text-left font-bold [[align=center]]:text-center [[align=right]]:text-right">
People&apos;s happiness
</th>
</tr>
</thead>
<tbody>
<tr className="m-0 border-t p-0 even:bg-muted">
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Empty
</td>
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Overflowing
</td>
</tr>
<tr className="m-0 border-t p-0 even:bg-muted">
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Modest
</td>
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Satisfied
</td>
</tr>
<tr className="m-0 border-t p-0 even:bg-muted">
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Full
</td>
<td className="border px-4 py-2 text-left [&[align=center]]:text-center [&[align=right]]:text-right">
<td className="border px-4 py-2 text-left [[align=center]]:text-center [[align=right]]:text-right">
Ecstatic
</td>
</tr>
+17
View File
@@ -25,12 +25,24 @@ export const examples: Registry = [
registryDependencies: ['admonition'],
files: ['example/admonition-button.tsx'],
},
{
name: 'admonition-description-only',
type: 'components:example',
registryDependencies: ['admonition'],
files: ['example/admonition-description-only.tsx'],
},
{
name: 'admonition-warning',
type: 'components:example',
registryDependencies: ['admonition'],
files: ['example/admonition-warning.tsx'],
},
{
name: 'admonition-success',
type: 'components:example',
registryDependencies: ['admonition'],
files: ['example/admonition-success.tsx'],
},
{
name: 'admonition-destructive',
type: 'components:example',
@@ -1418,6 +1430,11 @@ export const examples: Registry = [
type: 'components:example',
files: ['example/multi-select-inline-search-input.tsx'],
},
{
name: 'multi-select-in-dialog',
type: 'components:example',
files: ['example/multi-select-in-dialog.tsx'],
},
{
name: 'tree-view-demo',
type: 'components:example',
+18 -7
View File
@@ -1,11 +1,18 @@
@import './../../../packages/ui/build/css/source/global.css';
@import './../../../packages/ui/build/css/themes/dark.css';
@import 'config/tailwind.config.css';
@import './../../../packages/ui/build/css/themes/classic-dark.css';
@import './../../../packages/ui/build/css/themes/light.css';
@import 'config/typography.css';
@tailwind base;
@tailwind components;
@tailwind utilities;
@source '../app/**/*.{js,ts,jsx,tsx}';
@source '../components/**/*.{js,ts,jsx,tsx}';
@source '../registry/**/*.{js,ts,jsx,tsx}';
@source '../content/**/*.mdx';
@source './../../../packages/ui/src/**/*.{tsx,ts,js}';
@source './../../../packages/ui-patterns/src/**/*.{tsx,ts,js}';
@theme {
/* added to get max-w-site */
--container-site: 128rem;
}
@layer base {
:root {
@@ -33,7 +40,7 @@
@apply scroll-smooth;
}
body {
@apply bg text-foreground;
@apply bg-default text-foreground;
/* font-feature-settings: "rlig" 1, "calt" 1; */
font-synthesis-weight: none;
text-rendering: optimizeLegibility;
@@ -68,3 +75,7 @@
@apply px-4;
}
}
.rdg-cell {
padding-inline: 0.5rem;
}
+2
View File
@@ -1,3 +1,5 @@
@reference './globals.css';
/* [data-theme="light"] {
display: block;
} */
-21
View File
@@ -1,21 +0,0 @@
const config = require('config/tailwind.config')
module.exports = config({
content: [
'./app/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./registry/**/*.{js,ts,jsx,tsx}',
// purge styles from grid library
//
'./../../packages/ui/src/**/*.{tsx,ts,js}',
'./../../packages/ui-patterns/src/**/*.{tsx,ts,js}',
],
plugins: [require('@tailwindcss/container-queries')],
theme: {
extend: {
maxWidth: {
site: '128rem',
},
},
},
})
+86 -5
View File
@@ -1,14 +1,15 @@
import { promises as fs } from 'fs'
import path from 'path'
import { promises as fs } from 'node:fs'
import path from 'node:path'
import { BASE_PATH, IS_PRODUCTION, PROD_URL } from '~/lib/constants'
import { NextResponse } from 'next/server'
export async function GET(_request: Request, { params }: { params: Promise<{ slug: string[] }> }) {
export async function GET(request: Request, { params }: { params: Promise<{ slug: string[] }> }) {
const { slug } = await params
const baseDir = path.join(process.cwd(), 'public/docs/guides')
const filePath = path.join(baseDir, `${slug.join('/')}.md`)
if (!filePath.startsWith(baseDir + path.sep) && filePath !== baseDir) {
return new NextResponse('Not found', { status: 404 })
return notFoundResponse(request, slug)
}
try {
@@ -20,6 +21,86 @@ export async function GET(_request: Request, { params }: { params: Promise<{ slu
},
})
} catch {
return new NextResponse('Not found', { status: 404 })
return notFoundResponse(request, slug)
}
}
/**
* Resolves the docs base URL from trusted sources only.
* Avoids host-header-driven SSRF from request origin.
*/
function resolveDocsBaseUrl() {
if (IS_PRODUCTION) return PROD_URL
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}${BASE_PATH}`
if (process.env.NEXT_PUBLIC_SITE_URL) return `${process.env.NEXT_PUBLIC_SITE_URL}${BASE_PATH}`
return undefined
}
async function notFoundResponse(_request: Request, slug: string[]) {
const baseUrl = resolveDocsBaseUrl()
const query = slug.join(' ').replace(/[_-]/g, ' ')
const suggestions = baseUrl ? await searchForSuggestions(baseUrl, query) : []
const markdown = buildNotFoundMarkdown(slug, suggestions)
return new NextResponse(markdown, {
status: 404,
headers: {
'Content-Type': 'text/markdown; charset=utf-8',
'Cache-Control': 'no-store',
},
})
}
interface SearchSuggestion {
title: string
href: string
}
async function searchForSuggestions(baseUrl: string, query: string): Promise<SearchSuggestion[]> {
try {
const response = await fetch(`${baseUrl}/api/graphql`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: `
query SearchDocs($query: String!) {
searchDocs(query: $query, limit: 5) {
nodes {
title
href
}
}
}
`,
variables: { query },
}),
})
if (!response.ok) return []
const data = await response.json()
return (data?.data?.searchDocs?.nodes ?? []).filter(
(n: Partial<SearchSuggestion>): n is SearchSuggestion => !!n.title && !!n.href
)
} catch {
return []
}
}
function buildNotFoundMarkdown(slug: string[], suggestions: SearchSuggestion[]): string {
const pagePath = slug.join('/')
const suggestionsMd =
suggestions.length > 0
? `## You might be looking for...\n\n${suggestions
.map(({ title, href }) => `- [${title}](${href}.md)`)
.join('\n')}\n`
: ''
return `# 404 - Page Not Found
The page \`/docs/guides/${pagePath}.md\` does not exist.
${suggestionsMd}
See also: [Changelog](https://supabase.com/changelog.md)
`
}
+1 -1
View File
@@ -29,5 +29,5 @@ export default function GraphiQLPage() {
notFound()
}
return <LazyGraphiQL className="!h-[calc(100vh-var(--header-height))]" />
return <LazyGraphiQL className="h-[calc(100vh-var(--header-height))]!" />
}
@@ -0,0 +1,26 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
const AiToolsGuidePage = async (props: { params: Promise<Params> }) => {
const params = await props.params
const slug = ['ai-tools', ...(params.slug ?? [])]
const data = await getGuidesMarkdown(slug)
return <GuideTemplate {...data!} />
}
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('ai-tools') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['ai-tools', ...(params.slug ?? [])])
)
export default AiToolsGuidePage
export { generateMetadata, generateStaticParams }
@@ -1,13 +1,13 @@
import { source } from 'common-tags'
import { notFound } from 'next/navigation'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import {
generateAiPromptMetadata,
generateAiPromptsStaticParams,
generateCursorPromptDeepLink,
getAiPrompt,
wrapInMarkdownCodeBlock,
} from './AiPrompts.utils'
} from '~/app/guides/getting-started/ai-prompts/[slug]/AiPrompts.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { source } from 'common-tags'
import { notFound } from 'next/navigation'
export const dynamicParams = false
@@ -50,6 +50,7 @@ export default async function AiPromptsPage(props: { params: Promise<{ slug: str
meta={{ title: `AI Prompt: ${heading}` }}
content={content}
editLink={newEditLink(`supabase/supabase/blob/master/examples/prompts/${slug}.md`)}
pathname={`/guides/ai-tools/ai-prompts/${slug}`}
/>
)
}
+5
View File
@@ -0,0 +1,5 @@
import Layout from '~/layouts/guides'
export default async function AiToolsLayout({ children }: { children: React.ReactNode }) {
return <Layout>{children}</Layout>
}
@@ -0,0 +1,15 @@
import SectionTroubleshootingPage, {
generateSectionTroubleshootingMetadata,
} from '~/features/docs/TroubleshootingSection.page'
export default async function AiToolsTroubleshootingPage() {
return (
<SectionTroubleshootingPage
topic="ai-tools"
sectionName="AI Tools"
description="Search or browse troubleshooting guides for common AI tools issues, including configuration, usage, and integration problems."
/>
)
}
export const metadata = generateSectionTroubleshootingMetadata('AI', 'AI Tools')
+4 -4
View File
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const AiGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('ai') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('ai') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['ai', ...(params.slug ?? [])])
)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const ApiGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('api') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('api') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['api', ...(params.slug ?? [])])
)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const AuthGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('auth') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('auth') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['auth', ...(params.slug ?? [])])
)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const CronGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('cron') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('cron') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['cron', ...(params.slug ?? [])])
)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const DatabaseGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('database') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('database') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['database', ...(params.slug ?? [])])
)
@@ -1,19 +1,18 @@
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { MDXRemoteBase } from '~/features/docs/MdxBase'
import { TabPanel, Tabs } from '~/features/ui/Tabs'
import { linkTransform, UrlTransformFunction } from '~/lib/mdx/plugins/rehypeLinkTransform'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import { getGitHubFileContents, octokit, OCTOKIT_RETRY_OPTIONS } from '~/lib/octokit'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
import { capitalize } from 'lodash-es'
import rehypeSlug from 'rehype-slug'
import { Heading } from 'ui'
import { Admonition } from 'ui-patterns'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { MDXRemoteBase } from '~/features/docs/MdxBase'
import { OCTOKIT_RETRY_OPTIONS, getGitHubFileContents, octokit } from '~/lib/octokit'
import { TabPanel, Tabs } from '~/features/ui/Tabs'
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
// We fetch these docs at build time from an external repo
const org = 'supabase'
const repo = 'splinter'
@@ -64,7 +63,7 @@ const DatabaseAdvisorDocs = async () => {
} as SerializeOptions
return (
<GuideTemplate meta={meta} editLink={editLink}>
<GuideTemplate meta={meta} editLink={editLink} pathname="/guides/database/database-advisors">
<MDXRemoteBase source={markdownIntro} />
<Heading tag="h2">Available checks</Heading>
@@ -87,7 +86,7 @@ const DatabaseAdvisorDocs = async () => {
.
</Admonition>
) : (
<Tabs listClassNames="flex flex-wrap gap-2 [&>button]:!m-0" queryGroup="lint">
<Tabs listClassNames="flex flex-wrap gap-2 [&>button]:m-0!" queryGroup="lint">
{lints.map((lint) => (
<TabPanel
key={lint.path}
@@ -1,15 +1,5 @@
import matter from 'gray-matter'
import Link from 'next/link'
import { notFound } from 'next/navigation'
import { readFile } from 'node:fs/promises'
import { join, relative } from 'node:path'
import rehypeSlug from 'rehype-slug'
import emoji from 'remark-emoji'
// End of third-party imports
import { IS_PROD, isFeatureEnabled } from 'common'
import { Button } from 'ui'
import { Admonition } from 'ui-patterns'
import {
genGuideMeta,
genGuidesStaticParams,
@@ -17,6 +7,9 @@ import {
} from '~/features/docs/GuidesMdx.utils'
import { newEditLink } from '~/features/helpers.edit-link'
import { Guide, GuideArticle, GuideFooter, GuideHeader, GuideMdxContent } from '~/features/ui/guide'
// End of third-party imports
import { IS_DEV } from '~/lib/constants'
import { GUIDES_DIRECTORY, isValidGuideFrontmatter } from '~/lib/docs'
import { linkTransform, type UrlTransformFunction } from '~/lib/mdx/plugins/rehypeLinkTransform'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
@@ -24,6 +17,14 @@ import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import { getGitHubFileContents, octokit } from '~/lib/octokit'
import type { SerializeOptions } from '~/types/next-mdx-remote-serialize'
import { isFeatureEnabled } from 'common'
import matter from 'gray-matter'
import Link from 'next/link'
import { notFound } from 'next/navigation'
import rehypeSlug from 'rehype-slug'
import emoji from 'remark-emoji'
import { Button } from 'ui'
import { Admonition } from 'ui-patterns'
// We fetch these docs at build time from an external repo
const org = 'supabase'
@@ -424,7 +425,7 @@ const urlTransform: UrlTransformFunction = (url) => {
}
const generateStaticParams = async () => {
if (IS_PROD) {
if (!IS_DEV) {
return []
}
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const DeploymentGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('deployment') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('deployment') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['deployment', ...(params.slug ?? [])])
)
@@ -1,24 +1,24 @@
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
import { isValidGuideFrontmatter } from '~/lib/docs'
import { linkTransform, UrlTransformFunction } from '~/lib/mdx/plugins/rehypeLinkTransform'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import { getGitHubFileContents } from '~/lib/octokit'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
import matter from 'gray-matter'
import { notFound } from 'next/navigation'
import rehypeSlug from 'rehype-slug'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils'
import { getGitHubFileContents } from '~/lib/octokit'
import { isValidGuideFrontmatter } from '~/lib/docs'
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import {
terraformDocsBranch,
terraformDocsDocsDir,
terraformDocsOrg,
terraformDocsRepo,
} from '../terraformConstants'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
// Each external docs page is mapped to a local page
const pageMap = [
@@ -143,7 +143,7 @@ const getContent = async ({ slug }: Params) => {
}
}
const generateStaticParams = IS_PROD
const generateStaticParams = !IS_DEV
? async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
: getEmptyArray
const generateMetadata = genGuideMeta(getContent)
@@ -156,7 +156,7 @@ function Resources({ schema }: { schema: any }) {
<li key={nestedAttribute}>
{nestedAttribute}
<ul>
<li className="*:!m-0">
<li className="*:m-0!">
<ReactMarkdown>
{
schema[resource].block.attributes[attribute].nested_type
@@ -285,7 +285,7 @@ function DataSources({ schema }: { schema: any }) {
<li key={nestedAttribute}>
{nestedAttribute}
<ul>
<li className="*:!m-0">
<li className="*:m-0!">
<ReactMarkdown>
{
schema[dataSource].block.attributes[attribute].nested_type
@@ -352,7 +352,11 @@ const TerraformReferencePage = async () => {
const editLink = newEditLink('supabase/terraform-provider-supabase')
return (
<GuideTemplate meta={meta} editLink={editLink}>
<GuideTemplate
meta={meta}
editLink={editLink}
pathname="/guides/deployment/terraform/reference"
>
The Terraform Provider provides access to{' '}
<Link
href="https://developer.hashicorp.com/terraform/language/resources"
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const FunctionsGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('functions') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('functions') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['functions', ...(params.slug ?? [])])
)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const GettingStartedGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('getting-started') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('getting-started') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['getting-started', ...(params.slug ?? [])])
)
@@ -1,5 +1,4 @@
import Link from 'next/link'
import { GlassPanel } from 'ui-patterns'
import { getAiPrompts } from './AiPrompts.utils'
@@ -12,7 +11,7 @@ export async function AiPromptsIndex() {
{prompts.map((prompt) => (
<Link
key={prompt.filename}
href={`/guides/getting-started/ai-prompts/${prompt.filename}`}
href={`/guides/ai-tools/ai-prompts/${prompt.filename}`}
passHref
>
<GlassPanel
@@ -1,17 +1,16 @@
import { notFound } from 'next/navigation'
import { isAbsolute, relative } from 'path'
import rehypeSlug from 'rehype-slug'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
import { getGitHubFileContents } from '~/lib/octokit'
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
import { linkTransform, UrlTransformFunction } from '~/lib/mdx/plugins/rehypeLinkTransform'
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
import { getGitHubFileContents } from '~/lib/octokit'
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { notFound } from 'next/navigation'
import rehypeSlug from 'rehype-slug'
// We fetch these docs at build time from an external repo
const org = 'supabase'
@@ -190,7 +189,7 @@ const urlTransform: UrlTransformFunction = (url) => {
}
}
const generateStaticParams = IS_PROD
const generateStaticParams = !IS_DEV
? async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
: getEmptyArray
const generateMetadata = genGuideMeta(getContent)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const IntegrationsGuidePage = async (props: { params: Promise<Params> }) => {
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('integrations') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('integrations') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['integrations', ...(params.slug ?? [])])
)
@@ -1,11 +1,11 @@
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import {
getGuidesMarkdown,
genGuideMeta,
genGuidesStaticParams,
getGuidesMarkdown,
} from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
import { IS_PROD } from 'common'
import { getEmptyArray } from '~/features/helpers.fn'
import { IS_DEV } from '~/lib/constants'
type Params = { slug?: string[] }
@@ -17,7 +17,7 @@ const LocalDevelopmentGuidePage = async (props: { params: Promise<Params> }) =>
return <GuideTemplate {...data!} />
}
const generateStaticParams = IS_PROD ? genGuidesStaticParams('local-development') : getEmptyArray
const generateStaticParams = !IS_DEV ? genGuidesStaticParams('local-development') : getEmptyArray
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
getGuidesMarkdown(['local-development', ...(params.slug ?? [])])
)
@@ -36,7 +36,7 @@ const Config = () => {
const editLink = newEditLink('supabase/supabase/blob/master/apps/docs/spec/cli_v1_config.yaml')
return (
<GuideTemplate meta={meta} editLink={editLink}>
<GuideTemplate meta={meta} editLink={editLink} pathname="/guides/local-development/cli/config">
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
<div>{content}</div>
</GuideTemplate>
Loaded 100 of 2752 files, more files were not shown because too many files have changed in this diff. Show more