Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/apps/www/public/images/blog @supabase/marketing
/apps/www/lib/redirects.js

/docker/ @supabase/dev-workflows @aantti
/docker/ @supabase/dev-workflows @supabase/self-hosted

/apps/studio/csp.js @supabase/security
/apps/studio/components/interfaces/Billing/Payment @supabase/security
Expand Down
44 changes: 44 additions & 0 deletions apps/design-system/__registry__/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2480,6 +2480,50 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"metric-card": {
name: "metric-card",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/metric-card")),
source: "",
files: ["registry/default/example/metric-card.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"metric-card-minimal": {
name: "metric-card-minimal",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/metric-card-minimal")),
source: "",
files: ["registry/default/example/metric-card-minimal.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"metric-card-minimal-horizontal": {
name: "metric-card-minimal-horizontal",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/metric-card-minimal-horizontal")),
source: "",
files: ["registry/default/example/metric-card-minimal-horizontal.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"metric-card-with-icon-link-tooltip": {
name: "metric-card-with-icon-link-tooltip",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/metric-card-with-icon-link-tooltip")),
source: "",
files: ["registry/default/example/metric-card-with-icon-link-tooltip.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"chart-area-axes": {
name: "chart-area-axes",
type: "components:block",
Expand Down
5 changes: 5 additions & 0 deletions apps/design-system/config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/fragments/logs-bar-chart',
items: [],
},
{
title: 'Metric Card',
href: '/docs/fragments/metric-card',
items: [],
},
{
title: 'Table of Contents (TOC)',
href: '/docs/fragments/toc',
Expand Down
21 changes: 21 additions & 0 deletions apps/design-system/content/docs/fragments/metric-card.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Metric Card
description: A card to display pull out metrics at a glance.
fragment: true
---

<ComponentPreview name="metric-card" peekCode wide />

## Examples

### Minimal

<ComponentPreview name="metric-card-minimal" />

### Minimal Horizontal

<ComponentPreview name="metric-card-minimal-horizontal" />

### With Icon, Link and Tooltip

<ComponentPreview name="metric-card-with-icon-link-tooltip" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client'

import { useEffect, useState } from 'react'
import {
MetricCard,
MetricCardHeader,
MetricCardLabel,
MetricCardContent,
MetricCardValue,
MetricCardDifferential,
} from 'ui-patterns/MetricCard'

export default function MetricsCardDemo() {
const [data, setData] = useState<Array<{ value: number; timestamp: string }>>([])

useEffect(() => {
const now = new Date()
setData(
Array.from({ length: 12 }, (_, i) => ({
value: Math.floor(4000 + i * 100 + (Math.random() * 2000 - 800)),
timestamp: new Date(now.getTime() - (11 - i) * 60 * 60 * 1000).toISOString(),
}))
)
}, [])

const averageValue = data.reduce((acc, curr) => acc + curr.value, 0) / data.length

const diff = data[data.length - 1]?.value - data[0]?.value || 0
const diffPercentage = (diff / averageValue) * 100

return (
<div className="w-1/2">
<MetricCard isLoading={!data.length}>
<MetricCardHeader>
<MetricCardLabel>Active Users</MetricCardLabel>
</MetricCardHeader>
<MetricCardContent orientation="horizontal">
<MetricCardValue>
{averageValue.toLocaleString(undefined, { maximumFractionDigits: 0 })}
</MetricCardValue>
<MetricCardDifferential variant={diffPercentage > 0 ? 'positive' : 'negative'}>
{diffPercentage > 0 ? '+' : '-'}
{Math.abs(diffPercentage).toFixed(1)}%
</MetricCardDifferential>
</MetricCardContent>
</MetricCard>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use client'

import { useEffect, useState } from 'react'
import {
MetricCard,
MetricCardHeader,
MetricCardLabel,
MetricCardContent,
MetricCardValue,
MetricCardDifferential,
} from 'ui-patterns/MetricCard'

export default function MetricsCardDemo() {
const [data, setData] = useState<Array<{ value: number; timestamp: string }>>([])

useEffect(() => {
const now = new Date()
setData(
Array.from({ length: 12 }, (_, i) => ({
value: Math.floor(4000 + i * 100 + (Math.random() * 2000 - 800)),
timestamp: new Date(now.getTime() - (11 - i) * 60 * 60 * 1000).toISOString(),
}))
)
}, [])

const averageValue = data.reduce((acc, curr) => acc + curr.value, 0) / data.length

const diff = data[data.length - 1]?.value - data[0]?.value || 0
const diffPercentage = (diff / averageValue) * 100

return (
<div className="w-1/2">
<MetricCard isLoading={!data.length}>
<MetricCardHeader>
<MetricCardLabel>Active Users</MetricCardLabel>
</MetricCardHeader>
<MetricCardContent>
<MetricCardValue>
{averageValue.toLocaleString(undefined, { maximumFractionDigits: 0 })}
</MetricCardValue>
<MetricCardDifferential variant={diffPercentage > 0 ? 'positive' : 'negative'}>
{diffPercentage > 0 ? '+' : '-'}
{Math.abs(diffPercentage).toFixed(1)}%
</MetricCardDifferential>
</MetricCardContent>
</MetricCard>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
'use client'

import { useEffect, useState } from 'react'
import {
MetricCard,
MetricCardHeader,
MetricCardIcon,
MetricCardLabel,
MetricCardContent,
MetricCardValue,
MetricCardDifferential,
MetricCardSparkline,
} from 'ui-patterns/MetricCard'
import { User2 } from 'lucide-react'

export default function MetricsCardDemo() {
const [data, setData] = useState<Array<{ value: number; timestamp: string }>>([])

useEffect(() => {
const now = new Date()
setData(
Array.from({ length: 12 }, (_, i) => ({
value: Math.floor(4000 + i * 100 + (Math.random() * 2000 - 800)),
timestamp: new Date(now.getTime() - (11 - i) * 60 * 60 * 1000).toISOString(),
}))
)
}, [])

const averageValue = data.reduce((acc, curr) => acc + curr.value, 0) / data.length

const diff = data[data.length - 1]?.value - data[0]?.value || 0
const diffPercentage = (diff / averageValue) * 100

return (
<div className="w-1/2">
<MetricCard isLoading={!data.length}>
<MetricCardHeader href="https://www.supabase.io">
<MetricCardIcon>
<User2 size={14} strokeWidth={1.5} />
</MetricCardIcon>
<MetricCardLabel tooltip="The number of active users over the last 24 hours">
Active Users
</MetricCardLabel>
</MetricCardHeader>
<MetricCardContent>
<MetricCardValue>
{averageValue.toLocaleString(undefined, { maximumFractionDigits: 0 })}
</MetricCardValue>
<MetricCardDifferential variant={diffPercentage > 0 ? 'positive' : 'negative'}>
{diffPercentage > 0 ? '+' : '-'}
{Math.abs(diffPercentage).toFixed(1)}%
</MetricCardDifferential>
</MetricCardContent>
<MetricCardSparkline data={data} dataKey="value" />
</MetricCard>
</div>
)
}
53 changes: 53 additions & 0 deletions apps/design-system/registry/default/example/metric-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use client'

import { useEffect, useState } from 'react'
import {
MetricCard,
MetricCardHeader,
MetricCardLabel,
MetricCardContent,
MetricCardValue,
MetricCardDifferential,
MetricCardSparkline,
} from 'ui-patterns/MetricCard'

export default function MetricsCardDemo() {
const [data, setData] = useState<Array<{ value: number; timestamp: string }>>([])

useEffect(() => {
const now = new Date()
setData(
Array.from({ length: 12 }, (_, i) => ({
value: Math.floor(4000 + i * 100 + (Math.random() * 2000 - 800)),
timestamp: new Date(now.getTime() - (11 - i) * 60 * 60 * 1000).toISOString(),
}))
)
}, [])

const averageValue = data.reduce((acc, curr) => acc + curr.value, 0) / data.length

const diff = data[data.length - 1]?.value - data[0]?.value || 0
const diffPercentage = (diff / averageValue) * 100

return (
<div className="w-1/2">
<MetricCard isLoading={!data.length}>
<MetricCardHeader href="https://www.supabase.io">
<MetricCardLabel tooltip="The number of active users over the last 24 hours">
Active Users
</MetricCardLabel>
</MetricCardHeader>
<MetricCardContent>
<MetricCardValue>
{averageValue.toLocaleString(undefined, { maximumFractionDigits: 0 })}
</MetricCardValue>
<MetricCardDifferential variant={diffPercentage > 0 ? 'positive' : 'negative'}>
{diffPercentage > 0 ? '+' : '-'}
{Math.abs(diffPercentage).toFixed(1)}%
</MetricCardDifferential>
</MetricCardContent>
<MetricCardSparkline data={data} dataKey="value" />
</MetricCard>
</div>
)
}
20 changes: 20 additions & 0 deletions apps/design-system/registry/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1333,4 +1333,24 @@ export const examples: Registry = [
type: 'components:example',
files: ['example/empty-state-zero-items-data-grid.tsx'],
},
{
name: 'metric-card',
type: 'components:example',
files: ['example/metric-card.tsx'],
},
{
name: 'metric-card-minimal',
type: 'components:example',
files: ['example/metric-card-minimal.tsx'],
},
{
name: 'metric-card-minimal-horizontal',
type: 'components:example',
files: ['example/metric-card-minimal-horizontal.tsx'],
},
{
name: 'metric-card-with-icon-link-tooltip',
type: 'components:example',
files: ['example/metric-card-with-icon-link-tooltip.tsx'],
},
]
Original file line number Diff line number Diff line change
Expand Up @@ -1408,6 +1408,10 @@ export const queues: NavMenuConstant = {
name: 'Consuming Messages with Edge Functions',
url: '/guides/queues/consuming-messages-with-edge-functions',
},
{
name: 'Expose Queues for local and self-hosted Supabase',
url: '/guides/queues/expose-self-hosted-queues',
},
],
},
{
Expand Down
7 changes: 7 additions & 0 deletions apps/docs/content/_partials/uiLibCta.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Admonition type="tip" title="Explore drop-in UI components for your Supabase app.">

UI components built on shadcn/ui that connect to Supabase via a single command.

<Button type="primary">Explore Components</Button>

</Admonition>
2 changes: 1 addition & 1 deletion apps/docs/content/guides/auth/quickstarts/nextjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ hideToc: true
- [TypeScript](https://www.typescriptlang.org/)
- [Tailwind CSS](https://tailwindcss.com/)

[See GitHub repo](https://github.com/vercel/next.js/tree/canary/examples/with-supabase)
<$Partial path="uiLibCta.mdx" />

</StepHikeCompact.Details>

Expand Down
11 changes: 3 additions & 8 deletions apps/docs/content/guides/auth/quickstarts/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,10 @@ hideToc: true
<StepHikeCompact.Step step={2}>
<StepHikeCompact.Details title="Create a React app">

Create a React app using [Vite](https://vitejs.dev/).
Select React from the [list of UI Library quickstarts](/ui/docs/getting-started/quickstart) and follow the instructions to create a new project.

</StepHikeCompact.Details>

<StepHikeCompact.Code>

```bash name=Terminal
npm create vite@latest my-app -- --template react
```

</StepHikeCompact.Code>
</StepHikeCompact.Step>

<StepHikeCompact.Step step={3}>
Expand All @@ -64,6 +57,8 @@ hideToc: true
<StepHikeCompact.Step step={4}>
<StepHikeCompact.Details title="Set up your login component">

<$Partial path="uiLibCta.mdx" />

In `App.jsx`, create a Supabase client using your Project URL and key.

<$Partial path="api_settings_steps.mdx" />
Expand Down
Loading
Loading