mirror of
https://github.com/versia-pub/frontend.git
synced 2025-12-06 16:38:20 +01:00
feat: ✨ Add support for developer badges and user role displaying
This commit is contained in:
parent
a889f8d142
commit
46193938fe
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div v-bind="$props" class="bg-dark-700 overflow-hidden flex items-center justify-center">
|
||||
<Skeleton :enabled="!src" class="!h-full !w-full">
|
||||
<Skeleton :enabled="!src" class="!h-full !w-full !rounded-none">
|
||||
<img class="cursor-pointer bg-dark-700 ring-1 w-full h-full object-cover" :src="src" :alt="alt" />
|
||||
</Skeleton>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<button v-bind="$props" type="button" :disabled="loading"
|
||||
:class="['rounded-md duration-200 relative hover:shadow disabled:opacity-70 content-none disabled:cursor-not-allowed px-3 py-2 text-sm font-semibold text-white shadow-sm', loading && '[&>*]:invisible']">
|
||||
:class="['relative isolate text-base/6 font-semibold px-[calc(theme(spacing[3.5])-1px)] py-[calc(theme(spacing[2.5])-1px)] sm:px-[calc(theme(spacing.3)-1px)] sm:py-[calc(theme(spacing[1.5])-1px)] sm:text-sm/6 focus:outline-none focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-[--btn-bg] before:absolute before:inset-0 before:-z-10 before:rounded-[calc(theme(borderRadius.lg)-1px)] before:shadow before:hidden after:absolute after:-z-10 after:-inset-px after:rounded-md before:disabled:shadow-none after:disabled:shadow-none text-white cursor-default rounded-md duration-200 hover:shadow disabled:opacity-70 content-none disabled:cursor-not-allowed shadow-sm bg-[--btn-bg] before:bg-[--btn-bg] after:active:bg-[--btn-hover-overlay] after:hover:bg-[--btn-hover-overlay]', loading && '[&>*]:invisible']">
|
||||
<div v-if="loading" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 !visible">
|
||||
<iconify-icon icon="tabler:loader-2" height="1.25rem" width="1.25rem" class="animate-spin" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<ButtonsBase :loading="loading" class="bg-pink-600 hover:bg-pink-500">
|
||||
<ButtonsBase :loading="loading"
|
||||
class="[--btn-border:theme(colors.pink.950/90%)] [--btn-bg:theme(colors.pink.600)] [--btn-hover-overlay:theme(colors.white/5%)] [--btn-icon:theme(colors.pink.400)] active:[--btn-icon:theme(colors.pink.300)] hover:[--btn-icon:theme(colors.pink.300)] after:shadow-[shadow:inset_0_1px_theme(colors.white/15%)] border border-white/5"
|
||||
v-bind="$props">
|
||||
<slot />
|
||||
</ButtonsBase>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<ButtonsBase class="bg-white/10 hover:bg-white/20" :loading="loading">
|
||||
<ButtonsBase
|
||||
class="[--btn-border:theme(colors.zinc.950/90%)] [--btn-bg:theme(colors.zinc.800)] [--btn-hover-overlay:theme(colors.white/5%)] [--btn-icon:theme(colors.zinc.400)] active:[--btn-icon:theme(colors.zinc.300)] hover:[--btn-icon:theme(colors.zinc.300)] after:shadow-[shadow:inset_0_1px_theme(colors.white/15%)] border border-white/5"
|
||||
v-bind="$props" :loading="loading">
|
||||
<slot />
|
||||
</ButtonsBase>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<!-- Overlay that blocks clicks for disabled notes -->
|
||||
<div v-if="disabled" class="absolute z-10 inset-0 hover:cursor-not-allowed">
|
||||
</div>
|
||||
<div v-if="reblog" class="mb-4 flex flex-row gap-2 items-center text-pink-500">
|
||||
<div v-if="reblog" class="mb-4 flex flex-row gap-2 items-center text-pink-400">
|
||||
<Skeleton :enabled="!loaded" shape="rect" class="!h-6" :min-width="40" :max-width="100" width-unit="%">
|
||||
<iconify-icon width="1.5rem" height="1.5rem" icon="tabler:repeat" class="size-6" aria-hidden="true" />
|
||||
<AvatarsCentered v-if="reblog.avatar" :src="reblog.avatar" :alt="`${reblog.acct}'s avatar'`"
|
||||
|
|
@ -91,8 +91,8 @@
|
|||
</ButtonsDropdownElement>
|
||||
</Menu.Item>
|
||||
</Menu.ItemGroup>
|
||||
<hr class="border-white/10 rounded" />
|
||||
<Menu.ItemGroup>
|
||||
<hr class="border-white/10 rounded" v-if="identity" />
|
||||
<Menu.ItemGroup v-if="identity">
|
||||
<Menu.Item value="">
|
||||
<ButtonsDropdownElement @click="outputtedNote && useEvent('note:reply', outputtedNote)"
|
||||
icon="tabler:arrow-back-up" class="w-full">
|
||||
|
|
@ -125,8 +125,8 @@
|
|||
</ButtonsDropdownElement>
|
||||
</Menu.Item>
|
||||
</Menu.ItemGroup>
|
||||
<hr class="border-white/10 rounded" />
|
||||
<Menu.ItemGroup>
|
||||
<hr class="border-white/10 rounded" v-if="identity" />
|
||||
<Menu.ItemGroup v-if="identity">
|
||||
<Menu.Item value="">
|
||||
<ButtonsDropdownElement @click="outputtedNote && useEvent('note:report', outputtedNote)"
|
||||
icon="tabler:flag" class="w-full"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<ClientOnly>
|
||||
<div class="w-full ring-1 ring-inset ring-white/5 pb-10">
|
||||
<div class="w-full ring-1 ring-inset ring-white/5 pb-10 bg-dark-800">
|
||||
<AvatarsCentered :src="account?.header" :alt="`${account?.acct}'s header image'`"
|
||||
class="w-full aspect-[8/3] border-b border-white/10 bg-dark-700" />
|
||||
class="w-full aspect-[8/3] border-b border-white/10 bg-dark-700 !rounded-none" />
|
||||
|
||||
<div class="flex items-start justify-between px-4 py-3">
|
||||
<AvatarsCentered :src="account?.avatar" :alt="`${account?.acct}'s avatar'`"
|
||||
|
|
@ -36,9 +36,15 @@
|
|||
title="This account manually approves its followers" />
|
||||
</Skeleton>
|
||||
</h2>
|
||||
<span class="text-gray-400 block mt-2">
|
||||
<span class="text-gray-300 block mt-2">
|
||||
<Skeleton :enabled="skeleton" :min-width="130" :max-width="250">@{{ account?.acct }}</Skeleton>
|
||||
</span>
|
||||
<div class="flex flex-row flex-wrap gap-4 mt-4" v-if="isDeveloper || visibleRoles.length > 0">
|
||||
<SocialElementsUsersBadge v-for="role of visibleRoles" :key="role.id" :name="role.name"
|
||||
:description="role.description" :img="role.icon" />
|
||||
<SocialElementsUsersBadge v-if="isDeveloper" name="Lysand Developer"
|
||||
description="This user is a Lysand developer." :verified="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 px-4">
|
||||
|
|
@ -105,6 +111,7 @@ const props = defineProps<{
|
|||
const skeleton = computed(() => !props.account);
|
||||
const identity = useCurrentIdentity();
|
||||
const client = useClient();
|
||||
const config = useConfig();
|
||||
const accountId = computed(() => props.account?.id ?? null);
|
||||
const { relationship, isLoading } = useRelationship(client, accountId);
|
||||
|
||||
|
|
@ -138,6 +145,18 @@ const parsedFields: Ref<
|
|||
value: string;
|
||||
}[]
|
||||
> = ref([]);
|
||||
const handle = computed(() => {
|
||||
if (!props.account?.acct.includes("@")) {
|
||||
return `${props.account?.acct}@${new URL(useBaseUrl().value).host}`;
|
||||
}
|
||||
return props.account?.acct;
|
||||
});
|
||||
const isDeveloper = computed(() =>
|
||||
config.DEVELOPER_HANDLES.includes(handle.value),
|
||||
);
|
||||
const visibleRoles = computed(
|
||||
() => props.account?.roles.filter((r) => r.visible) ?? [],
|
||||
);
|
||||
|
||||
watch(
|
||||
skeleton,
|
||||
|
|
|
|||
54
components/social-elements/users/Badge.vue
Normal file
54
components/social-elements/users/Badge.vue
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<template>
|
||||
<Tooltip.Root @update:open="(o) => open = o" :open="open" :open-delay="0">
|
||||
<Tooltip.Trigger><span
|
||||
class="inline-flex items-center px-2 py-1 gap-x-2 rounded text-sm font-medium bg-dark-300 text-pink-200 ring-white/5 ring-1">
|
||||
<svg viewBox="0 0 22 22" v-if="verified" aria-label="Verified account" role="img"
|
||||
class="size-4 fill-pink-500">
|
||||
<g>
|
||||
<path
|
||||
d="M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816zM9.662 14.85l-3.429-3.428 1.293-1.302 2.072 2.072 4.4-4.794 1.347 1.246z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
<img v-else-if="img" :src="img" alt="" class="size-4 rounded-sm" />
|
||||
<iconify-icon v-else-if="icon" :icon="icon" width="none" class="text-pink-200 size-4"
|
||||
aria-hidden="true" />
|
||||
<span>{{ name }}</span>
|
||||
</span></Tooltip.Trigger>
|
||||
<Tooltip.Positioner>
|
||||
<transition enter-active-class="transition ease-in duration-100"
|
||||
enter-from-class="transform opacity-0 translate-y-full sm:translate-y-0 scale-95"
|
||||
enter-to-class="transform translate-y-0 opacity-100 scale-100"
|
||||
leave-active-class="transition ease-out duration-75" leave-from-class="transform opacity-100 scale-100"
|
||||
leave-to-class="transform opacity-0 scale-95">
|
||||
<Tooltip.Content v-if="open"
|
||||
class="rounded px-4 py-2 text-sm bg-dark-400 text-gray-200 ring-1 ring-white/10 shadow-xl">
|
||||
<svg viewBox="0 0 22 22" v-if="verified" aria-label="Verified account" role="img"
|
||||
class="size-4 fill-pink-500 inline mb-0.5">
|
||||
<g>
|
||||
<path
|
||||
d="M20.396 11c-.018-.646-.215-1.275-.57-1.816-.354-.54-.852-.972-1.438-1.246.223-.607.27-1.264.14-1.897-.131-.634-.437-1.218-.882-1.687-.47-.445-1.053-.75-1.687-.882-.633-.13-1.29-.083-1.897.14-.273-.587-.704-1.086-1.245-1.44S11.647 1.62 11 1.604c-.646.017-1.273.213-1.813.568s-.969.854-1.24 1.44c-.608-.223-1.267-.272-1.902-.14-.635.13-1.22.436-1.69.882-.445.47-.749 1.055-.878 1.688-.13.633-.08 1.29.144 1.896-.587.274-1.087.705-1.443 1.245-.356.54-.555 1.17-.574 1.817.02.647.218 1.276.574 1.817.356.54.856.972 1.443 1.245-.224.606-.274 1.263-.144 1.896.13.634.433 1.218.877 1.688.47.443 1.054.747 1.687.878.633.132 1.29.084 1.897-.136.274.586.705 1.084 1.246 1.439.54.354 1.17.551 1.816.569.647-.016 1.276-.213 1.817-.567s.972-.854 1.245-1.44c.604.239 1.266.296 1.903.164.636-.132 1.22-.447 1.68-.907.46-.46.776-1.044.908-1.681s.075-1.299-.165-1.903c.586-.274 1.084-.705 1.439-1.246.354-.54.551-1.17.569-1.816zM9.662 14.85l-3.429-3.428 1.293-1.302 2.072 2.072 4.4-4.794 1.347 1.246z">
|
||||
</path>
|
||||
</g>
|
||||
</svg>
|
||||
{{ description }}
|
||||
</Tooltip.Content>
|
||||
</transition>
|
||||
</Tooltip.Positioner>
|
||||
</Tooltip.Root>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Tooltip } from "@ark-ui/vue";
|
||||
|
||||
const props = defineProps<{
|
||||
name: string;
|
||||
description?: string | null;
|
||||
icon?: string | null;
|
||||
img?: string | null;
|
||||
verified?: boolean;
|
||||
}>();
|
||||
|
||||
const open = ref(false);
|
||||
</script>
|
||||
|
|
@ -23,5 +23,12 @@ export const useConfig = () => {
|
|||
"I'm sorry, Dave. I'm afraid I can't do that.",
|
||||
"I am the Senate",
|
||||
],
|
||||
DEVELOPER_HANDLES: [
|
||||
"jessew@social.lysand.org",
|
||||
"aprl@social.lysand.org",
|
||||
"graphite@social.lysand.org",
|
||||
"jessew@mk.cpluspatch.com",
|
||||
"graphite@shonk.phite.ro",
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue