Skip to content

Commit 9949916

Browse files
Baroshemivasilovsaltcod
authored
Docs/UI library vue nuxt clients (supabase#38279)
* docs: add vue client to ui-library * docs: add missing vue client to llms.txt * docs: add nuxt client to ui-library * docs: wrong env variable names * docs: fix dependencies * docs: update client-nuxtjs.json * Reinstall the deps so that the pnpm-lock.yaml has less changes. * Add blocks/vue package. * Remove the vue blocks from ui-library. * Copy the vue blocks into ui-library. * Clean up unneeded files. * Regenerate the pnpm-lock file from master. * Fix prettier errors. * docs: update shadcn-vue cli * docs: reusable server client * Small things * docs: improvments after CR --------- Co-authored-by: Ivan Vasilov <[email protected]> Co-authored-by: Terry Sutton <[email protected]>
1 parent 5f53324 commit 9949916

33 files changed

+4777
-280
lines changed

apps/ui-library/components/block-item.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ interface BlockItemProps {
1212
}
1313

1414
export const BlockItem = ({ name }: BlockItemProps) => {
15+
const framework = name.includes('vue') || name.includes('nuxtjs') ? 'vue' : 'react'
16+
1517
return (
1618
<div className="mt-4">
17-
<Command name={name} highlight />
19+
<Command name={name} highlight framework={framework} />
1820
<OpenInV0Button name={name} className="w-fit shrink-0 mt-4" />
1921
</div>
2022
)

apps/ui-library/components/command.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import { useLocalStorage } from './use-local-storage'
88
interface CommandCopyProps {
99
name: string
1010
highlight?: boolean
11+
// For Vue, we need to use the `shadcn-vue` package instead of `shadcn`
12+
framework?: 'react' | 'vue'
1113
}
1214

1315
type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun'
1416

1517
const LOCAL_STORAGE_KEY = 'package-manager-copy-command'
1618

17-
export function Command({ name, highlight }: CommandCopyProps) {
19+
export function Command({ name, highlight, framework = 'react' }: CommandCopyProps) {
1820
const [value, setValue] = useLocalStorage(LOCAL_STORAGE_KEY, 'npm')
1921

2022
const getBaseUrl = () => {
@@ -30,12 +32,27 @@ export function Command({ name, highlight }: CommandCopyProps) {
3032
const baseUrl = getBaseUrl()
3133
const componentPath = `${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}/r/${name}.json`
3234

33-
const commands: Record<PackageManager, string> = {
34-
npm: `npx shadcn@latest add ${baseUrl}${componentPath}`,
35-
pnpm: `pnpm dlx shadcn@latest add ${baseUrl}${componentPath}`,
36-
yarn: `yarn dlx shadcn@latest add ${baseUrl}${componentPath}`,
37-
bun: `bunx --bun shadcn@latest add ${baseUrl}${componentPath}`,
38-
}
35+
const commands: Record<PackageManager, string> =
36+
framework === 'react'
37+
? {
38+
npm: `npx shadcn@latest add ${baseUrl}${componentPath}`,
39+
pnpm: `pnpm dlx shadcn@latest add ${baseUrl}${componentPath}`,
40+
yarn: `yarn dlx shadcn@latest add ${baseUrl}${componentPath}`,
41+
bun: `bunx --bun shadcn@latest add ${baseUrl}${componentPath}`,
42+
}
43+
: framework === 'vue'
44+
? {
45+
npm: `npx shadcn-vue@latest add ${baseUrl}${componentPath}`,
46+
pnpm: `pnpm dlx shadcn-vue@latest add ${baseUrl}${componentPath}`,
47+
yarn: `yarn dlx shadcn-vue@latest add ${baseUrl}${componentPath}`,
48+
bun: `bunx --bun shadcn-vue@latest add ${baseUrl}${componentPath}`,
49+
}
50+
: {
51+
npm: `npx shadcn@latest add ${baseUrl}${componentPath}`,
52+
pnpm: `pnpm dlx shadcn@latest add ${baseUrl}${componentPath}`,
53+
yarn: `yarn dlx shadcn@latest add ${baseUrl}${componentPath}`,
54+
bun: `bunx --bun shadcn@latest add ${baseUrl}${componentPath}`,
55+
}
3956

4057
return (
4158
<Tabs_Shadcn_ value={value} onValueChange={setValue} className="w-full">

apps/ui-library/config/docs.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export const componentPages: SidebarNavGroup = {
5454
items: [
5555
{
5656
title: 'Client',
57-
supportedFrameworks: ['nextjs', 'react-router', 'tanstack', 'react'],
57+
supportedFrameworks: ['nextjs', 'react-router', 'tanstack', 'react', 'vue', 'nuxtjs'],
5858
href: '/docs/nextjs/client',
5959
items: [],
6060
commandItemLabel: 'Supabase Client',
@@ -141,4 +141,6 @@ export const frameworkTitles: Record<string, string> = {
141141
'react-router': 'React Router',
142142
tanstack: 'TanStack Start',
143143
react: 'React SPA',
144+
vue: 'Vue',
145+
nuxtjs: 'Nuxt.js',
144146
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
title: Supabase Client Libraries
3+
description: Supabase client for Nuxt.js
4+
---
5+
6+
## Installation
7+
8+
<BlockItem name="supabase-client-nuxtjs" description="Supabase Client for Nuxt.js" />
9+
10+
## Folder structure
11+
12+
<RegistryBlock itemName="supabase-client-nuxtjs" />
13+
14+
## Usage
15+
16+
This block installs a Supabase client for connecting your Nuxt.js project to Supabase. It's designed to fully supports server-side rendering (SSR).
17+
18+
If you've already set up your Supabase client—either using the `npm create nuxt@latest` template or another method—you can continue using your existing setup.
19+
20+
### Getting started
21+
22+
After installing the block, you'll have the following environment variables in your `.env.local` file:
23+
24+
```env
25+
NUXT_PUBLIC_SUPABASE_URL=
26+
NUXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=
27+
```
28+
29+
- If you're using supabase.com, you can find these values in the [Connect modal](https://supabase.com/dashboard/project/_?showConnect=true&tab=frameworks&framework=vuejs&using=supabasejs) under App Frameworks or in your project's [API keys](https://supabase.com/dashboard/project/_/settings/api-keys).
30+
31+
- If you're using a local instance of Supabase, you can find these values by running `supabase start` or `supabase status` (if you already have it running).
32+
33+
- Nuxt recommends [NuxtSupabase](https://supabase.nuxtjs.org/) module to integrate Nuxt application with Supabase. It’s an alternative to this approach, but both approaches are fine.
34+
35+
<Callout type="warning" className="mt-4">
36+
{' '}
37+
This Supabase client is built for SSR with the Nuxt.js. If you're building a Vue SPA, use the [Vue
38+
SPA client](/ui/docs/vue/client) instead.{' '}
39+
</Callout>
40+
41+
## Further reading
42+
43+
- [Use Supabase with Nuxt](https://supabase.com/docs/guides/getting-started/quickstarts/nuxtjs)
44+
- [Build a User Management App with Nuxt 3](https://supabase.com/docs/guides/getting-started/tutorials/with-nuxt-3)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Supabase Client Libraries
3+
description: Supabase client for Vue Single Page Applications
4+
---
5+
6+
## Installation
7+
8+
<BlockItem name="supabase-client-vue" description="Supabase Client for Vue SPA" />
9+
10+
## Folder structure
11+
12+
<RegistryBlock itemName="supabase-client-vue" />
13+
14+
## Usage
15+
16+
This block installs a Supabase client for connecting your Vue project to Supabase. It's designed for use in client-side components.
17+
18+
If you've already set up a Supabase client in your project, you can just continue using that existing setup.
19+
20+
### Getting started
21+
22+
After installing the block, you'll have the following environment variables in your `.env.local` file:
23+
24+
```env
25+
VITE_SUPABASE_URL=
26+
VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY=
27+
```
28+
29+
- If you're using supabase.com, you can find these values in the [Connect modal](https://supabase.com/dashboard/project/_?showConnect=true&tab=frameworks&framework=vuejs&using=supabasejs) under App Frameworks or in your project's [API keys](https://supabase.com/dashboard/project/_/settings/api-keys).
30+
31+
- If you're using a local instance of Supabase, you can find these values by running `supabase start` or `supabase status` (if you already have it running).
32+
33+
You can use the client in your Vue component like following:
34+
35+
```vue
36+
<script setup lang="ts">
37+
import { onMounted, ref } from 'vue'
38+
import { createClient } from './lib/supabase/client'
39+
40+
const profile = ref(null)
41+
42+
onMounted(async () => {
43+
const { data, error } = await createClient.from('profiles').select('*').single()
44+
45+
if (!error) profile.value = data
46+
})
47+
</script>
48+
49+
<template>
50+
<div>
51+
{{ profile }}
52+
</div>
53+
</template>
54+
```
55+
56+
## Further reading
57+
58+
- [Generating TypeScript types for your client](https://supabase.com/docs/guides/api/rest/generating-types)
59+
- [Use Supabase with Vue](https://supabase.com/docs/guides/getting-started/quickstarts/vue)

apps/ui-library/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"preinstall": "npx only-allow pnpm",
88
"dev": "next dev --port 3004",
99
"build": "pnpm run content:build && pnpm run build:registry && pnpm run build:llms && next build --turbopack",
10-
"build:registry": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --cache --write registry.json && rimraf -G public/r && shadcn build && tsx scripts/clean-registry.ts",
10+
"build:registry": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --cache --write registry.json && rimraf -G public/r && shadcn build && cp node_modules/@supabase/vue-blocks/public/r/* public/r && tsx scripts/clean-registry.ts",
1111
"build:llms": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-llms-txt.ts",
1212
"start": "next start",
1313
"lint": "next lint",
@@ -50,6 +50,7 @@
5050
"@supabase/postgrest-js": "*",
5151
"@supabase/supa-mdx-lint": "0.2.6-alpha",
5252
"@tanstack/react-query": "^5.83.0",
53+
"@supabase/vue-blocks": "workspace:*",
5354
"axios": "^1.11.0",
5455
"class-variance-authority": "*",
5556
"cmdk": "^1.0.0",

apps/ui-library/public/llms.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,7 @@ Library of components for your project. The components integrate with Supabase a
8181
- Real-time cursor sharing for collaborative applications
8282
- [Social Authentication](https://supabase.com/ui/docs/tanstack/social-auth)
8383
- Social authentication block for Tanstack Start
84+
- [Supabase Client Libraries](https://supabase.com/ui/docs/vue/client)
85+
- Supabase client for Vue Single Page Applications
86+
- [Supabase Client Libraries](https://supabase.com/ui/docs/nuxtjs/client)
87+
- Supabase client for Nuxt.js
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
3+
"name": "supabase-client-nuxtjs",
4+
"type": "registry:lib",
5+
"title": "Supabase Client for Nuxt.js",
6+
"description": "",
7+
"dependencies": [
8+
"@supabase/ssr@latest",
9+
"@supabase/supabase-js@latest"
10+
],
11+
"registryDependencies": [],
12+
"files": [
13+
{
14+
"path": "registry/default/clients/nuxtjs/lib/supabase/client.ts",
15+
"content": "import { createBrowserClient } from '@supabase/ssr'\n\nexport function createClient() {\n return createBrowserClient(\n process.env.NUXT_PUBLIC_SUPABASE_URL!,\n process.env.NUXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!\n )\n}\n",
16+
"type": "registry:lib"
17+
},
18+
{
19+
"path": "registry/default/clients/nuxtjs/server/middleware/is-authenticated.ts",
20+
"content": "import { defineNuxtRouteMiddleware, navigateTo, useRequestEvent } from 'nuxt/app'\nimport { createSupabaseServerClient } from '../supabase/client'\n\nexport default defineNuxtRouteMiddleware(async (to) => {\n const event = useRequestEvent()\n\n // create Supabase SSR client directly here\n const supabase = createSupabaseServerClient(event);\n\n // check current user\n const { data: { user } } = await supabase.auth.getUser()\n\n if (!user && to.path !== '/login') {\n return navigateTo('/login')\n }\n})\n",
21+
"type": "registry:file",
22+
"target": "server/middleware/is-authenticated.ts"
23+
},
24+
{
25+
"path": "registry/default/clients/nuxtjs/server/api/profile.get.ts",
26+
"content": "import { createError, defineEventHandler } from 'h3';\nimport { createSupabaseServerClient } from '../supabase/client';\n\nexport default defineEventHandler(async (event) => {\n // Create Supabase SSR client\n const supabase = createSupabaseServerClient(event)\n\n // Example: get user session\n const {\n data: { user },\n } = await supabase.auth.getUser();\n\n if (!user) {\n return { error: 'Not authenticated' };\n }\n\n // Fetch profile row\n const { data, error } = await supabase\n .from('profiles')\n .select('*')\n .eq('id', user.id)\n .single();\n\n if (error) {\n throw createError({ statusCode: 500, statusMessage: error.message });\n }\n\n return { profile: data };\n});\n",
27+
"type": "registry:file",
28+
"target": "server/api/profile.get.ts"
29+
},
30+
{
31+
"path": "registry/default/clients/nuxtjs/server/supabase/client.ts",
32+
"content": "import { createServerClient } from '@supabase/ssr'\nimport { getCookie, setCookie, deleteCookie, H3Event, EventHandlerRequest } from 'h3'\n\nexport const createSupabaseServerClient = (event: H3Event<EventHandlerRequest> | undefined) => {\n return createServerClient(\n process.env.NUXT_PUBLIC_SUPABASE_URL!,\n process.env.NUXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!,\n {\n cookies: {\n get: (key) => getCookie(event!, key),\n set: (key, value, options) => setCookie(event!, key, value, options),\n remove: (key, options) => deleteCookie(event!, key, options),\n },\n }\n )\n}",
33+
"type": "registry:file",
34+
"target": "server/supabase/client.ts"
35+
}
36+
],
37+
"envVars": {
38+
"NUXT_PUBLIC_SUPABASE_URL": "",
39+
"NUXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
40+
},
41+
"docs": "You'll need to set the following environment variables in your project: `NUXT_PUBLIC_SUPABASE_URL` and `NUXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`."
42+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
3+
"name": "supabase-client-vue",
4+
"type": "registry:lib",
5+
"title": "Supabase Client for Vue",
6+
"description": "",
7+
"dependencies": [
8+
"@supabase/supabase-js@latest"
9+
],
10+
"registryDependencies": [],
11+
"files": [
12+
{
13+
"path": "registry/default/clients/vue/lib/supabase/client.ts",
14+
"content": "/// <reference types=\"vite/types/importMeta.d.ts\" />\nimport { createClient as createSupabaseClient } from '@supabase/supabase-js'\n\nexport function createClient() {\n return createSupabaseClient(\n import.meta.env.VITE_SUPABASE_URL!,\n import.meta.env.VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY!\n )\n}\n",
15+
"type": "registry:lib"
16+
}
17+
],
18+
"envVars": {
19+
"VITE_SUPABASE_URL": "",
20+
"VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
21+
},
22+
"docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`."
23+
}

apps/ui-library/types/nav.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
type supportedFrameworks = 'nextjs' | 'react-router' | 'tanstack' | 'react'
1+
type supportedFrameworks = 'nextjs' | 'react-router' | 'tanstack' | 'react' | 'vue' | 'nuxtjs'
22
export interface NavItem {
33
title: string
44
href?: string

0 commit comments

Comments
 (0)