mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 14:19:11 +03:00
Merge branch 'master' into chore/move-policies
This commit is contained in:
commit
6da91309ca
2752 files changed
+195264
-131909
No files matched your search
@@ -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'
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
} */
|
||||
@@ -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 }
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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" />
|
||||
@@ -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'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."
|
||||
</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'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'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'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's pillow, in his soup, even in the royal toilet. The
|
||||
king was furious, but he couldn'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't help but laugh. And once they started laughing, they
|
||||
couldn'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'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'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'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'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'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>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
@reference './globals.css';
|
||||
|
||||
/* [data-theme="light"] {
|
||||
display: block;
|
||||
} */
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -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)
|
||||
`
|
||||
}
|
||||
@@ -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 }
|
||||
+5
-4
@@ -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}`}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -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')
|
||||
@@ -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
Reference in new issue
Block a user