mirror of
https://github.com/versia-pub/frontend.git
synced 2026-01-26 04:16:02 +01:00
refactor: ♻️ Make auth store require less null checks
This commit is contained in:
parent
68e23a818a
commit
b23ed66401
|
|
@ -56,13 +56,13 @@ useSeoMeta({
|
|||
titleTemplate: (titleChunk) => {
|
||||
return titleChunk ? `${titleChunk} · Versia` : "Versia";
|
||||
},
|
||||
title: computed(() => authStore.instance?.title ?? ""),
|
||||
ogImage: computed(() => authStore.instance?.banner?.url),
|
||||
twitterTitle: computed(() => authStore.instance?.title ?? ""),
|
||||
title: computed(() => authStore.instanceOptional?.title ?? ""),
|
||||
ogImage: computed(() => authStore.instanceOptional?.banner?.url),
|
||||
twitterTitle: computed(() => authStore.instanceOptional?.title ?? ""),
|
||||
twitterDescription: computed(() =>
|
||||
convert(description.value?.content ?? ""),
|
||||
),
|
||||
twitterImage: computed(() => authStore.instance?.banner?.url),
|
||||
twitterImage: computed(() => authStore.instanceOptional?.banner?.url),
|
||||
description: computed(() => convert(description.value?.content ?? "")),
|
||||
ogDescription: computed(() => convert(description.value?.content ?? "")),
|
||||
ogSiteName: "Versia",
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ const composerKey = props.relation
|
|||
const store = useComposerStore(composerKey)();
|
||||
const authStore = useAuthStore();
|
||||
const charactersLeft = computed(() => {
|
||||
const max = authStore.instance?.configuration.statuses.max_characters ?? 0;
|
||||
const max = authStore.instance.configuration.statuses.max_characters;
|
||||
|
||||
return max - store.rawContent.length;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<Command
|
||||
class="rounded border shadow-md min-w-[200px] h-fit not-prose"
|
||||
class="rounded border shadow-md min-w-50 h-fit not-prose"
|
||||
:selected-value="emojis[selectedIndex]?.id"
|
||||
>
|
||||
<CommandList>
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
class="scroll-m-10"
|
||||
>
|
||||
<img
|
||||
class="h-[1lh] align-middle inline hover:scale-110 transition-transform duration-75 ease-in-out"
|
||||
class="h-lh align-middle inline hover:scale-110 transition-transform duration-75 ease-in-out"
|
||||
:src="emoji.url"
|
||||
:title="emoji.shortcode"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -126,11 +126,9 @@ export const emojiSuggestion = {
|
|||
return [];
|
||||
}
|
||||
|
||||
const emojis = authStore.emojis;
|
||||
|
||||
return go(
|
||||
query,
|
||||
emojis
|
||||
authStore.emojis
|
||||
.filter((emoji) => emoji.shortcode.includes(query))
|
||||
.map((emoji) => ({
|
||||
key: emoji.shortcode,
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ const isValid = ref(false);
|
|||
:open="isOpen"
|
||||
@update:open="isOpen = false"
|
||||
>
|
||||
<AlertDialogContent class="sm:max-w-[425px] flex flex-col">
|
||||
<AlertDialogContent class="sm:max-w-106.25 flex flex-col">
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{ modalOptions.title }}</AlertDialogTitle>
|
||||
<AlertDialogDescription v-if="modalOptions.message">
|
||||
|
|
|
|||
|
|
@ -44,14 +44,13 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import type { CustomEmoji, Status } from "@versia/client/schemas";
|
||||
import { Ellipsis, Heart, Quote, Repeat, Reply, Smile } from "lucide-vue-next";
|
||||
import { Heart, Quote, Repeat, Reply, Smile } from "lucide-vue-next";
|
||||
import { toast } from "vue-sonner";
|
||||
import type { z } from "zod";
|
||||
import * as m from "~~/paraglide/messages.js";
|
||||
import { getLocale } from "~~/paraglide/runtime";
|
||||
import { confirmModalService } from "../modals/composable";
|
||||
import ActionButton from "./action-button.vue";
|
||||
import Menu from "./menu.vue";
|
||||
import type { UnicodeEmoji } from "./reactions/picker/emoji";
|
||||
import Picker from "./reactions/picker/index.vue";
|
||||
|
||||
|
|
|
|||
|
|
@ -136,8 +136,8 @@ const _delete = async () => {
|
|||
{{ m.tense_quick_cod_favor() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="authStore.isSignedIn && !authorIsMe" />
|
||||
<DropdownMenuGroup v-if="authStore.isSignedIn && !authorIsMe">
|
||||
<DropdownMenuSeparator v-if="authorIsMe" />
|
||||
<DropdownMenuGroup v-if="authorIsMe">
|
||||
<DropdownMenuItem as="button" :disabled="true">
|
||||
<Flag />
|
||||
{{ m.great_few_jaguar_rise() }}
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ const copy = (data: string) => {
|
|||
const authStore = useAuthStore();
|
||||
|
||||
const data: [string, string | VNode][] = [
|
||||
["User ID", authStore.account?.id ?? ""],
|
||||
["Instance domain", authStore.instance?.domain ?? ""],
|
||||
["Instance version", authStore.instance?.versia_version ?? ""],
|
||||
["User ID", authStore.account.id],
|
||||
["Instance domain", authStore.instance.domain],
|
||||
["Instance version", authStore.instance.versia_version ?? ""],
|
||||
["Client ID", authStore.application?.client_id ?? ""],
|
||||
[
|
||||
"Client secret",
|
||||
|
|
@ -55,7 +55,7 @@ const data: [string, string | VNode][] = [
|
|||
class="font-sans"
|
||||
size="sm"
|
||||
// @ts-expect-error missing onClick types
|
||||
onClick={() => copy(authStore.token?.access_token ?? "")}
|
||||
onClick={() => copy(authStore.token.access_token)}
|
||||
>
|
||||
Click to copy
|
||||
</Button>,
|
||||
|
|
|
|||
|
|
@ -76,12 +76,12 @@ useListen("preferences:open", () => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="open" v-if="authStore.isSignedIn">
|
||||
<Dialog v-model:open="open">
|
||||
<DialogContent
|
||||
class="md:max-w-5xl w-full h-full p-0 md:max-h-[70dvh] overflow-hidden"
|
||||
>
|
||||
<Tabs
|
||||
class="md:grid-cols-[auto_minmax(0,1fr)] !grid gap-2 *:p-4 overflow-hidden *:overflow-y-auto *:h-full"
|
||||
class="md:grid-cols-[auto_minmax(0,1fr)] grid! gap-2 *:p-4 overflow-hidden *:overflow-y-auto *:h-full"
|
||||
orientation="vertical"
|
||||
:default-value="pages[0]"
|
||||
>
|
||||
|
|
@ -92,8 +92,8 @@ useListen("preferences:open", () => {
|
|||
class="grid gap-3 items-center grid-cols-[auto_minmax(0,1fr)]"
|
||||
>
|
||||
<Avatar
|
||||
:name="authStore.account!.display_name || authStore.account!.username"
|
||||
:src="authStore.account!.avatar"
|
||||
:name="authStore.account.display_name || authStore.account.username"
|
||||
:src="authStore.account.avatar"
|
||||
/>
|
||||
<DialogTitle>Preferences</DialogTitle>
|
||||
</div>
|
||||
|
|
@ -101,7 +101,7 @@ useListen("preferences:open", () => {
|
|||
Make changes to your preferences here.
|
||||
</DialogDescription>
|
||||
<TabsList
|
||||
class="md:grid md:grid-cols-1 w-full h-fit *:justify-start !justify-start"
|
||||
class="md:grid md:grid-cols-1 w-full h-fit *:justify-start justify-start!"
|
||||
>
|
||||
<TabsTrigger
|
||||
v-for="page in pages"
|
||||
|
|
|
|||
|
|
@ -37,10 +37,6 @@ const canEdit =
|
|||
authStore.permissions.includes(RolePermission.ManageEmojis);
|
||||
|
||||
const deleteAll = async () => {
|
||||
if (!authStore.isSignedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { confirmed } = await confirmModalService.confirm({
|
||||
title: m.tense_quick_cod_favor(),
|
||||
message: m.next_hour_jurgen_sprout({
|
||||
|
|
|
|||
|
|
@ -50,10 +50,6 @@ const { emoji } = defineProps<{
|
|||
const authStore = useAuthStore();
|
||||
|
||||
const editName = async () => {
|
||||
if (!authStore.isSignedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await confirmModalService.confirm({
|
||||
title: m.slimy_awful_florian_sail(),
|
||||
defaultValue: emoji.shortcode,
|
||||
|
|
@ -83,10 +79,6 @@ const editName = async () => {
|
|||
};
|
||||
|
||||
const _delete = async () => {
|
||||
if (!authStore.isSignedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { confirmed } = await confirmModalService.confirm({
|
||||
title: m.tense_quick_cod_favor(),
|
||||
message: m.honest_factual_carp_aspire(),
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ const columns: ColumnDef<z.infer<typeof CustomEmoji>>[] = [
|
|||
src={row.getValue("url")}
|
||||
alt={`:${row.getValue("shortcode")}:`}
|
||||
title={row.getValue("shortcode")}
|
||||
class="h-[1lh] align-middle inline not-prose hover:scale-110 transition-transform duration-75 ease-in-out"
|
||||
class="h-lh align-middle inline not-prose hover:scale-110 transition-transform duration-75 ease-in-out"
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
|
@ -108,7 +108,7 @@ const columns: ColumnDef<z.infer<typeof CustomEmoji>>[] = [
|
|||
return (
|
||||
<Button
|
||||
variant="link"
|
||||
class="!p-0 !h-auto"
|
||||
class="p-0! h-auto!"
|
||||
// @ts-expect-error types don't include onClick
|
||||
onClick={() =>
|
||||
column.toggleSorting(column.getIsSorted() === "asc")
|
||||
|
|
@ -135,7 +135,7 @@ const columns: ColumnDef<z.infer<typeof CustomEmoji>>[] = [
|
|||
return (
|
||||
<Button
|
||||
variant="link"
|
||||
class="!p-0 !h-auto"
|
||||
class="p-0! h-auto!"
|
||||
// @ts-expect-error types don't include onClick
|
||||
onClick={() =>
|
||||
column.toggleSorting(column.getIsSorted() === "asc")
|
||||
|
|
@ -164,7 +164,7 @@ const columns: ColumnDef<z.infer<typeof CustomEmoji>>[] = [
|
|||
return (
|
||||
<Button
|
||||
variant="link"
|
||||
class="!p-0 !h-auto"
|
||||
class="p-0! h-auto!"
|
||||
// @ts-expect-error types don't include onClick
|
||||
onClick={() => {
|
||||
const filter = column.getFilterValue();
|
||||
|
|
|
|||
|
|
@ -203,25 +203,21 @@ const formSchema = toTypedSchema(
|
|||
.refine(
|
||||
(v) =>
|
||||
v.size <=
|
||||
(authStore.instance?.configuration.emojis
|
||||
.emoji_size_limit ?? Number.POSITIVE_INFINITY),
|
||||
authStore.instance.configuration.emojis.emoji_size_limit,
|
||||
m.orange_weird_parakeet_hug({
|
||||
count:
|
||||
authStore.instance?.configuration.emojis
|
||||
.emoji_size_limit ?? Number.POSITIVE_INFINITY,
|
||||
count: authStore.instance.configuration.emojis
|
||||
.emoji_size_limit,
|
||||
}),
|
||||
),
|
||||
shortcode: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(
|
||||
authStore.instance?.configuration.emojis
|
||||
.max_shortcode_characters ?? Number.POSITIVE_INFINITY,
|
||||
authStore.instance.configuration.emojis
|
||||
.max_shortcode_characters,
|
||||
m.solid_inclusive_owl_hug({
|
||||
count:
|
||||
authStore.instance?.configuration.emojis
|
||||
.max_shortcode_characters ??
|
||||
Number.POSITIVE_INFINITY,
|
||||
count: authStore.instance.configuration.emojis
|
||||
.max_shortcode_characters,
|
||||
}),
|
||||
)
|
||||
.regex(emojiValidator),
|
||||
|
|
@ -238,13 +234,11 @@ const formSchema = toTypedSchema(
|
|||
alt: z
|
||||
.string()
|
||||
.max(
|
||||
authStore.instance?.configuration.emojis
|
||||
.max_description_characters ?? Number.POSITIVE_INFINITY,
|
||||
authStore.instance.configuration.emojis
|
||||
.max_description_characters,
|
||||
m.key_ago_hound_emerge({
|
||||
count:
|
||||
authStore.instance?.configuration.emojis
|
||||
.max_description_characters ??
|
||||
Number.POSITIVE_INFINITY,
|
||||
count: authStore.instance.configuration.emojis
|
||||
.max_description_characters,
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
|
|
@ -255,10 +249,6 @@ const { isSubmitting, handleSubmit, values, setFieldValue } = useForm({
|
|||
});
|
||||
|
||||
const submit = handleSubmit(async (values) => {
|
||||
if (!authStore.isSignedIn) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = toast.loading(m.factual_gray_mouse_believe());
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
<FormField v-slot="{ setValue }" name="avatar">
|
||||
<TextInput :title="m.safe_icy_bulldog_quell()">
|
||||
<ImageUploader
|
||||
v-model:image="authStore.account!.avatar"
|
||||
v-model:image="authStore.account.avatar"
|
||||
@submit-file="(file) => setValue(file)"
|
||||
@submit-url="(url) => setValue(url)"
|
||||
/>
|
||||
|
|
@ -143,10 +143,6 @@ const dirty = computed(() => form.meta.value.dirty);
|
|||
const submitting = ref(false);
|
||||
const authStore = useAuthStore();
|
||||
|
||||
if (!(authStore.instance && authStore.account)) {
|
||||
throw new Error("Not signed in.");
|
||||
}
|
||||
|
||||
const schema = formSchema(authStore.instance);
|
||||
|
||||
const form = useForm({
|
||||
|
|
@ -167,7 +163,7 @@ const form = useForm({
|
|||
});
|
||||
|
||||
const save = form.handleSubmit(async (values) => {
|
||||
if (submitting.value || !authStore.account) {
|
||||
if (submitting.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +194,7 @@ const save = form.handleSubmit(async (values) => {
|
|||
: values.discoverable,
|
||||
// Can't compare two arrays directly in JS, so we need to check if all fields are the same
|
||||
fields_attributes: values.fields.every((field) =>
|
||||
authStore.account?.source?.fields?.some(
|
||||
authStore.account.source?.fields?.some(
|
||||
(f) => f.name === field.name && f.value === field.value,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@
|
|||
{{ m.active_trite_lark_inspire() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="authStore.isSignedIn && !isMe" />
|
||||
<DropdownMenuGroup v-if="authStore.isSignedIn && !isMe">
|
||||
<DropdownMenuSeparator v-if="!isMe" />
|
||||
<DropdownMenuGroup v-if="!isMe">
|
||||
<DropdownMenuItem as="button" @click="muteUser(account.id)">
|
||||
<VolumeX />
|
||||
{{ m.spare_wild_mole_intend() }}
|
||||
|
|
@ -63,8 +63,8 @@
|
|||
{{ m.slow_chunky_chipmunk_hush() }}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator v-if="authStore.isSignedIn && !isMe" />
|
||||
<DropdownMenuGroup v-if="authStore.isSignedIn && !isMe">
|
||||
<DropdownMenuSeparator v-if="!isMe" />
|
||||
<DropdownMenuGroup v-if="!isMe">
|
||||
<DropdownMenuItem as="button" :disabled="true">
|
||||
<Flag />
|
||||
{{ m.great_few_jaguar_rise() }}
|
||||
|
|
@ -104,7 +104,7 @@ const { account } = defineProps<{
|
|||
}>();
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const isMe = authStore.account?.id === account.id;
|
||||
const isMe = authStore.accountOptional?.id === account.id;
|
||||
|
||||
const { copy } = useClipboard();
|
||||
const copyText = (text: string) => {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ const roles = account.roles.filter((r) => r.visible);
|
|||
// Get user handle in username@instance format
|
||||
const handle = account.acct.includes("@")
|
||||
? account.acct
|
||||
: `${account.acct}@${authStore.instance?.domain ?? window.location.host}`;
|
||||
: `${account.acct}@${authStore.instance.domain}`;
|
||||
const isDeveloper = config.DEVELOPER_HANDLES.includes(handle);
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<Button
|
||||
variant="secondary"
|
||||
:disabled="isLoading || relationship?.requested"
|
||||
v-if="!isMe && authStore.isSignedIn"
|
||||
v-if="!isMe"
|
||||
@click="relationship?.following ? unfollow() : follow()"
|
||||
>
|
||||
<Loader v-if="isLoading" class="animate-spin" />
|
||||
|
|
@ -31,7 +31,7 @@ const { account } = defineProps<{
|
|||
|
||||
const { relationship, isLoading } = useRelationship(account.id);
|
||||
const authStore = useAuthStore();
|
||||
const isMe = authStore.account?.id === account.id;
|
||||
const isMe = authStore.accountOptional?.id === account.id;
|
||||
|
||||
const follow = async () => {
|
||||
if (preferences.confirm_actions.value.includes("follow")) {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
/>
|
||||
<Button
|
||||
data-switch
|
||||
v-if="authStore.identity?.id !== identity.id"
|
||||
v-if="authStore.identityOptional?.id !== identity.id"
|
||||
@click="authStore.setActiveIdentity(identity.id)"
|
||||
variant="outline"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -26,10 +26,7 @@ const authStore = useAuthStore();
|
|||
<SidebarMenu class="gap-3">
|
||||
<SidebarMenuItem>
|
||||
<AccountManager>
|
||||
<SidebarMenuButton
|
||||
v-if="authStore.account && authStore.instance"
|
||||
size="lg"
|
||||
>
|
||||
<SidebarMenuButton v-if="authStore.isSignedIn" size="lg">
|
||||
<TinyCard
|
||||
:account="authStore.account"
|
||||
:domain="authStore.instance.domain"
|
||||
|
|
|
|||
|
|
@ -11,13 +11,10 @@ const authStore = useAuthStore();
|
|||
|
||||
<template>
|
||||
<SidebarHeader>
|
||||
<SidebarMenu>
|
||||
<SidebarMenu v-if="authStore.isSignedIn">
|
||||
<SidebarMenuItem>
|
||||
<NuxtLink href="/">
|
||||
<InstanceSmallCard
|
||||
v-if="authStore.instance"
|
||||
:instance="authStore.instance"
|
||||
/>
|
||||
<InstanceSmallCard :instance="authStore.instance" />
|
||||
</NuxtLink>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||
data-slot="dropdown-menu-checkbox-item"
|
||||
v-bind="forwarded"
|
||||
:class=" cn(
|
||||
`focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 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`,
|
||||
`focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 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`,
|
||||
props.class,
|
||||
)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||
<DropdownMenuContent
|
||||
data-slot="dropdown-menu-content"
|
||||
v-bind="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 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-[8rem] origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', props.class)"
|
||||
: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 z-50 max-h-(--reka-dropdown-menu-content-available-height) min-w-32 origin-(--reka-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</DropdownMenuContent>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const forwardedProps = useForwardProps(delegatedProps);
|
|||
data-slot="dropdown-menu-sub-trigger"
|
||||
v-bind="forwardedProps"
|
||||
:class="cn(
|
||||
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8',
|
||||
'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-inset:pl-8',
|
||||
props.class,
|
||||
)"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const props = defineProps<{
|
|||
data-slot="table-cell"
|
||||
:class="
|
||||
cn(
|
||||
'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
|
||||
'p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-0.5',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ const props = defineProps<{
|
|||
<template>
|
||||
<th
|
||||
data-slot="table-head"
|
||||
:class="cn('text-muted-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]', props.class)"
|
||||
:class="cn('text-muted-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-0.5', props.class)"
|
||||
>
|
||||
<slot />
|
||||
</th>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import * as m from "~~/paraglide/messages.js";
|
|||
|
||||
export const useCacheRefresh = () => {
|
||||
const authStore = useAuthStore();
|
||||
const { identity } = storeToRefs(authStore);
|
||||
const { identityOptional } = storeToRefs(authStore);
|
||||
|
||||
authStore.client.getInstance().then((res) => {
|
||||
authStore.updateActiveIdentity({
|
||||
|
|
@ -13,7 +13,7 @@ export const useCacheRefresh = () => {
|
|||
|
||||
// Refresh custom emojis and instance data and me on every reload
|
||||
watch(
|
||||
identity,
|
||||
identityOptional,
|
||||
async (oldIdentity, newIdentity) => {
|
||||
if (newIdentity && newIdentity.id !== oldIdentity?.id) {
|
||||
console.info("Refreshing emoji, instance and account cache");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { Client, Output } from "@versia/client";
|
||||
import type { Output } from "@versia/client";
|
||||
import type { Notification, Status } from "@versia/client/schemas";
|
||||
import { useIntervalFn } from "@vueuse/core";
|
||||
import type { z } from "zod";
|
||||
|
|
@ -17,7 +17,7 @@ export function useTimeline<
|
|||
const hasReachedEnd = ref(false);
|
||||
const error = ref<Error | null>(null);
|
||||
const authStore = useAuthStore();
|
||||
const { identity } = storeToRefs(authStore);
|
||||
const { identityOptional } = storeToRefs(authStore);
|
||||
|
||||
const nextMaxId = ref<string | undefined>(undefined);
|
||||
const prevMinId = ref<string | undefined>(undefined);
|
||||
|
|
@ -101,7 +101,7 @@ export function useTimeline<
|
|||
pause();
|
||||
});
|
||||
|
||||
watch(identity, (newIdentity, oldIdentity) => {
|
||||
watch(identityOptional, (newIdentity, oldIdentity) => {
|
||||
if (newIdentity?.id !== oldIdentity?.id) {
|
||||
// Reload timeline when identity changes
|
||||
items.value = [];
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ const route = useRoute();
|
|||
watch(
|
||||
() => route.path,
|
||||
async () => {
|
||||
console.log(route.meta.requiresAuth && !authStore.isSignedIn);
|
||||
if (route.meta.requiresAuth && !authStore.isSignedIn) {
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,34 +38,55 @@ export const useAuthStore = defineStore("auth", {
|
|||
applications: {},
|
||||
}),
|
||||
getters: {
|
||||
identity(state): Identity | null {
|
||||
return state.activeIdentityId
|
||||
? state.identities.find(
|
||||
(id) => id.id === state.activeIdentityId,
|
||||
) || null
|
||||
: null;
|
||||
identity(state): Identity {
|
||||
if (state.activeIdentityId === null) {
|
||||
throw new Error("This functionality requires authentication.");
|
||||
}
|
||||
|
||||
const identity = state.identities.find(
|
||||
(id) => id.id === state.activeIdentityId,
|
||||
);
|
||||
|
||||
if (!identity) {
|
||||
throw new Error("This functionality requires authentication.");
|
||||
}
|
||||
|
||||
return identity;
|
||||
},
|
||||
emojis(): z.infer<typeof CustomEmoji>[] {
|
||||
return this.identity?.emojis || [];
|
||||
},
|
||||
instance(): z.infer<typeof Instance> | null {
|
||||
return this.identity?.instance || null;
|
||||
},
|
||||
account(): z.infer<typeof Account> | null {
|
||||
return this.identity?.account || null;
|
||||
},
|
||||
application(): z.infer<typeof CredentialApplication> | null {
|
||||
if (!this.identity) {
|
||||
identityOptional(state): Identity | null {
|
||||
if (state.activeIdentityId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
state.identities.find(
|
||||
(id) => id.id === state.activeIdentityId,
|
||||
) || null
|
||||
);
|
||||
},
|
||||
emojis(): z.infer<typeof CustomEmoji>[] {
|
||||
return this.identity.emojis;
|
||||
},
|
||||
instance(): z.infer<typeof Instance> {
|
||||
return this.identity.instance;
|
||||
},
|
||||
instanceOptional(): z.infer<typeof Instance> | null {
|
||||
return this.identityOptional?.instance ?? null;
|
||||
},
|
||||
account(): z.infer<typeof Account> {
|
||||
return this.identity.account;
|
||||
},
|
||||
accountOptional(): z.infer<typeof Account> | null {
|
||||
return this.identityOptional?.account ?? null;
|
||||
},
|
||||
application(): z.infer<typeof CredentialApplication> | null {
|
||||
return this.applications[this.identity.instance.domain] || null;
|
||||
},
|
||||
token(): z.infer<typeof Token> | null {
|
||||
return this.identity?.token || null;
|
||||
token(): z.infer<typeof Token> {
|
||||
return this.identity.token;
|
||||
},
|
||||
permissions(): RolePermission[] {
|
||||
const roles = this.account?.roles ?? [];
|
||||
const roles = this.account.roles;
|
||||
|
||||
return roles
|
||||
.flatMap((r) => r.permissions)
|
||||
|
|
@ -76,11 +97,11 @@ export const useAuthStore = defineStore("auth", {
|
|||
},
|
||||
client(): Client {
|
||||
const apiHost = window.location.origin;
|
||||
const domain = this.identity?.instance.domain;
|
||||
const domain = this.identityOptional?.instance.domain;
|
||||
|
||||
return new Client(
|
||||
domain ? new URL(`https://${domain}`) : new URL(apiHost),
|
||||
this.identity?.token.access_token ?? undefined,
|
||||
this.identityOptional?.token.access_token ?? undefined,
|
||||
{
|
||||
globalCatch: (error) => {
|
||||
toast.error(
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export const calculateMentionsFromReply = (
|
|||
// Deduplicate mentions
|
||||
.filter((men, i, a) => a.indexOf(men) === i)
|
||||
// Remove self
|
||||
.filter((men) => men.id !== authStore.identity?.account.id);
|
||||
.filter((men) => men.id !== authStore.identity.account.id);
|
||||
|
||||
if (peopleToMention.length === 0) {
|
||||
return "";
|
||||
|
|
@ -72,8 +72,8 @@ export const useComposerStore = (key: ComposerStateKey) =>
|
|||
isOverCharacterLimit(): boolean {
|
||||
const authStore = useAuthStore();
|
||||
const characterLimit =
|
||||
authStore.identity?.instance.configuration.statuses
|
||||
.max_characters ?? 0;
|
||||
authStore.identity.instance.configuration.statuses
|
||||
.max_characters;
|
||||
|
||||
return this.characterCount > characterLimit;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ export const wrapUrl = (path: string) => {
|
|||
|
||||
return new URL(
|
||||
path,
|
||||
authStore.instance
|
||||
authStore.instanceOptional
|
||||
? `https://${authStore.instance.domain}`
|
||||
: window.location.origin,
|
||||
).toString();
|
||||
|
|
|
|||
|
|
@ -90,7 +90,9 @@
|
|||
"noUselessElse": "error",
|
||||
"noCommonJs": "error"
|
||||
},
|
||||
"nursery": {}
|
||||
"nursery": {
|
||||
"noUnnecessaryConditions": "error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue