mirror of
https://github.com/versia-pub/frontend.git
synced 2025-12-06 08:28:20 +01:00
feat: ✨ Implement mobile navbar
This commit is contained in:
parent
4ba3ed3d37
commit
0987df7783
9
components/modals/drawer-content.vue
Normal file
9
components/modals/drawer-content.vue
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<template>
|
||||||
|
<DrawerContent class="flex flex-col gap-2 px-4 mb-4 [&>:nth-child(2)]:mt-4">
|
||||||
|
<slot />
|
||||||
|
</DrawerContent>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { DrawerContent } from "../ui/drawer";
|
||||||
|
</script>
|
||||||
31
components/navigation/mobile-navbar.vue
Normal file
31
components/navigation/mobile-navbar.vue
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="fixed md:hidden bottom-0 inset-x-0 border-t h-20 bg-background z-10 flex items-center justify-around *:p-7 *:w-full gap-6 p-6">
|
||||||
|
<Timelines>
|
||||||
|
<Button variant="ghost" size="icon">
|
||||||
|
<Home class="!size-6" />
|
||||||
|
</Button>
|
||||||
|
</Timelines>
|
||||||
|
<Button v-if="identity" :as="NuxtLink" href="/notifications" variant="ghost" size="icon">
|
||||||
|
<Bell class="!size-6" />
|
||||||
|
</Button>
|
||||||
|
<AccountSwitcher>
|
||||||
|
<Button variant="ghost" size="icon">
|
||||||
|
<User class="!size-6" />
|
||||||
|
</Button>
|
||||||
|
</AccountSwitcher>
|
||||||
|
<Button v-if="identity" variant="default" size="icon" :title="m.salty_aloof_turkey_nudge()"
|
||||||
|
@click="useEvent('composer:open')">
|
||||||
|
<Pen class="!size-6" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Bell, Home, Pen, User } from "lucide-vue-next";
|
||||||
|
import * as m from "~/paraglide/messages.js";
|
||||||
|
import { NuxtLink } from "#components";
|
||||||
|
import AccountSwitcher from "../sidebars/account-switcher.vue";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import Timelines from "./timelines.vue";
|
||||||
|
</script>
|
||||||
55
components/navigation/timelines.vue
Normal file
55
components/navigation/timelines.vue
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<Drawer>
|
||||||
|
<DrawerTrigger :as-child="true">
|
||||||
|
<slot />
|
||||||
|
</DrawerTrigger>
|
||||||
|
<DrawerContent>
|
||||||
|
<DrawerClose v-for="item in timelines.filter(
|
||||||
|
i => i.requiresLogin ? !!identity : true,
|
||||||
|
)" :key="item.name" :as-child="true">
|
||||||
|
<Button :as="NuxtLink" :href="item.url" variant="outline" size="lg" class="w-full">
|
||||||
|
<component :is="item.icon" />
|
||||||
|
{{ item.name }}
|
||||||
|
</Button>
|
||||||
|
</DrawerClose>
|
||||||
|
<DialogTitle class="sr-only">{{ m.trite_real_sawfish_drum() }}</DialogTitle>
|
||||||
|
<DialogDescription class="sr-only">{{ m.trite_real_sawfish_drum() }}</DialogDescription>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { BedSingle, Globe, House, MapIcon } from "lucide-vue-next";
|
||||||
|
import * as m from "~/paraglide/messages.js";
|
||||||
|
import { NuxtLink } from "#components";
|
||||||
|
import DrawerContent from "../modals/drawer-content.vue";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import { Drawer, DrawerTrigger } from "../ui/drawer";
|
||||||
|
|
||||||
|
const timelines = [
|
||||||
|
{
|
||||||
|
name: m.bland_chunky_sparrow_propel(),
|
||||||
|
url: "/home",
|
||||||
|
icon: House,
|
||||||
|
requiresLogin: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: m.lost_trick_dog_grace(),
|
||||||
|
url: "/public",
|
||||||
|
icon: MapIcon,
|
||||||
|
requiresLogin: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: m.crazy_game_parrot_pave(),
|
||||||
|
url: "/local",
|
||||||
|
icon: BedSingle,
|
||||||
|
requiresLogin: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: m.real_tame_moose_greet(),
|
||||||
|
url: "/global",
|
||||||
|
icon: Globe,
|
||||||
|
requiresLogin: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
@ -1,23 +1,46 @@
|
||||||
<template>
|
<template>
|
||||||
<DropdownMenu>
|
<Drawer v-if="isMobile">
|
||||||
<DropdownMenuTrigger as-child>
|
<DrawerTrigger :as-child="true">
|
||||||
<SidebarMenuButton size="lg"
|
<slot />
|
||||||
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
|
</DrawerTrigger>
|
||||||
<Avatar v-if="identity" class="size-8" :src="identity.account.avatar" :name="identity.account.display_name" />
|
<DrawerContent>
|
||||||
<Avatar v-else class="size-8" name="AB" />
|
<Button @click="switchAccount(identity.account.id)" variant="outline" size="lg"
|
||||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
:href="`/@${identity.account.username}`" v-for="identity of identities"
|
||||||
<span class="truncate font-semibold" v-render-emojis="identity?.account.emojis">{{
|
class="flex w-full items-center gap-2 px-4 text-left h-20">
|
||||||
identity?.account.display_name ?? "Not signed in"
|
<Avatar class="size-12" :src="identity.account.avatar" :name="identity.account.display_name" />
|
||||||
|
<div class="grid flex-1 text-left leading-tight">
|
||||||
|
<span class="truncate font-semibold" v-render-emojis="identity.account.emojis">{{
|
||||||
|
identity.account.display_name
|
||||||
|
}}</span>
|
||||||
|
<span class="truncate text-sm">@{{
|
||||||
|
identity.account.acct
|
||||||
}}</span>
|
}}</span>
|
||||||
<span class="truncate text-xs" v-if="identity">@{{ identity?.account.acct }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<ChevronsUpDown class="ml-auto size-4" />
|
</Button>
|
||||||
</SidebarMenuButton>
|
<Button variant="secondary" size="lg" class="w-full" @click="signInAction">
|
||||||
|
<UserPlus />
|
||||||
|
{{ m.sunny_pink_hyena_walk() }}
|
||||||
|
</Button>
|
||||||
|
<Button variant="secondary" size="lg" @click="signOut()" v-if="identity">
|
||||||
|
<LogOut />
|
||||||
|
{{ m.sharp_big_mallard_reap() }}
|
||||||
|
</Button>
|
||||||
|
<Button variant="secondary" size="lg" :as="NuxtLink" href="/register" v-else>
|
||||||
|
<LogIn />
|
||||||
|
{{ m.honest_few_baboon_pop() }}
|
||||||
|
</Button>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
<DropdownMenu v-else>
|
||||||
|
<DropdownMenuTrigger :as-child="true">
|
||||||
|
<slot />
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg" side="bottom"
|
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg" side="bottom"
|
||||||
align="end" :side-offset="4">
|
align="end" :side-offset="4">
|
||||||
<DropdownMenuLabel class="p-0 font-normal">
|
<DropdownMenuLabel class="p-0 font-normal">
|
||||||
<Button @click="switchAccount(identity.account.id)" variant="ghost" size="lg" :href="`/@${identity.account.username}`" v-for="identity of identities" class="flex w-full items-center gap-2 px-1 text-left text-sm">
|
<Button @click="switchAccount(identity.account.id)" variant="ghost" size="lg"
|
||||||
|
:href="`/@${identity.account.username}`" v-for="identity of identities"
|
||||||
|
class="flex w-full items-center gap-2 px-1 text-left text-sm">
|
||||||
<Avatar class="size-8" :src="identity.account.avatar" :name="identity.account.display_name" />
|
<Avatar class="size-8" :src="identity.account.avatar" :name="identity.account.display_name" />
|
||||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||||
<span class="truncate font-semibold" v-render-emojis="identity.account.emojis">{{
|
<span class="truncate font-semibold" v-render-emojis="identity.account.emojis">{{
|
||||||
|
|
@ -54,18 +77,14 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {
|
import { BadgeCheck, LogIn, LogOut, UserPlus } from "lucide-vue-next";
|
||||||
BadgeCheck,
|
|
||||||
ChevronsUpDown,
|
|
||||||
LogIn,
|
|
||||||
LogOut,
|
|
||||||
UserPlus,
|
|
||||||
} from "lucide-vue-next";
|
|
||||||
import { toast } from "vue-sonner";
|
import { toast } from "vue-sonner";
|
||||||
import * as m from "~/paraglide/messages.js";
|
import * as m from "~/paraglide/messages.js";
|
||||||
import { NuxtLink } from "#components";
|
import { NuxtLink } from "#components";
|
||||||
|
import DrawerContent from "../modals/drawer-content.vue";
|
||||||
import Avatar from "../profiles/avatar.vue";
|
import Avatar from "../profiles/avatar.vue";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
import { Drawer, DrawerTrigger } from "../ui/drawer";
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
|
|
@ -75,9 +94,9 @@ import {
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "../ui/dropdown-menu";
|
} from "../ui/dropdown-menu";
|
||||||
import { SidebarMenuButton } from "../ui/sidebar";
|
|
||||||
|
|
||||||
const appData = useAppData();
|
const appData = useAppData();
|
||||||
|
const isMobile = useMediaQuery("(max-width: 768px)");
|
||||||
|
|
||||||
const signInAction = () => signIn(appData);
|
const signInAction = () => signIn(appData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@
|
||||||
'https://cdn.versia.pub/branding/icon.svg'
|
'https://cdn.versia.pub/branding/icon.svg'
|
||||||
" :name="instance?.title" />
|
" :name="instance?.title" />
|
||||||
<div class="grid flex-1 text-left text-sm leading-tight">
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||||
<span class="truncate font-semibold">{{ instance?.title ?? m.short_zippy_felix_kick() }}</span>
|
<span class="truncate font-semibold">{{ instance?.title ?? m.short_zippy_felix_kick()
|
||||||
|
}}</span>
|
||||||
<span class="truncate text-xs">{{ m.top_active_ocelot_cure() }}</span>
|
<span class="truncate text-xs">{{ m.top_active_ocelot_cure() }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- <ChevronsUpDown class="ml-auto" /> -->
|
<!-- <ChevronsUpDown class="ml-auto" /> -->
|
||||||
|
|
@ -67,7 +68,21 @@
|
||||||
<SidebarFooter>
|
<SidebarFooter>
|
||||||
<SidebarMenu class="gap-3">
|
<SidebarMenu class="gap-3">
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<AccountSwitcher />
|
<AccountSwitcher>
|
||||||
|
<SidebarMenuButton size="lg"
|
||||||
|
class="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground">
|
||||||
|
<Avatar v-if="identity" class="size-8" :src="identity.account.avatar"
|
||||||
|
:name="identity.account.display_name" />
|
||||||
|
<Avatar v-else class="size-8" name="AB" />
|
||||||
|
<div class="grid flex-1 text-left text-sm leading-tight">
|
||||||
|
<span class="truncate font-semibold" v-render-emojis="identity?.account.emojis">{{
|
||||||
|
identity?.account.display_name ?? "Not signed in"
|
||||||
|
}}</span>
|
||||||
|
<span class="truncate text-xs" v-if="identity">@{{ identity?.account.acct }}</span>
|
||||||
|
</div>
|
||||||
|
<ChevronsUpDown class="ml-auto size-4" />
|
||||||
|
</SidebarMenuButton>
|
||||||
|
</AccountSwitcher>
|
||||||
</SidebarMenuItem>
|
</SidebarMenuItem>
|
||||||
<SidebarMenuItem class="flex flex-col gap-2">
|
<SidebarMenuItem class="flex flex-col gap-2">
|
||||||
<Button variant="default" size="lg" class="w-full group-data-[collapsible=icon]:px-4"
|
<Button variant="default" size="lg" class="w-full group-data-[collapsible=icon]:px-4"
|
||||||
|
|
@ -92,6 +107,7 @@ import {
|
||||||
BedSingle,
|
BedSingle,
|
||||||
Bell,
|
Bell,
|
||||||
ChevronRight,
|
ChevronRight,
|
||||||
|
ChevronsUpDown,
|
||||||
DownloadCloud,
|
DownloadCloud,
|
||||||
Globe,
|
Globe,
|
||||||
House,
|
House,
|
||||||
|
|
|
||||||
19
components/ui/drawer/Drawer.vue
Normal file
19
components/ui/drawer/Drawer.vue
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useForwardPropsEmits } from "radix-vue";
|
||||||
|
import type { DrawerRootEmits, DrawerRootProps } from "vaul-vue";
|
||||||
|
import { DrawerRoot } from "vaul-vue";
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<DrawerRootProps>(), {
|
||||||
|
shouldScaleBackground: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits<DrawerRootEmits>();
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(props, emits);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DrawerRoot v-bind="forwarded">
|
||||||
|
<slot />
|
||||||
|
</DrawerRoot>
|
||||||
|
</template>
|
||||||
30
components/ui/drawer/DrawerContent.vue
Normal file
30
components/ui/drawer/DrawerContent.vue
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { DialogContentEmits, DialogContentProps } from "radix-vue";
|
||||||
|
import { useForwardPropsEmits } from "radix-vue";
|
||||||
|
import { DrawerContent, DrawerPortal } from "vaul-vue";
|
||||||
|
import type { HtmlHTMLAttributes } from "vue";
|
||||||
|
import DrawerOverlay from "./DrawerOverlay.vue";
|
||||||
|
|
||||||
|
const props = defineProps<
|
||||||
|
DialogContentProps & { class?: HtmlHTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
const emits = defineEmits<DialogContentEmits>();
|
||||||
|
|
||||||
|
const forwarded = useForwardPropsEmits(props, emits);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DrawerPortal>
|
||||||
|
<DrawerOverlay />
|
||||||
|
<DrawerContent
|
||||||
|
v-bind="forwarded" :class="cn(
|
||||||
|
'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background',
|
||||||
|
props.class,
|
||||||
|
)"
|
||||||
|
>
|
||||||
|
<div class="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
|
||||||
|
<slot />
|
||||||
|
</DrawerContent>
|
||||||
|
</DrawerPortal>
|
||||||
|
</template>
|
||||||
22
components/ui/drawer/DrawerDescription.vue
Normal file
22
components/ui/drawer/DrawerDescription.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { DrawerDescriptionProps } from "vaul-vue";
|
||||||
|
import { DrawerDescription } from "vaul-vue";
|
||||||
|
import { type HtmlHTMLAttributes, computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<
|
||||||
|
DrawerDescriptionProps & { class?: HtmlHTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DrawerDescription v-bind="delegatedProps" :class="cn('text-sm text-muted-foreground', props.class)">
|
||||||
|
<slot />
|
||||||
|
</DrawerDescription>
|
||||||
|
</template>
|
||||||
14
components/ui/drawer/DrawerFooter.vue
Normal file
14
components/ui/drawer/DrawerFooter.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HtmlHTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HtmlHTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('mt-auto flex flex-col gap-2 p-4', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
14
components/ui/drawer/DrawerHeader.vue
Normal file
14
components/ui/drawer/DrawerHeader.vue
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { HtmlHTMLAttributes } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
class?: HtmlHTMLAttributes["class"];
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div :class="cn('grid gap-1.5 p-4 text-center sm:text-left', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
20
components/ui/drawer/DrawerOverlay.vue
Normal file
20
components/ui/drawer/DrawerOverlay.vue
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { DialogOverlayProps } from "radix-vue";
|
||||||
|
import { DrawerOverlay } from "vaul-vue";
|
||||||
|
import { type HtmlHTMLAttributes, computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<
|
||||||
|
DialogOverlayProps & { class?: HtmlHTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DrawerOverlay v-bind="delegatedProps" :class="cn('fixed inset-0 z-50 bg-black/80', props.class)" />
|
||||||
|
</template>
|
||||||
22
components/ui/drawer/DrawerTitle.vue
Normal file
22
components/ui/drawer/DrawerTitle.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { DrawerTitleProps } from "vaul-vue";
|
||||||
|
import { DrawerTitle } from "vaul-vue";
|
||||||
|
import { type HtmlHTMLAttributes, computed } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps<
|
||||||
|
DrawerTitleProps & { class?: HtmlHTMLAttributes["class"] }
|
||||||
|
>();
|
||||||
|
|
||||||
|
const delegatedProps = computed(() => {
|
||||||
|
const { class: _, ...delegated } = props;
|
||||||
|
|
||||||
|
return delegated;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DrawerTitle v-bind="delegatedProps" :class="cn('text-lg font-semibold leading-none tracking-tight', props.class)">
|
||||||
|
<slot />
|
||||||
|
</DrawerTitle>
|
||||||
|
</template>
|
||||||
8
components/ui/drawer/index.ts
Normal file
8
components/ui/drawer/index.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
export { default as Drawer } from "./Drawer.vue";
|
||||||
|
export { default as DrawerContent } from "./DrawerContent.vue";
|
||||||
|
export { default as DrawerDescription } from "./DrawerDescription.vue";
|
||||||
|
export { default as DrawerFooter } from "./DrawerFooter.vue";
|
||||||
|
export { default as DrawerHeader } from "./DrawerHeader.vue";
|
||||||
|
export { default as DrawerOverlay } from "./DrawerOverlay.vue";
|
||||||
|
export { default as DrawerTitle } from "./DrawerTitle.vue";
|
||||||
|
export { DrawerClose, DrawerPortal, DrawerTrigger } from "vaul-vue";
|
||||||
|
|
@ -16,12 +16,14 @@
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
<MobileNavbar />
|
||||||
<ComposerDialog />
|
<ComposerDialog />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ComposerDialog from "~/components/composer/dialog.vue";
|
import ComposerDialog from "~/components/composer/dialog.vue";
|
||||||
import SquarePattern from "~/components/graphics/square-pattern.vue";
|
import SquarePattern from "~/components/graphics/square-pattern.vue";
|
||||||
|
import MobileNavbar from "~/components/navigation/mobile-navbar.vue";
|
||||||
import Sidebar from "~/components/sidebars/sidebar.vue";
|
import Sidebar from "~/components/sidebars/sidebar.vue";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,9 @@ export default defineNuxtConfig({
|
||||||
],
|
],
|
||||||
htmlAttrs: { lang: "en-us" },
|
htmlAttrs: { lang: "en-us" },
|
||||||
},
|
},
|
||||||
|
rootAttrs: {
|
||||||
|
"vaul-drawer-wrapper": true,
|
||||||
|
},
|
||||||
keepalive: true,
|
keepalive: true,
|
||||||
},
|
},
|
||||||
nitro: {
|
nitro: {
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@
|
||||||
"shadcn-nuxt": "0.11.3",
|
"shadcn-nuxt": "0.11.3",
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"vaul-vue": "^0.2.0",
|
||||||
"vee-validate": "^4.14.7",
|
"vee-validate": "^4.14.7",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue