feat: 👽 Support Versia Server 0.9 login system
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 0s
Deploy to GitHub Pages / build (push) Failing after 0s
Deploy to GitHub Pages / deploy (push) Has been skipped
Docker / build (push) Failing after 0s
Mirror to Codeberg / Mirror (push) Failing after 0s

This commit is contained in:
Jesse Wierzbinski 2025-11-21 12:16:00 +01:00
parent cc95f043bd
commit dc32f3b3ea
No known key found for this signature in database
21 changed files with 221 additions and 567 deletions

View file

@ -1,39 +0,0 @@
<template>
<Alert layout="button">
<LogIn />
<AlertTitle>{{ m.sunny_quick_lionfish_flip() }}</AlertTitle>
<AlertDescription>
{{ m.brave_known_pelican_drip() }}
</AlertDescription>
<Button
variant="secondary"
class="w-full"
@click="signInAction"
>
{{ m.fuzzy_sea_moth_absorb() }}
</Button>
</Alert>
</template>
<script lang="ts" setup>
import { LogIn } from "lucide-vue-next";
import { toast } from "vue-sonner";
import { Alert, AlertDescription, AlertTitle } from "~/components/ui/alert";
import { Button } from "~/components/ui/button";
import * as m from "~~/paraglide/messages.js";
const authStore = useAuthStore();
const signInAction = async () => {
const instance = await askForInstance();
const id = toast.loading(m.level_due_ox_greet());
try {
await authStore.startSignIn(instance);
} catch (e) {
toast.dismiss(id);
}
};
</script>
<style></style>

View file

@ -1,23 +1,27 @@
<template>
<Alert layout="button">
<TriangleAlert />
<AlertTitle>{{ contentWarning || m.sour_seemly_bird_hike() }}</AlertTitle>
<Button @click="blurred = !blurred" variant="outline" size="sm">{{ blurred ? m.bald_direct_turtle_win() :
m.known_flaky_cockroach_dash() }}</Button>
</Alert>
<div class="flex flex-col gap-1">
<p class="text-sm leading-6 wrap-anywhere">
{{ contentWarning || m.sour_seemly_bird_hike() }}
</p>
<Button @click="hidden = !hidden" variant="outline" size="sm" class="col-span-2">
{{ hidden ? m.bald_direct_turtle_win() :
m.known_flaky_cockroach_dash() }} {{ characterCount > 0 ? ` (${characterCount} characters` : "" }}{{
attachmentCount > 0 ? `${characterCount > 0 ? " · " : " ("}${attachmentCount} file(s)` : "" }}{{ (characterCount > 0 || attachmentCount > 0) ? ")" : "" }}
</Button>
</div>
</template>
<script lang="ts" setup>
import { TriangleAlert } from "lucide-vue-next";
import * as m from "~~/paraglide/messages.js";
import { Alert, AlertDescription, AlertTitle } from "../ui/alert";
import { Button } from "../ui/button";
const { contentWarning } = defineProps<{
const { contentWarning, characterCount, attachmentCount } = defineProps<{
contentWarning?: string;
characterCount: number;
attachmentCount: number;
}>();
const blurred = defineModel<boolean>({
const hidden = defineModel<boolean>({
default: true,
});
</script>

View file

@ -1,11 +1,11 @@
<template>
<ContentWarning v-if="(sensitive || contentWarning) && preferences.show_content_warning" :content-warning="contentWarning" v-model="blurred" />
<ContentWarning v-if="(sensitive || contentWarning) && preferences.show_content_warning" :content-warning="contentWarning" :character-count="characterCount ?? 0" :attachment-count="attachments.length" v-model="hidden" />
<OverflowGuard v-if="content" :character-count="characterCount" :class="(blurred && preferences.show_content_warning) && 'blur-md'">
<OverflowGuard v-if="content" :character-count="characterCount" :class="(hidden && preferences.show_content_warning) && 'hidden'">
<Prose v-html="content" v-render-emojis="emojis"></Prose>
</OverflowGuard>
<Attachments v-if="attachments.length > 0" :attachments="attachments" :class="(blurred && preferences.show_content_warning) && 'blur-xl'" />
<Attachments v-if="attachments.length > 0" :attachments="attachments" :class="(hidden && preferences.show_content_warning) && 'hidden'" />
<div v-if="quote" class="mt-4 rounded border overflow-hidden">
<Note :note="quote" :hide-actions="true" :small-layout="true" />
@ -31,7 +31,7 @@ const { content, plainContent, sensitive, contentWarning } = defineProps<{
contentWarning?: string;
}>();
const blurred = ref(sensitive || !!contentWarning);
const hidden = ref(sensitive || !!contentWarning);
const characterCount = plainContent?.length;
</script>

View file

@ -16,13 +16,13 @@
:visibility="noteToUse.visibility"
:created-at="new Date(noteToUse.created_at)"
:small-layout="smallLayout"
class="z-[1]"
class="z-1"
/>
<div
v-if="topAvatarBar"
:class="
cn(
'shrink-0 bg-border w-0.5 absolute top-0 h-7 left-[3rem]'
'shrink-0 bg-border w-0.5 absolute top-0 h-7 left-12'
)
"
></div>
@ -30,7 +30,7 @@
v-if="bottomAvatarBar"
:class="
cn(
'shrink-0 bg-border w-0.5 absolute bottom-0 h-[calc(100%-1.5rem)] left-[3rem]'
'shrink-0 bg-border w-0.5 absolute bottom-0 h-[calc(100%-1.5rem)] left-12'
)
"
></div>
@ -38,7 +38,7 @@
<!-- Simply offset by the size of avatar + 0.75rem (the gap) -->
<CardContent
:class="
['space-y-4', contentUnderUsername && (smallLayout ? 'ml-11' : 'ml-[4.25rem]')]
['space-y-4', contentUnderUsername && (smallLayout ? 'ml-11' : 'ml-17')]
"
>
<Content

View file

@ -1,171 +0,0 @@
<script setup lang="ts">
import { toTypedSchema } from "@vee-validate/zod";
import type { Instance } from "@versia/client/schemas";
import { Loader } from "lucide-vue-next";
import { useForm } from "vee-validate";
import * as z from "zod";
import {
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import * as m from "~~/paraglide/messages.js";
const { instance } = defineProps<{
instance: z.infer<typeof Instance>;
}>();
const isLoading = ref(false);
const ssoConfig = computed(() => instance.sso);
const formSchema = toTypedSchema(
z.object({
identifier: z
.string()
.min(3, {
message: m.aware_house_dolphin_win(),
})
.or(
z.string().email({
message: m.weary_fresh_dragonfly_bless(),
}),
),
password: z.string().min(3, {
message: m.aware_house_dolphin_win(),
}),
}),
);
const form = useForm({
validationSchema: formSchema,
});
const redirectUrl = new URL("/api/auth/login", `https://${instance.domain}`);
const params = useUrlSearchParams();
for (const name of [
"redirect_uri",
"response_type",
"client_id",
"scope",
"state",
]) {
if (params[name]) {
redirectUrl.searchParams.set(name, params[name] as string);
}
}
const issuerRedirectUrl = (issuerId: string) => {
const url = new URL("/oauth/sso", useRequestURL().origin);
for (const name of [
"redirect_uri",
"response_type",
"client_id",
"scope",
"state",
]) {
if (params[name]) {
url.searchParams.set(name, params[name] as string);
}
}
url.searchParams.set("issuer", issuerId);
return url.toString();
};
</script>
<template>
<div class="grid gap-6">
<form
@submit="form.submitForm"
method="post"
:action="redirectUrl.toString()"
>
<div class="grid gap-6">
<FormField v-slot="{ componentField }" name="identifier">
<FormItem>
<FormLabel>
{{ m.fluffy_soft_wolf_cook() }}
</FormLabel>
<FormControl>
<Input
placeholder="petergriffin"
type="text"
auto-capitalize="none"
auto-complete="idenfifier"
auto-correct="off"
:disabled="isLoading"
v-bind="componentField"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<FormField v-slot="{ componentField }" name="password">
<FormItem>
<FormLabel>
{{ m.livid_bright_wallaby_quiz() }}
</FormLabel>
<FormControl>
<Input
placeholder="hunter2"
type="password"
auto-capitalize="none"
auto-complete="password"
auto-correct="off"
:disabled="isLoading"
v-bind="componentField"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
<Button :disabled="isLoading" type="submit">
<Loader v-if="isLoading" class="mr-2 size-4 animate-spin" />
{{ m.fuzzy_sea_moth_absorb() }}
</Button>
</div>
</form>
<div
v-if="ssoConfig && ssoConfig.providers.length > 0"
class="relative"
>
<div class="absolute inset-0 flex items-center">
<span class="w-full border-t" />
</div>
<div class="relative flex justify-center text-xs uppercase">
<span class="bg-background px-2 text-muted-foreground">
{{ m.tidy_tidy_cow_cut() }}
</span>
</div>
</div>
<div
v-if="ssoConfig && ssoConfig.providers.length > 0"
class="flex flex-col gap-2"
>
<Button
as="a"
:href="issuerRedirectUrl(provider.id)"
variant="outline"
type="button"
:disabled="isLoading"
v-for="provider of ssoConfig.providers"
>
<Loader v-if="isLoading" class="mr-2 animate-spin" />
<img
crossorigin="anonymous"
:src="provider.icon"
:alt="`${provider.name}'s logo`"
class="size-4 mr-2"
/>
{{ provider.name }}
</Button>
</div>
</div>
</template>

View file

@ -1,13 +1,13 @@
<template>
<form class="grid gap-6" @submit="save">
<Transition name="slide-up">
<Alert v-if="dirty" layout="button" class="absolute bottom-2 z-10 inset-x-2 w-[calc(100%-1rem)]">
<Alert v-if="dirty" class="absolute bottom-2 z-10 inset-x-2 w-[calc(100%-1rem)] grid-cols-[calc(var(--spacing)*4)_1fr_auto]!">
<SaveOff class="size-4" />
<AlertTitle>Unsaved changes</AlertTitle>
<Button variant="secondary" class="w-full row-span-2" type="button" :disabled="submitting">Apply</Button>
<AlertDescription>
Click "apply" to save your changes.
</AlertDescription>
<Button variant="secondary" class="w-full" typ="submit" :disabled="submitting">Apply</Button>
</Alert>
</Transition>

View file

@ -6,14 +6,13 @@ import { type AlertVariants, alertVariants } from ".";
const props = defineProps<{
class?: HTMLAttributes["class"];
variant?: AlertVariants["variant"];
layout?: AlertVariants["layout"];
}>();
</script>
<template>
<div
data-slot="alert"
:class="cn(alertVariants({ variant, layout }), props.class)"
:class="cn(alertVariants({ variant }), props.class)"
role="alert"
>
<slot />

View file

@ -10,7 +10,7 @@ const props = defineProps<{
<template>
<div
data-slot="alert-description"
:class="cn('text-muted-foreground text-sm [&_p]:leading-relaxed', props.class)"
:class="cn('text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed', props.class)"
>
<slot />
</div>

View file

@ -10,7 +10,7 @@ const props = defineProps<{
<template>
<div
data-slot="alert-title"
:class="cn('line-clamp-1 min-h-4 font-medium tracking-tight', props.class)"
:class="cn('col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight', props.class)"
>
<slot />
</div>

View file

@ -5,7 +5,7 @@ export { default as AlertDescription } from "./AlertDescription.vue";
export { default as AlertTitle } from "./AlertTitle.vue";
export const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 grid text-sm [&>svg]:size-4 [&>svg]:text-current",
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
{
variants: {
variant: {
@ -13,15 +13,9 @@ export const alertVariants = cva(
destructive:
"text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
},
layout: {
default:
"has-[>svg]:grid-cols-[1fr_auto] grid-rows-2 gap-x-3 gap-y-1 items-start",
button: "grid-cols-[auto_1fr_auto] items-center gap-x-3 gap-y-0.5 *:data-[slot=alert-description]:col-start-2 *:data-[slot=alert-description]:row-start-2 has-[>[data-slot=alert-description]]:[&>button]:row-span-2",
},
},
defaultVariants: {
variant: "default",
layout: "default",
},
},
);