Added supabase auth to project
This design is minimalist for now, it might be extended (at least with a basic profil page or command list)
This commit is contained in:
@@ -2,55 +2,55 @@
|
||||
import { useCalendar } from '@/stores/CalendarStore'
|
||||
|
||||
import { PhList, PhHouse, PhMagnifyingGlass } from '@phosphor-icons/vue'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import Button from '../ui/button/Button.vue'
|
||||
|
||||
const { revealAdvancedSearch } = useCalendar()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<nav class="w-16 py-6 border-r-[1px] border-l-slate-500 grid justify-center">
|
||||
<nav class="w-16 py-6 border-r-[1px] border-l-slate-500 grid grid-rows-[1fr_auto] justify-center">
|
||||
<menu class="flex flex-col gap-4">
|
||||
<li class="mb-12">
|
||||
<Button variant="ghost" size="icon" class="rounded-full" @click="console.log">
|
||||
<UiButton variant="ghost" size="icon" class="rounded-full" @click="console.log">
|
||||
<PhList size="27" />
|
||||
</Button>
|
||||
</UiButton>
|
||||
</li>
|
||||
<li>
|
||||
<TooltipProvider :delay-duration="100">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="rounded-full" as-child>
|
||||
<UiTooltipProvider :delay-duration="100">
|
||||
<UiTooltip>
|
||||
<UiTooltipTrigger as-child>
|
||||
<UiButton variant="ghost" size="icon" class="rounded-full" as-child>
|
||||
<RouterLink to="/">
|
||||
<PhHouse size="24" weight="fill" />
|
||||
</RouterLink>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent :side="'right'">
|
||||
</UiButton>
|
||||
</UiTooltipTrigger>
|
||||
<UiTooltipContent :side="'right'">
|
||||
<p>Retourner aux outils</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</UiTooltipContent>
|
||||
</UiTooltip>
|
||||
</UiTooltipProvider>
|
||||
</li>
|
||||
<li>
|
||||
<TooltipProvider :delay-duration="100">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button
|
||||
<UiTooltipProvider :delay-duration="100">
|
||||
<UiTooltip>
|
||||
<UiTooltipTrigger as-child>
|
||||
<UiButton
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
class="rounded-full"
|
||||
@click="revealAdvancedSearch()"
|
||||
>
|
||||
<PhMagnifyingGlass size="24" weight="fill" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent :side="'right'">
|
||||
</UiButton>
|
||||
</UiTooltipTrigger>
|
||||
<UiTooltipContent :side="'right'">
|
||||
<p>Recherche avancée</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</UiTooltipContent>
|
||||
</UiTooltip>
|
||||
</UiTooltipProvider>
|
||||
</li>
|
||||
</menu>
|
||||
|
||||
<UserCTA />
|
||||
</nav>
|
||||
</template>
|
||||
|
||||
@@ -26,7 +26,7 @@ const moveCalendarRight = useThrottleFn(() => {
|
||||
|
||||
<template>
|
||||
<div class="container mt-[10vh] mb-auto" @wheel="handleWheel">
|
||||
<div ref="test" class="grid grid-cols-5 gap-x-8 gap-y-16">
|
||||
<div class="grid grid-cols-5 gap-x-8 gap-y-16">
|
||||
<MonthTile
|
||||
v-for="month in staticConfig.monthsPerYear"
|
||||
:key="month"
|
||||
|
||||
77
components/global/user/CTA.vue
Normal file
77
components/global/user/CTA.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { PhUserCircle } from '@phosphor-icons/vue'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const { auth } = useSupabaseClient()
|
||||
const user = useSupabaseUser()
|
||||
const userMeta = computed(() => user.value?.user_metadata)
|
||||
const hasSession = computed(() => Boolean(user.value))
|
||||
|
||||
async function handleGoogleLogin() {
|
||||
try {
|
||||
auth.signInWithOAuth({
|
||||
provider: 'google',
|
||||
options: {
|
||||
queryParams: {
|
||||
access_type: 'offline',
|
||||
prompt: 'consent'
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLogout() {
|
||||
try {
|
||||
const { error } = await auth.signOut()
|
||||
|
||||
if (error) throw error
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
function gotoProfilePage() {
|
||||
router.push({ path: '/profil' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<UiPopover>
|
||||
<UiPopoverTrigger :as-child="hasSession">
|
||||
<UiAvatar v-if="hasSession" class="cursor-pointer">
|
||||
<UiAvatarImage
|
||||
:src="userMeta?.avatar_url"
|
||||
:alt="userMeta?.full_name"
|
||||
referrerpolicy="no-referrer"
|
||||
/>
|
||||
<UiAvatarFallback>Me</UiAvatarFallback>
|
||||
</UiAvatar>
|
||||
<UiButton v-else variant="outline" size="icon">
|
||||
<PhUserCircle size="18" />
|
||||
</UiButton>
|
||||
</UiPopoverTrigger>
|
||||
<UiPopoverContent class="w-fit p-0" :align="'start'" :side="'top'" :collision-padding="20">
|
||||
<div id="user-popover">
|
||||
<UiCommand>
|
||||
<UiCommandList v-if="user">
|
||||
<UiCommandGroup :heading="`Connecté en tant que ${user?.email}`">
|
||||
<UiCommandItem value="profile" @select="gotoProfilePage"> Profil </UiCommandItem>
|
||||
<UiCommandItem value="logout" @select="handleLogout"> Déconnexion </UiCommandItem>
|
||||
</UiCommandGroup>
|
||||
</UiCommandList>
|
||||
<UiCommandList v-else>
|
||||
<UiCommandItem value="logout" @select="handleGoogleLogin"> Connexion </UiCommandItem>
|
||||
</UiCommandList>
|
||||
</UiCommand>
|
||||
</div>
|
||||
</UiPopoverContent>
|
||||
</UiPopover>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
21
components/ui/avatar/Avatar.vue
Normal file
21
components/ui/avatar/Avatar.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import type { HTMLAttributes } from 'vue'
|
||||
import { AvatarRoot } from 'radix-vue'
|
||||
import { type AvatarVariants, avatarVariant } from '.'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
class?: HTMLAttributes['class']
|
||||
size?: AvatarVariants['size']
|
||||
shape?: AvatarVariants['shape']
|
||||
}>(), {
|
||||
size: 'sm',
|
||||
shape: 'circle',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AvatarRoot :class="cn(avatarVariant({ size, shape }), props.class)">
|
||||
<slot />
|
||||
</AvatarRoot>
|
||||
</template>
|
||||
11
components/ui/avatar/AvatarFallback.vue
Normal file
11
components/ui/avatar/AvatarFallback.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { AvatarFallback, type AvatarFallbackProps } from 'radix-vue'
|
||||
|
||||
const props = defineProps<AvatarFallbackProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AvatarFallback v-bind="props">
|
||||
<slot />
|
||||
</AvatarFallback>
|
||||
</template>
|
||||
9
components/ui/avatar/AvatarImage.vue
Normal file
9
components/ui/avatar/AvatarImage.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { AvatarImage, type AvatarImageProps } from 'radix-vue'
|
||||
|
||||
const props = defineProps<AvatarImageProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AvatarImage v-bind="props" class="h-full w-full object-cover" />
|
||||
</template>
|
||||
24
components/ui/avatar/index.ts
Normal file
24
components/ui/avatar/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
|
||||
export { default as Avatar } from './Avatar.vue'
|
||||
export { default as AvatarImage } from './AvatarImage.vue'
|
||||
export { default as AvatarFallback } from './AvatarFallback.vue'
|
||||
|
||||
export const avatarVariant = cva(
|
||||
'inline-flex items-center justify-center font-normal text-foreground select-none shrink-0 bg-secondary overflow-hidden',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
sm: 'h-10 w-10 text-xs',
|
||||
base: 'h-16 w-16 text-2xl',
|
||||
lg: 'h-32 w-32 text-5xl',
|
||||
},
|
||||
shape: {
|
||||
circle: 'rounded-full',
|
||||
square: 'rounded-md',
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
export type AvatarVariants = VariantProps<typeof avatarVariant>
|
||||
@@ -1,3 +1,5 @@
|
||||
export { ComboboxPortal } from 'radix-vue'
|
||||
|
||||
export { default as Command } from './Command.vue'
|
||||
export { default as CommandDialog } from './CommandDialog.vue'
|
||||
export { default as CommandEmpty } from './CommandEmpty.vue'
|
||||
|
||||
Reference in New Issue
Block a user