Merge branch 'master' into feat/mamba-d1-light-mode-imgs

This commit is contained in:
Terry Sutton committed 2025-03-31 11:58:19 -02:30
commit ca40c0f040
23 files changed
+167 -19

No files matched your search

@@ -22,6 +22,7 @@ import {
Separator,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { InlineLink } from 'components/ui/InlineLink'
interface CreateClerkAuthIntegrationProps {
visible: boolean
@@ -107,9 +108,13 @@ export const CreateClerkAuthIntegrationDialog = ({
<form id={FORM_ID} onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<p className="text-sm text-foreground-light">
Register your Clerk domain. Visit{' '}
<a href="https://dashboard.clerk.com/setup/supabase" target="_blank" rel="noopener">
<InlineLink
href="https://dashboard.clerk.com/setup/supabase"
target="_blank"
rel="noopener"
>
Clerk's Connect with Supabase page
</a>{' '}
</InlineLink>{' '}
to configure your Clerk instance.
</p>
<FormField_Shadcn_
+5 -2
View File
@@ -5,12 +5,15 @@ import { cn } from 'ui'
interface InlineLinkProps {
href: string
className?: string
target?: string
rel?: string
}
export const InlineLink = ({
href,
className: _className,
children,
...props
}: PropsWithChildren<InlineLinkProps>) => {
const className = cn(
'underline transition underline-offset-2 decoration-foreground-lighter hover:decoration-foreground text-foreground',
@@ -18,13 +21,13 @@ export const InlineLink = ({
)
if (href.startsWith('http')) {
return (
<a className={className} href={href} target="_blank" rel="noreferrer noopener">
<a className={className} href={href} target="_blank" rel="noreferrer noopener" {...props}>
{children}
</a>
)
}
return (
<Link className={className} href={href}>
<Link className={className} href={href} {...props}>
{children}
</Link>
)
+2 -1
View File
@@ -1,4 +1,5 @@
# Default to local supabase for local development
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
NEXT_PUBLIC_BASE_PATH=/ui
NEXT_PUBLIC_BASE_PATH=/ui
NEXT_PUBLIC_API_URL="http://localhost:8080/platform"
+2
View File
@@ -1,5 +1,6 @@
import { Sidebar } from '@/components/sidebar'
import { SiteFooter } from '@/components/site-footer'
import { TelemetryWrapper } from './telemetry-wrapper'
interface AppLayoutProps {
children: React.ReactNode
@@ -24,6 +25,7 @@ export default function AppLayout({ children }: AppLayoutProps) {
</main>
</div>
<SiteFooter />
<TelemetryWrapper />
</>
)
}
+2 -2
View File
@@ -76,7 +76,7 @@ export default function Home() {
</div>
<HorizontalGridLine />
<div className="col-start-2 col-span-10 md:col-start-3 md:col-span-8 relative">
<div className="-mt-4 flex rounded-lg overflow-hidden">
<div className="-mt-4 grid md:flex rounded-lg overflow-hidden">
<BlockPreview name="realtime-cursor-demo" isPair />
<BlockPreview name="realtime-cursor-demo" isPair />
</div>
@@ -149,7 +149,7 @@ export default function Home() {
</div>
<HorizontalGridLine />
<div className="col-start-2 col-span-10 md:col-start-3 md:col-span-8 relative">
<div className="-mt-4 flex rounded-lg overflow-hidden">
<div className="-mt-4 grid md:flex rounded-lg overflow-hidden">
<BlockPreview name="realtime-chat-demo" isPair />
<BlockPreview name="realtime-chat-demo" isPair />
</div>
@@ -0,0 +1,16 @@
'use client'
import { API_URL } from '@/lib/constants'
import { IS_PLATFORM, PageTelemetry } from 'common'
import { useConsent } from 'ui-patterns/ConsentToast'
export const TelemetryWrapper = () => {
const { hasAcceptedConsent } = useConsent()
return (
<PageTelemetry
API_URL={API_URL}
hasAcceptedConsent={hasAcceptedConsent}
enabled={IS_PLATFORM}
/>
)
}
+2 -1
View File
@@ -1,13 +1,14 @@
'use client'
import { AuthProvider } from 'common'
import { Provider as JotaiProvider } from 'jotai'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
import { ThemeProviderProps } from 'next-themes/dist/types'
import { FrameworkProvider } from '@/context/framework-context'
import { MobileMenuProvider } from '@/context/mobile-menu-context'
import { AuthProvider } from 'common'
import { TooltipProvider } from 'ui'
import { useConsent } from 'ui-patterns/ConsentToast'
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return (
+1 -1
View File
@@ -39,7 +39,7 @@ export function BlockPreview({ name, wide = false, isPair = false }: ComponentPr
<div className={cn('mt-4 w-full', wideClasses)}>
<div
className={cn(
'relative border rounded-lg overflow-hidden bg-muted min-h-[350px] h-[600px]',
'relative border rounded-lg overflow-hidden bg-muted min-h-[150px] h-[600px]',
isPair && 'rounded-none'
)}
>
@@ -2,10 +2,13 @@
import { Check, Copy } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useSendTelemetryEvent } from 'lib/telemetry'
import { Button_Shadcn_ } from 'ui'
export function CommandCopyButton({ command }: { command: string }) {
const [copied, setCopied] = useState(false)
const sendTelemetryEvent = useSendTelemetryEvent()
useEffect(() => {
if (copied) {
@@ -14,13 +17,56 @@ export function CommandCopyButton({ command }: { command: string }) {
}
}, [copied])
const parseCommandForTelemetry = (cmd: string) => {
// Extract framework from URL (e.g., 'nextjs' from 'password-based-auth-nextjs.json')
const frameworkMatch = cmd.match(/\/ui\/r\/.*?-(\w+)\.json/)
const framework = frameworkMatch
? (frameworkMatch[1] as 'nextjs' | 'react-router' | 'tanstack' | 'react')
: 'nextjs'
// Extract package manager from command prefix (npx, pnpm, yarn, bun)
const packageManager = cmd.startsWith('npx')
? ('npm' as const)
: cmd.startsWith('pnpm')
? ('pnpm' as const)
: cmd.startsWith('yarn')
? ('yarn' as const)
: cmd.startsWith('bun')
? ('bun' as const)
: ('npm' as const)
// Extract template title from URL (e.g., 'password-based-auth' from 'password-based-auth-nextjs.json')
const titleMatch = cmd.match(/\/ui\/r\/(.*?)-\w+\.json/)
const title = titleMatch ? titleMatch[1] : ''
return {
framework,
packageManager,
title,
}
}
return (
<Button_Shadcn_
variant="ghost"
size="icon"
onClick={() => {
// Copy command to clipboard
navigator.clipboard.writeText(command)
setCopied(true)
// Parse command and send telemetry event
const { framework, packageManager, title } = parseCommandForTelemetry(command)
sendTelemetryEvent({
action: 'supabase_ui_command_copy_button_clicked',
properties: {
templateTitle: title,
command: command,
framework,
packageManager,
},
})
}}
>
{copied ? <Check className="h-4 w-4" /> : <Copy className="h-4 w-4" />}
@@ -31,6 +31,7 @@ import {
TabsList_Shadcn_ as TabsList,
TabsTrigger_Shadcn_ as TabsTrigger,
} from 'ui'
import TanStackBeta from '@/components/tanstack-beta'
import { Admonition } from 'ui-patterns/admonition'
import { BlockItem } from './block-item'
import { BlockPreview } from './block-preview'
@@ -248,6 +249,7 @@ const components = {
{...props}
/>
),
TanStackBeta,
// FrameworkDocs: ({ className, ...props }: React.ComponentProps<typeof FrameworkDocs>) => (
// <FrameworkDocs className={cn(className)} {...props} />
// ),
@@ -257,7 +259,7 @@ const components = {
LinkedCard: ({ className, ...props }: React.ComponentProps<typeof Link>) => (
<Link
className={cn(
'flex w-full flex-col items-center rounded-xl border bg-surface-100 text-card-background p-6 shadow transition-colors hover:bg-muted/50 sm:p-10',
'flex w-full flex-col items-center rounded-xl border bg-surface-100 text-card-background py-6 px-4 shadow transition-colors hover:bg-muted/50 sm:p-10',
className
)}
{...props}
@@ -0,0 +1,29 @@
import { TriangleAlert } from 'lucide-react'
import { Callout } from './callout'
export default function TanStackBeta() {
return (
<div className="mt-4">
<Callout>
<div className="grid gap-2">
<div className="flex items-center gap-2 font-medium">
<TriangleAlert />
Heads up: TanStack Start is in beta.
</div>
We&apos;re excited to support TanStack Start in our UI library! But since it&apos;s still
in beta, things may change quickly — expect breaking changes and some rough edges.
We&apos;ll do our best to keep up and make integration with Supabase as smooth as
possible. If you run into issues, have a look at the TanStack docs.
<a
href="https://tanstack.com/start/latest/docs/framework/react/quick-start"
target="_blank"
rel="noopener noreferrer"
className="text-foreground underline decoration-1 decoration-foreground-muted underline-offset-4 transition-colors hover:decoration-brand hover:decoration-2"
>
TanStack Quickstart guide
</a>
</div>
</Callout>
</div>
)
}
@@ -60,6 +60,8 @@ If you're already using a recent version of shadcn/ui in your existing project,
</LinkedCard>
</div>
<TanStackBeta />
When you've finished setting up shadcn/ui, you can start exploring the components in the sidebar
## Troubleshooting
@@ -7,6 +7,8 @@ description: Supabase client for TanStack Start
<BlockItem name="supabase-client-tanstack" description="Supabase Client for TanStack Start" />
<TanStackBeta />
## Folder structure
<RegistryBlock itemName="supabase-client-tanstack" />
+1
View File
@@ -0,0 +1 @@
export const API_URL = process.env.NEXT_PUBLIC_API_URL!
+19
View File
@@ -0,0 +1,19 @@
'use client'
import { usePathname } from 'next/navigation'
import { useCallback } from 'react'
import { sendTelemetryEvent } from 'common'
import { TelemetryEvent } from 'common/telemetry-constants'
import { API_URL } from 'lib/constants'
export function useSendTelemetryEvent() {
const pathname = usePathname()
return useCallback(
(event: TelemetryEvent) => {
return sendTelemetryEvent(API_URL, event, pathname)
},
[pathname]
)
}
@@ -58,10 +58,10 @@ const RealtimeChatDemo = () => {
return (
<div className="flex flex-col w-full h-[600px] p-4">
<div className="p-4">
<Label className="text-xs font-medium mb-1 ml-1 text-foreground-light">Username</Label>
<Label className="text-xs font-medium mb-1 -ml-4 text-foreground-light">Username</Label>
<Input
autoComplete="off"
className="text-sm"
className="text-sm -ml-4"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
@@ -18,7 +18,7 @@ const RealtimeCursorDemo = () => {
return (
<div className="flex flex-col w-44">
<Label>Username</Label>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 mt-1">
<Input value={username} onChange={(e) => setUsername(e.target.value)} disabled />
<Button
variant="secondary"
@@ -56,10 +56,10 @@ One more thing: today we're making Third-party Auth cheaper so that it has prici
You can have up to 50,000 MAU on the Free plan, or 100,000 MAU on the Pro plan and $0.00325 per MAU above that number.
| | Free Plan | Pro Plan |
| ---------- | ---------------- | --------------------- |
| Previously | 50 MAUs included | 50,000 MAUs included |
| Now | 50 MAUs included | 100,000 MAUs included |
| | Free Plan | Pro Plan |
| ---------- | -------------------- | --------------------- |
| Previously | 50 MAUs included | 50,000 MAUs included |
| Now | 50,000 MAUs included | 100,000 MAUs included |
## Get started today
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

+18
View File
@@ -1223,6 +1223,23 @@ export interface EdgeFunctionTestSidePanelOpenedEvent {
}
}
/**
* User copied the command for a Supabase UI component.
*
* @group Events
* @source supabase-ui
* @page /ui/docs/{framework}/{templateTitle}
*/
export interface SupabaseUiCommandCopyButtonClickedEvent {
action: 'supabase_ui_command_copy_button_clicked'
properties: {
templateTitle: string
command: string
framework: 'nextjs' | 'react-router' | 'tanstack' | 'react'
packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun'
}
}
/**
* @hidden
*/
@@ -1297,3 +1314,4 @@ export type TelemetryEvent =
| EdgeFunctionDeployUpdatesButtonClickedEvent
| EdgeFunctionTestSendButtonClickedEvent
| EdgeFunctionTestSidePanelOpenedEvent
| SupabaseUiCommandCopyButtonClickedEvent
@@ -24,13 +24,13 @@ const AccordionTrigger = React.forwardRef<
<AccordionPrimitive.Trigger
ref={ref}
className={cn(
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
'flex flex-1 gap-2 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180 text-left',
className
)}
{...props}
>
{children}
{!hideIcon && <ChevronDown className="h-4 w-4 transition-transform duration-200" />}
{!hideIcon && <ChevronDown className="h-4 w-4 transition-transform duration-200 shrink-0" />}
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
))
+1
View File
@@ -130,6 +130,7 @@
"NEXT_PUBLIC_APP_URL",
"NEXT_PUBLIC_VERCEL_TARGET_ENV",
"NEXT_PUBLIC_VERCEL_BRANCH_URL",
"NEXT_PUBLIC_API_URL",
"NODE_ENV",
"HIDE_TAILWIND_INDICATOR",
// These envs are used in the packages