mirror of
https://github.com/SrIzan10/helium.git
synced 2026-06-06 00:56:58 +00:00
feat: clerk theming and preset selector
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
@import '@clerk/themes/shadcn.css';
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@@ -123,4 +124,8 @@
|
||||
h1 {
|
||||
@apply scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cl-avatarBox {
|
||||
@apply size-8;
|
||||
}
|
||||
|
||||
31
app/components/app/PresetSelect.vue
Normal file
31
app/components/app/PresetSelect.vue
Normal file
@@ -0,0 +1,31 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { Plus } from 'lucide-vue-next';
|
||||
const router = useRouter()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Select>
|
||||
<SelectTrigger class="w-[180px]">
|
||||
<SelectValue placeholder="Select a preset" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="default">
|
||||
Default
|
||||
</SelectItem>
|
||||
<SelectItem value="create-new" @click="router.push('/presets/new')">
|
||||
<div class="font-bold flex gap-2 items-center">
|
||||
<Plus class="size-4" />
|
||||
Create New Preset
|
||||
</div>
|
||||
</SelectItem>
|
||||
<!-- add database provided presets here -->
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</template>
|
||||
@@ -8,11 +8,17 @@ import {
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { LogIn } from "lucide-vue-next";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog>
|
||||
<DialogTrigger>Sign In</DialogTrigger>
|
||||
<DialogTrigger>
|
||||
<Button size="icon">
|
||||
<LogIn />
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<SignIn />
|
||||
</DialogContent>
|
||||
|
||||
@@ -7,12 +7,14 @@ const colorMode = useColorMode()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="fixed top-4 right-4 z-50">
|
||||
<div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="outline">
|
||||
<Icon icon="radix-icons:moon" class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Icon icon="radix-icons:sun" class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<Button size="icon" variant="outline">
|
||||
<Icon icon="radix-icons:moon"
|
||||
class="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Icon icon="radix-icons:sun"
|
||||
class="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<span class="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
@@ -29,4 +31,4 @@ const colorMode = useColorMode()
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
19
app/components/ui/select/Select.vue
Normal file
19
app/components/ui/select/Select.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectRootEmits, SelectRootProps } from "reka-ui"
|
||||
import { SelectRoot, useForwardPropsEmits } from "reka-ui"
|
||||
|
||||
const props = defineProps<SelectRootProps>()
|
||||
const emits = defineEmits<SelectRootEmits>()
|
||||
|
||||
const forwarded = useForwardPropsEmits(props, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectRoot
|
||||
v-slot="slotProps"
|
||||
data-slot="select"
|
||||
v-bind="forwarded"
|
||||
>
|
||||
<slot v-bind="slotProps" />
|
||||
</SelectRoot>
|
||||
</template>
|
||||
51
app/components/ui/select/SelectContent.vue
Normal file
51
app/components/ui/select/SelectContent.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectContentEmits, SelectContentProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import {
|
||||
SelectContent,
|
||||
SelectPortal,
|
||||
SelectViewport,
|
||||
useForwardPropsEmits,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { SelectScrollDownButton, SelectScrollUpButton } from "."
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
})
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<SelectContentProps & { class?: HTMLAttributes["class"] }>(),
|
||||
{
|
||||
position: "popper",
|
||||
},
|
||||
)
|
||||
const emits = defineEmits<SelectContentEmits>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectPortal>
|
||||
<SelectContent
|
||||
data-slot="select-content"
|
||||
v-bind="{ ...$attrs, ...forwarded }"
|
||||
:class="cn(
|
||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
|
||||
position === 'popper'
|
||||
&& 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectViewport :class="cn('p-1', position === 'popper' && 'h-[var(--reka-select-trigger-height)] w-full min-w-[var(--reka-select-trigger-width)] scroll-my-1')">
|
||||
<slot />
|
||||
</SelectViewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectContent>
|
||||
</SelectPortal>
|
||||
</template>
|
||||
15
app/components/ui/select/SelectGroup.vue
Normal file
15
app/components/ui/select/SelectGroup.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectGroupProps } from "reka-ui"
|
||||
import { SelectGroup } from "reka-ui"
|
||||
|
||||
const props = defineProps<SelectGroupProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectGroup
|
||||
data-slot="select-group"
|
||||
v-bind="props"
|
||||
>
|
||||
<slot />
|
||||
</SelectGroup>
|
||||
</template>
|
||||
44
app/components/ui/select/SelectItem.vue
Normal file
44
app/components/ui/select/SelectItem.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItemProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { Check } from "lucide-vue-next"
|
||||
import {
|
||||
SelectItem,
|
||||
SelectItemIndicator,
|
||||
SelectItemText,
|
||||
useForwardProps,
|
||||
} from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<SelectItemProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectItem
|
||||
data-slot="select-item"
|
||||
v-bind="forwardedProps"
|
||||
:class="
|
||||
cn(
|
||||
'focus:bg-accent focus:text-accent-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
>
|
||||
<span class="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectItemIndicator>
|
||||
<slot name="indicator-icon">
|
||||
<Check class="size-4" />
|
||||
</slot>
|
||||
</SelectItemIndicator>
|
||||
</span>
|
||||
|
||||
<SelectItemText>
|
||||
<slot />
|
||||
</SelectItemText>
|
||||
</SelectItem>
|
||||
</template>
|
||||
15
app/components/ui/select/SelectItemText.vue
Normal file
15
app/components/ui/select/SelectItemText.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectItemTextProps } from "reka-ui"
|
||||
import { SelectItemText } from "reka-ui"
|
||||
|
||||
const props = defineProps<SelectItemTextProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectItemText
|
||||
data-slot="select-item-text"
|
||||
v-bind="props"
|
||||
>
|
||||
<slot />
|
||||
</SelectItemText>
|
||||
</template>
|
||||
17
app/components/ui/select/SelectLabel.vue
Normal file
17
app/components/ui/select/SelectLabel.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectLabelProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { SelectLabel } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<SelectLabelProps & { class?: HTMLAttributes["class"] }>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectLabel
|
||||
data-slot="select-label"
|
||||
:class="cn('text-muted-foreground px-2 py-1.5 text-xs', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</SelectLabel>
|
||||
</template>
|
||||
26
app/components/ui/select/SelectScrollDownButton.vue
Normal file
26
app/components/ui/select/SelectScrollDownButton.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectScrollDownButtonProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ChevronDown } from "lucide-vue-next"
|
||||
import { SelectScrollDownButton, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<SelectScrollDownButtonProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
v-bind="forwardedProps"
|
||||
:class="cn('flex cursor-default items-center justify-center py-1', props.class)"
|
||||
>
|
||||
<slot>
|
||||
<ChevronDown class="size-4" />
|
||||
</slot>
|
||||
</SelectScrollDownButton>
|
||||
</template>
|
||||
26
app/components/ui/select/SelectScrollUpButton.vue
Normal file
26
app/components/ui/select/SelectScrollUpButton.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectScrollUpButtonProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ChevronUp } from "lucide-vue-next"
|
||||
import { SelectScrollUpButton, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<SelectScrollUpButtonProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
v-bind="forwardedProps"
|
||||
:class="cn('flex cursor-default items-center justify-center py-1', props.class)"
|
||||
>
|
||||
<slot>
|
||||
<ChevronUp class="size-4" />
|
||||
</slot>
|
||||
</SelectScrollUpButton>
|
||||
</template>
|
||||
19
app/components/ui/select/SelectSeparator.vue
Normal file
19
app/components/ui/select/SelectSeparator.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectSeparatorProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { SelectSeparator } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = defineProps<SelectSeparatorProps & { class?: HTMLAttributes["class"] }>()
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectSeparator
|
||||
data-slot="select-separator"
|
||||
v-bind="delegatedProps"
|
||||
:class="cn('bg-border pointer-events-none -mx-1 my-1 h-px', props.class)"
|
||||
/>
|
||||
</template>
|
||||
33
app/components/ui/select/SelectTrigger.vue
Normal file
33
app/components/ui/select/SelectTrigger.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectTriggerProps } from "reka-ui"
|
||||
import type { HTMLAttributes } from "vue"
|
||||
import { reactiveOmit } from "@vueuse/core"
|
||||
import { ChevronDown } from "lucide-vue-next"
|
||||
import { SelectIcon, SelectTrigger, useForwardProps } from "reka-ui"
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<SelectTriggerProps & { class?: HTMLAttributes["class"], size?: "sm" | "default" }>(),
|
||||
{ size: "default" },
|
||||
)
|
||||
|
||||
const delegatedProps = reactiveOmit(props, "class", "size")
|
||||
const forwardedProps = useForwardProps(delegatedProps)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectTrigger
|
||||
data-slot="select-trigger"
|
||||
:data-size="size"
|
||||
v-bind="forwardedProps"
|
||||
:class="cn(
|
||||
'border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*=\'text-\'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*=\'size-\'])]:size-4',
|
||||
props.class,
|
||||
)"
|
||||
>
|
||||
<slot />
|
||||
<SelectIcon as-child>
|
||||
<ChevronDown class="size-4 opacity-50" />
|
||||
</SelectIcon>
|
||||
</SelectTrigger>
|
||||
</template>
|
||||
15
app/components/ui/select/SelectValue.vue
Normal file
15
app/components/ui/select/SelectValue.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import type { SelectValueProps } from "reka-ui"
|
||||
import { SelectValue } from "reka-ui"
|
||||
|
||||
const props = defineProps<SelectValueProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectValue
|
||||
data-slot="select-value"
|
||||
v-bind="props"
|
||||
>
|
||||
<slot />
|
||||
</SelectValue>
|
||||
</template>
|
||||
11
app/components/ui/select/index.ts
Normal file
11
app/components/ui/select/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export { default as Select } from "./Select.vue"
|
||||
export { default as SelectContent } from "./SelectContent.vue"
|
||||
export { default as SelectGroup } from "./SelectGroup.vue"
|
||||
export { default as SelectItem } from "./SelectItem.vue"
|
||||
export { default as SelectItemText } from "./SelectItemText.vue"
|
||||
export { default as SelectLabel } from "./SelectLabel.vue"
|
||||
export { default as SelectScrollDownButton } from "./SelectScrollDownButton.vue"
|
||||
export { default as SelectScrollUpButton } from "./SelectScrollUpButton.vue"
|
||||
export { default as SelectSeparator } from "./SelectSeparator.vue"
|
||||
export { default as SelectTrigger } from "./SelectTrigger.vue"
|
||||
export { default as SelectValue } from "./SelectValue.vue"
|
||||
@@ -5,7 +5,8 @@ import ThemeDropdown from '~/components/ui/ThemeDropdown.vue';
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<header class="flex justify-end p-4">
|
||||
<header class="flex justify-end p-4 space-x-4">
|
||||
<ThemeDropdown />
|
||||
<SignedOut>
|
||||
<SignInDialog />
|
||||
</SignedOut>
|
||||
@@ -13,7 +14,6 @@ import ThemeDropdown from '~/components/ui/ThemeDropdown.vue';
|
||||
<UserButton />
|
||||
</SignedIn>
|
||||
</header>
|
||||
<ThemeDropdown />
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -3,10 +3,11 @@ import { useWebSocket } from '@vueuse/core';
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { useStreamerStore } from '~/state/streamer';
|
||||
import { useWebSocketUrl } from '~/composables/useWebSocketUrl';
|
||||
import PresetSelect from '~/components/app/PresetSelect.vue';
|
||||
|
||||
const streamerStore = useStreamerStore()
|
||||
const videofeedRef = ref<HTMLVideoElement|null>(null);
|
||||
const localStream = ref<MediaStream|null>(null);
|
||||
const videofeedRef = ref<HTMLVideoElement | null>(null);
|
||||
const localStream = ref<MediaStream | null>(null);
|
||||
const wsUrl = useWebSocketUrl()
|
||||
|
||||
const { send } = useWebSocket(wsUrl, {
|
||||
@@ -17,11 +18,11 @@ const { send } = useWebSocket(wsUrl, {
|
||||
},
|
||||
onMessage: async (ws, ev) => {
|
||||
const message = JSON.parse(ev.data)
|
||||
|
||||
|
||||
if (message.event === 'room-created') {
|
||||
streamerStore.setCode(message.roomId)
|
||||
}
|
||||
|
||||
|
||||
if (message.event === 'viewer-joined') {
|
||||
const peerConnection = new RTCPeerConnection({
|
||||
iceServers: [
|
||||
@@ -57,14 +58,12 @@ const { send } = useWebSocket(wsUrl, {
|
||||
});
|
||||
streamerStore.addPeerConnection(message.viewerId, peerConnection)
|
||||
|
||||
// Add media tracks to peer connection
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach(track => {
|
||||
peerConnection.addTrack(track, localStream.value!);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle ICE candidates
|
||||
peerConnection.onicecandidate = (event) => {
|
||||
if (event.candidate) {
|
||||
send(JSON.stringify({
|
||||
@@ -77,21 +76,21 @@ const { send } = useWebSocket(wsUrl, {
|
||||
|
||||
const offer = await peerConnection.createOffer();
|
||||
await peerConnection.setLocalDescription(offer);
|
||||
|
||||
|
||||
send(JSON.stringify({
|
||||
event: 'offer',
|
||||
targetId: message.viewerId,
|
||||
sdp: offer,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
if (message.event === 'ice-candidate') {
|
||||
const pc = streamerStore.peerConnections[message.from];
|
||||
if (pc) {
|
||||
await pc.addIceCandidate(new RTCIceCandidate(message.candidate));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (message.event === 'answer') {
|
||||
const pc = streamerStore.peerConnections[message.from];
|
||||
if (pc) {
|
||||
@@ -121,9 +120,12 @@ async function startScreenShare() {
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-center gap-6 mt-10 px-4">
|
||||
<Button @click="startScreenShare">
|
||||
screenshare
|
||||
</Button>
|
||||
<div class="flex space-x-4 items-center">
|
||||
<Button @click="startScreenShare">
|
||||
screenshare
|
||||
</Button>
|
||||
<PresetSelect />
|
||||
</div>
|
||||
<p v-if="streamerStore.code" class="font-mono">{{ streamerStore.code }}</p>
|
||||
<video ref="videofeedRef" autoplay playsinline muted></video>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { shadcn } from "@clerk/themes";
|
||||
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
@@ -30,4 +31,9 @@ export default defineNuxtConfig({
|
||||
websocket: true
|
||||
}
|
||||
},
|
||||
})
|
||||
clerk: {
|
||||
appearance: {
|
||||
theme: shadcn
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@clerk/nuxt": "^1.13.10",
|
||||
"@clerk/themes": "^2.4.46",
|
||||
"@neondatabase/serverless": "^1.0.2",
|
||||
"@pinia/nuxt": "0.11.2",
|
||||
"@tailwindcss/vite": "^4.1.16",
|
||||
|
||||
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@@ -11,6 +11,9 @@ importers:
|
||||
'@clerk/nuxt':
|
||||
specifier: ^1.13.10
|
||||
version: 1.13.10(magicast@0.5.0)(react@19.2.3)(vue@3.5.22(typescript@5.9.3))
|
||||
'@clerk/themes':
|
||||
specifier: ^2.4.46
|
||||
version: 2.4.46(react@19.2.3)
|
||||
'@neondatabase/serverless':
|
||||
specifier: ^1.0.2
|
||||
version: 1.0.2
|
||||
@@ -236,6 +239,10 @@ packages:
|
||||
react-dom:
|
||||
optional: true
|
||||
|
||||
'@clerk/themes@2.4.46':
|
||||
resolution: {integrity: sha512-26U+aInnWJwYHrT/LYX7sGRrLJwLk4NvfEoUyVc5EXUl7ue/TZ88r7ZiKDv0KutBTNopaz+p+7KD6F1j72nodA==}
|
||||
engines: {node: '>=18.17.0'}
|
||||
|
||||
'@clerk/types@4.101.9':
|
||||
resolution: {integrity: sha512-RO00JqqmkIoI1o0XCtvudjaLpqEoe8PRDHlLS1r/aNZazUQCO0TT6nZOx1F3X+QJDjqYVY7YmYl3mtO2QVEk1g==}
|
||||
engines: {node: '>=18.17.0'}
|
||||
@@ -4388,6 +4395,14 @@ snapshots:
|
||||
optionalDependencies:
|
||||
react: 19.2.3
|
||||
|
||||
'@clerk/themes@2.4.46(react@19.2.3)':
|
||||
dependencies:
|
||||
'@clerk/shared': 3.41.1(react@19.2.3)
|
||||
tslib: 2.8.1
|
||||
transitivePeerDependencies:
|
||||
- react
|
||||
- react-dom
|
||||
|
||||
'@clerk/types@4.101.9(react@19.2.3)':
|
||||
dependencies:
|
||||
'@clerk/shared': 3.41.1(react@19.2.3)
|
||||
|
||||
Reference in New Issue
Block a user