trypost/resources/js/components/analytics/AnalyticsAccountSelector.vue
Paulo Castellano 6ead4eee84 fix(analytics): full-width account selector on mobile
Matches the date-range picker below it instead of sitting content-width.
2026-07-17 21:16:43 -03:00

124 lines
5.7 KiB
Vue

<script setup lang="ts">
import { IconChevronDown } from '@tabler/icons-vue';
import { trans } from 'laravel-vue-i18n';
import { computed, ref } from 'vue';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Button } from '@/components/ui/button';
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from '@/components/ui/command';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { getPlatformLabel, getPlatformLogo } from '@/composables/usePlatformLogo';
import type { AnalyticsAccount } from './types';
const props = defineProps<{
accounts: AnalyticsAccount[];
selectedId: string | null;
}>();
const emit = defineEmits<{
select: [accountId: string];
}>();
const open = ref(false);
const selected = computed(() =>
props.accounts.find((a) => a.id === props.selectedId) ?? null,
);
const select = (account: AnalyticsAccount) => {
emit('select', account.id);
open.value = false;
};
</script>
<template>
<Popover v-model:open="open">
<PopoverTrigger as-child>
<Button
type="button"
variant="outline"
role="combobox"
:aria-expanded="open"
:disabled="accounts.length === 0"
class="h-auto w-full justify-start gap-3 px-3 py-2 text-left font-medium sm:w-auto sm:min-w-[240px]"
>
<template v-if="selected">
<div class="relative shrink-0">
<Avatar class="size-7 rounded-full border-2 border-foreground shadow-2xs">
<AvatarImage v-if="selected.avatar_url" :src="selected.avatar_url" :alt="selected.display_name" />
<AvatarFallback class="rounded-full bg-violet-100 text-xs font-bold text-foreground">
{{ selected.display_name?.charAt(0) }}
</AvatarFallback>
</Avatar>
<span class="absolute -bottom-1 -right-1 inline-flex size-4 items-center justify-center overflow-hidden rounded-full border-2 border-foreground bg-card shadow-2xs">
<img
:src="getPlatformLogo(selected.platform)"
:alt="selected.platform"
class="size-full object-cover"
/>
</span>
</div>
<span class="min-w-0 flex-1 truncate">
<span class="font-bold text-foreground">{{ selected.display_name }}</span>
<span v-if="selected.username" class="ml-1.5 text-xs font-medium text-foreground/60">
@{{ selected.username }}
</span>
</span>
</template>
<template v-else>
<span class="text-foreground/60">{{ $t('analytics.select_account') }}</span>
</template>
<IconChevronDown class="ml-auto size-4 shrink-0 text-foreground/60" />
</Button>
</PopoverTrigger>
<PopoverContent class="w-[320px] overflow-hidden p-0" align="start">
<Command class="rounded-[10px]">
<CommandInput :placeholder="trans('analytics.search_account')" />
<CommandList>
<CommandEmpty>{{ $t('analytics.no_accounts_match') }}</CommandEmpty>
<CommandGroup>
<CommandItem
v-for="account in accounts"
:key="account.id"
:value="account.id"
class="gap-3"
@select="select(account)"
>
<div class="relative shrink-0">
<Avatar class="size-9 rounded-full border-2 border-foreground shadow-2xs">
<AvatarImage v-if="account.avatar_url" :src="account.avatar_url" :alt="account.display_name" />
<AvatarFallback class="rounded-full bg-violet-100 font-bold text-foreground">
{{ account.display_name?.charAt(0) }}
</AvatarFallback>
</Avatar>
<span class="absolute -bottom-1 -right-1 inline-flex size-5 items-center justify-center overflow-hidden rounded-full border-2 border-foreground bg-card shadow-2xs">
<img
:src="getPlatformLogo(account.platform)"
:alt="account.platform"
class="size-full object-cover"
/>
</span>
</div>
<div class="min-w-0 flex-1">
<p class="truncate font-bold text-foreground">{{ account.display_name }}</p>
<p v-if="account.username" class="truncate text-xs font-medium text-foreground/60">
@{{ account.username }}
</p>
</div>
<span class="sr-only">{{ getPlatformLabel(account.platform) }}</span>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</template>