feat(discord): global floating Discord widget with PostHog tracking

- Fixed bottom-right Discord button (indies-club style) linking to
  https://trypost.it/discord, mounted globally in AppSidebarLayout
- Captures discord.clicked (placement: floating_widget) via captureEvent
- i18n label + aria-label in common.php (en, es, pt-BR)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paulo Castellano 2026-06-15 13:23:03 -03:00
parent c71234337d
commit f41b28c31d
5 changed files with 47 additions and 0 deletions

View file

@ -3,6 +3,12 @@
declare(strict_types=1);
return [
'discord' => [
'label' => 'Discord',
'join' => 'Join our Discord community',
],
'back' => 'Back',
'confirm_modal' => [

View file

@ -3,6 +3,12 @@
declare(strict_types=1);
return [
'discord' => [
'label' => 'Discord',
'join' => 'Unite a nuestra comunidad en Discord',
],
'back' => 'Volver',
'confirm_modal' => [

View file

@ -3,6 +3,12 @@
declare(strict_types=1);
return [
'discord' => [
'label' => 'Discord',
'join' => 'Entre na nossa comunidade no Discord',
],
'back' => 'Voltar',
'confirm_modal' => [

View file

@ -0,0 +1,27 @@
<script setup lang="ts">
import { IconBrandDiscord } from '@tabler/icons-vue';
import { captureEvent } from '@/posthog';
const DISCORD_URL = 'https://trypost.it/discord';
// Distinct from the marketing site's site_discord_clicked, following the
// app's noun.verb event convention.
const trackClick = () => {
captureEvent('discord.clicked', { placement: 'floating_widget' });
};
</script>
<template>
<a
:href="DISCORD_URL"
target="_blank"
rel="noopener noreferrer"
:aria-label="$t('common.discord.join')"
class="group fixed bottom-5 right-5 z-50 inline-flex items-center gap-2 rounded-full border-2 border-foreground bg-[#5865F2] py-2.5 pl-3 pr-4 text-sm font-bold text-white shadow-md transition-all hover:-translate-y-0.5 hover:shadow-lg"
@click="trackClick"
>
<IconBrandDiscord class="size-5 shrink-0" stroke-width="2" />
<span>{{ $t('common.discord.label') }}</span>
</a>
</template>

View file

@ -4,6 +4,7 @@ import { onBeforeUnmount, onMounted } from 'vue';
import AppHeader from '@/components/AppHeader.vue';
import AppSidebar from '@/components/AppSidebar.vue';
import DiscordWidget from '@/components/DiscordWidget.vue';
import Toast from '@/components/Toast.vue';
import { SidebarInset, SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar';
import UpgradeDialog from '@/components/UpgradeDialog.vue';
@ -76,4 +77,5 @@ onBeforeUnmount(() => {
</SidebarProvider>
<UpgradeDialog />
<Toast />
<DiscordWidget />
</template>