mirror of
https://github.com/versia-pub/frontend.git
synced 2026-03-13 03:29:16 +01:00
chore: ⬆️ Upgrade to Nuxt 4
Some checks failed
Some checks failed
This commit is contained in:
parent
8debe97f63
commit
7f7cf20311
386 changed files with 2376 additions and 2332 deletions
91
app/components/sidebars/account/account-manager.vue
Normal file
91
app/components/sidebars/account/account-manager.vue
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
<template>
|
||||
<Dialog>
|
||||
<DialogTrigger as-child>
|
||||
<slot />
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Accounts</DialogTitle>
|
||||
<DialogDescription class="sr-only">
|
||||
Manage your accounts and settings.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div v-if="identities.length > 0" class="grid gap-4 py-2">
|
||||
<div v-for="identity of identities" :key="identity.account.id"
|
||||
class="grid grid-cols-[1fr_auto] has-[>[data-switch]]:grid-cols-[1fr_auto_auto] gap-2">
|
||||
<TinyCard :account="identity.account" :domain="identity.instance.domain" naked />
|
||||
<Button data-switch v-if="currentIdentity?.id !== identity.id"
|
||||
@click="switchAccount(identity.account.id)" variant="outline">
|
||||
Switch
|
||||
</Button>
|
||||
<Button @click="signOut(appData, identity)" variant="outline" size="icon"
|
||||
:title="m.sharp_big_mallard_reap()">
|
||||
<LogOut />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Log in to or register an account on your favourite instance.
|
||||
</p>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button :as="NuxtLink" href="/register" variant="outline">
|
||||
<UserPlus />
|
||||
{{ m.honest_few_baboon_pop() }}
|
||||
</Button>
|
||||
<Button @click="signInAction">
|
||||
<LogIn />
|
||||
{{ m.sunny_pink_hyena_walk() }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { LogIn, LogOut, UserPlus } from "lucide-vue-next";
|
||||
import { toast } from "vue-sonner";
|
||||
import { NuxtLink } from "#components";
|
||||
import { identity as currentIdentity } from "#imports";
|
||||
import TinyCard from "~/components/profiles/tiny-card.vue";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "~/components/ui/dialog";
|
||||
import * as m from "~~/paraglide/messages.js";
|
||||
|
||||
const appData = useAppData();
|
||||
|
||||
const signInAction = async () => signIn(appData, await askForInstance());
|
||||
|
||||
const switchAccount = async (userId: string) => {
|
||||
if (userId === currentIdentity.value?.account.id) {
|
||||
return await navigateTo(`/@${currentIdentity.value.account.username}`);
|
||||
}
|
||||
|
||||
const id = toast.loading("Switching account...");
|
||||
|
||||
const identityToSwitch = identities.value.find(
|
||||
(i) => i.account.id === userId,
|
||||
);
|
||||
|
||||
if (!identityToSwitch) {
|
||||
toast.dismiss(id);
|
||||
toast.error("No identity to switch to");
|
||||
return;
|
||||
}
|
||||
|
||||
currentIdentity.value = identityToSwitch;
|
||||
toast.dismiss(id);
|
||||
toast.success("Switched account");
|
||||
|
||||
window.location.href = "/";
|
||||
};
|
||||
</script>
|
||||
61
app/components/sidebars/footer/footer-actions.vue
Normal file
61
app/components/sidebars/footer/footer-actions.vue
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
ChevronsUpDown,
|
||||
Cog,
|
||||
DownloadCloud,
|
||||
Pen,
|
||||
UserPlus,
|
||||
} from "lucide-vue-next";
|
||||
import TinyCard from "~/components/profiles/tiny-card.vue";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
SidebarFooter,
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from "~/components/ui/sidebar";
|
||||
import * as m from "~~/paraglide/messages.js";
|
||||
import AccountManager from "../account/account-manager.vue";
|
||||
|
||||
const { $pwa } = useNuxtApp();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SidebarFooter>
|
||||
<SidebarMenu class="gap-3">
|
||||
<SidebarMenuItem>
|
||||
<AccountManager>
|
||||
<SidebarMenuButton v-if="identity" size="lg">
|
||||
<TinyCard :account="identity.account" :domain="identity.instance.domain" naked />
|
||||
<ChevronsUpDown class="ml-auto size-4" />
|
||||
</SidebarMenuButton>
|
||||
<SidebarMenuButton v-else>
|
||||
<UserPlus />
|
||||
{{ m.sunny_pink_hyena_walk() }}
|
||||
<ChevronsUpDown class="ml-auto size-4" />
|
||||
</SidebarMenuButton>
|
||||
</AccountManager>
|
||||
</SidebarMenuItem>
|
||||
<SidebarMenuItem class="flex flex-col gap-2">
|
||||
<Button v-if="identity" variant="default" size="lg" class="w-full group-data-[collapsible=icon]:px-4"
|
||||
@click="useEvent('composer:open')">
|
||||
<Pen />
|
||||
<span class="group-data-[collapsible=icon]:hidden">
|
||||
{{ m.salty_aloof_turkey_nudge() }}
|
||||
</span>
|
||||
</Button>
|
||||
<Button v-if="identity" size="lg" variant="secondary" @click="useEvent('preferences:open')">
|
||||
<Cog />
|
||||
Preferences
|
||||
</Button>
|
||||
<Button v-if="$pwa?.needRefresh" variant="destructive" size="lg"
|
||||
class="w-full group-data-[collapsible=icon]:px-4" @click="$pwa?.updateServiceWorker(true)">
|
||||
<DownloadCloud />
|
||||
<span class="group-data-[collapsible=icon]:hidden">
|
||||
{{ m.quaint_low_felix_pave() }}
|
||||
</span>
|
||||
</Button>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
</template>
|
||||
22
app/components/sidebars/instance/instance-header.vue
Normal file
22
app/components/sidebars/instance/instance-header.vue
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import InstanceSmallCard from "~/components/instance/small-card.vue";
|
||||
import {
|
||||
SidebarHeader,
|
||||
SidebarMenu,
|
||||
SidebarMenuItem,
|
||||
} from "~/components/ui/sidebar";
|
||||
|
||||
const instance = useInstance();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<NuxtLink href="/">
|
||||
<InstanceSmallCard v-if="instance" :instance="instance" />
|
||||
</NuxtLink>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarHeader>
|
||||
</template>
|
||||
36
app/components/sidebars/left-sidebar.vue
Normal file
36
app/components/sidebars/left-sidebar.vue
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<template>
|
||||
<Sidebar collapsible="offcanvas">
|
||||
<InstanceHeader />
|
||||
<SidebarContent>
|
||||
<SidebarGroup>
|
||||
<SidebarGroupLabel>{{
|
||||
m.trite_real_sawfish_drum()
|
||||
}}</SidebarGroupLabel>
|
||||
<NavItems
|
||||
:items="
|
||||
sidebarConfig.other.filter((i) =>
|
||||
i.requiresLogin ? !!identity : true
|
||||
)
|
||||
"
|
||||
/>
|
||||
</SidebarGroup>
|
||||
</SidebarContent>
|
||||
<FooterActions />
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { sidebarConfig } from "~/components/sidebars/sidebar";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarGroup,
|
||||
SidebarGroupLabel,
|
||||
SidebarRail,
|
||||
} from "~/components/ui/sidebar";
|
||||
import * as m from "~~/paraglide/messages.js";
|
||||
import FooterActions from "./footer/footer-actions.vue";
|
||||
import InstanceHeader from "./instance/instance-header.vue";
|
||||
import NavItems from "./navigation/nav-items.vue";
|
||||
</script>
|
||||
59
app/components/sidebars/navigation/nav-group.vue
Normal file
59
app/components/sidebars/navigation/nav-group.vue
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<script setup lang="ts">
|
||||
import { ChevronRight } from "lucide-vue-next";
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
CollapsibleTrigger,
|
||||
} from "~/components/ui/collapsible";
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
SidebarMenuSub,
|
||||
SidebarMenuSubButton,
|
||||
SidebarMenuSubItem,
|
||||
} from "~/components/ui/sidebar";
|
||||
import type { SidebarNavMainItem } from "~/types/sidebar";
|
||||
|
||||
defineProps<{
|
||||
items: SidebarNavMainItem[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SidebarMenu>
|
||||
<Collapsible
|
||||
v-for="item in items"
|
||||
:key="item.title"
|
||||
as-child
|
||||
default-open
|
||||
class="group/collapsible"
|
||||
>
|
||||
<SidebarMenuItem>
|
||||
<CollapsibleTrigger as-child>
|
||||
<SidebarMenuButton :tooltip="item.title">
|
||||
<component :is="item.icon" />
|
||||
{{ item.title }}
|
||||
<ChevronRight
|
||||
class="ml-auto transition-transform group-data-[state=open]/collapsible:rotate-180"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
<SidebarMenuSub>
|
||||
<SidebarMenuSubItem
|
||||
v-for="subItem in item.items"
|
||||
:key="subItem.title"
|
||||
>
|
||||
<SidebarMenuSubButton as-child>
|
||||
<NuxtLink :href="subItem.url">
|
||||
<span>{{ subItem.title }}</span>
|
||||
</NuxtLink>
|
||||
</SidebarMenuSubButton>
|
||||
</SidebarMenuSubItem>
|
||||
</SidebarMenuSub>
|
||||
</CollapsibleContent>
|
||||
</SidebarMenuItem>
|
||||
</Collapsible>
|
||||
</SidebarMenu>
|
||||
</template>
|
||||
25
app/components/sidebars/navigation/nav-items.vue
Normal file
25
app/components/sidebars/navigation/nav-items.vue
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
SidebarMenu,
|
||||
SidebarMenuButton,
|
||||
SidebarMenuItem,
|
||||
} from "~/components/ui/sidebar";
|
||||
import type { SidebarNavItem } from "~/types/sidebar";
|
||||
|
||||
defineProps<{
|
||||
items: SidebarNavItem[];
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem v-for="item in items" :key="item.title">
|
||||
<SidebarMenuButton as-child>
|
||||
<NuxtLink :href="item.url">
|
||||
<component :is="item.icon" />
|
||||
<span>{{ item.title }}</span>
|
||||
</NuxtLink>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</template>
|
||||
17
app/components/sidebars/right-sidebar.vue
Normal file
17
app/components/sidebars/right-sidebar.vue
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<Sidebar
|
||||
side="right"
|
||||
collapsible="none"
|
||||
class="hidden md:flex"
|
||||
style="--sidebar-width: 24rem; --sidebar-width-mobile: 18rem"
|
||||
>
|
||||
<SidebarContent class="overflow-y-auto *:p-2 *:gap-2">
|
||||
<NotificationsTimeline />
|
||||
</SidebarContent>
|
||||
</Sidebar>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import NotificationsTimeline from "~/components/timelines/notifications.vue";
|
||||
import { Sidebar, SidebarContent } from "~/components/ui/sidebar";
|
||||
</script>
|
||||
39
app/components/sidebars/sidebar.ts
Normal file
39
app/components/sidebars/sidebar.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import { BedSingle, Bell, Globe, House, MapIcon } from "lucide-vue-next";
|
||||
import type { SidebarConfig } from "~/types/sidebar";
|
||||
import * as m from "~~/paraglide/messages.js";
|
||||
|
||||
export const sidebarConfig: SidebarConfig = {
|
||||
navMain: [],
|
||||
other: [
|
||||
{
|
||||
title: m.bland_chunky_sparrow_propel(),
|
||||
url: "/home",
|
||||
icon: House,
|
||||
requiresLogin: true,
|
||||
},
|
||||
{
|
||||
title: m.lost_trick_dog_grace(),
|
||||
url: "/public",
|
||||
icon: MapIcon,
|
||||
requiresLogin: false,
|
||||
},
|
||||
{
|
||||
title: m.crazy_game_parrot_pave(),
|
||||
url: "/local",
|
||||
icon: BedSingle,
|
||||
requiresLogin: false,
|
||||
},
|
||||
{
|
||||
title: m.real_tame_moose_greet(),
|
||||
url: "/global",
|
||||
icon: Globe,
|
||||
requiresLogin: false,
|
||||
},
|
||||
{
|
||||
title: m.that_patchy_mare_snip(),
|
||||
url: "/notifications",
|
||||
icon: Bell,
|
||||
requiresLogin: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
27
app/components/sidebars/sidebar.vue
Normal file
27
app/components/sidebars/sidebar.vue
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<script setup lang="ts">
|
||||
import Timelines from "~/components/navigation/timelines.vue";
|
||||
import LeftSidebar from "./left-sidebar.vue";
|
||||
import RightSidebar from "./right-sidebar.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const isMd = useMediaQuery("(max-width: 768px)");
|
||||
const showTimelines = computed(
|
||||
() =>
|
||||
["/", "/home", "/local", "/public", "/global"].includes(route.path) &&
|
||||
isMd.value,
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LeftSidebar />
|
||||
<main class="grow h-dvh overflow-y-auto">
|
||||
<header
|
||||
v-if="showTimelines"
|
||||
class="flex h-16 items-center bg-background/80 backdrop-blur-2xl sticky top-0 inset-x-0 z-10 p-4"
|
||||
>
|
||||
<Timelines />
|
||||
</header>
|
||||
<slot />
|
||||
</main>
|
||||
<RightSidebar v-if="identity" v-show="preferences.display_notifications_sidebar" />
|
||||
</template>
|
||||
Loading…
Add table
Add a link
Reference in a new issue