feat(activities): UI tweaks across feed, detail, hosting, calendar, scan, shell #91
5 changed files with 67 additions and 46 deletions
feat(activities): reclaim vertical space above the feed
Past events no longer gets its own row — it folds into the existing collapsible (renamed "Filters") alongside Categories, so the feed gains that row by default. The Filters trigger badge counts past- events being on plus any selected categories, so users still see at a glance when hidden toggles are active. The standalone "Filters active / Clear all" notice is gone too; Clear all sits inline beside the trigger only when something's active. Header is tightened (text-xl) and inter-row margins drop from mb-4 to mb-3 across the date strip + temporal pills.
commit
fb0f687c07
|
|
@ -69,6 +69,8 @@ const messages: LocaleMessages = {
|
||||||
hosting: 'Hosting',
|
hosting: 'Hosting',
|
||||||
pastEvents: 'Past events',
|
pastEvents: 'Past events',
|
||||||
past: 'Past',
|
past: 'Past',
|
||||||
|
filters: 'Filters',
|
||||||
|
clearAll: 'Clear all',
|
||||||
},
|
},
|
||||||
categories: {
|
categories: {
|
||||||
concert: 'Concert',
|
concert: 'Concert',
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ const messages: LocaleMessages = {
|
||||||
hosting: 'Organizo',
|
hosting: 'Organizo',
|
||||||
pastEvents: 'Eventos pasados',
|
pastEvents: 'Eventos pasados',
|
||||||
past: 'Pasado',
|
past: 'Pasado',
|
||||||
|
filters: 'Filtros',
|
||||||
|
clearAll: 'Limpiar todo',
|
||||||
},
|
},
|
||||||
categories: {
|
categories: {
|
||||||
concert: 'Concierto',
|
concert: 'Concierto',
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ const messages: LocaleMessages = {
|
||||||
hosting: 'J\'organise',
|
hosting: 'J\'organise',
|
||||||
pastEvents: 'Événements passés',
|
pastEvents: 'Événements passés',
|
||||||
past: 'Passé',
|
past: 'Passé',
|
||||||
|
filters: 'Filtres',
|
||||||
|
clearAll: 'Tout effacer',
|
||||||
},
|
},
|
||||||
categories: {
|
categories: {
|
||||||
concert: 'Concert',
|
concert: 'Concert',
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,8 @@ export interface LocaleMessages {
|
||||||
hosting: string
|
hosting: string
|
||||||
pastEvents: string
|
pastEvents: string
|
||||||
past: string
|
past: string
|
||||||
|
filters: string
|
||||||
|
clearAll: string
|
||||||
}
|
}
|
||||||
categories: Record<string, string>
|
categories: Record<string, string>
|
||||||
detail: {
|
detail: {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
CollapsibleContent,
|
CollapsibleContent,
|
||||||
CollapsibleTrigger,
|
CollapsibleTrigger,
|
||||||
} from '@/components/ui/collapsible'
|
} from '@/components/ui/collapsible'
|
||||||
|
import { Separator } from '@/components/ui/separator'
|
||||||
import { SlidersHorizontal, ChevronDown, History } from 'lucide-vue-next'
|
import { SlidersHorizontal, ChevronDown, History } from 'lucide-vue-next'
|
||||||
import { useEvents } from '../composables/useEvents'
|
import { useEvents } from '../composables/useEvents'
|
||||||
import EventSearchOverlay from '../components/EventSearchOverlay.vue'
|
import EventSearchOverlay from '../components/EventSearchOverlay.vue'
|
||||||
|
|
@ -40,6 +41,13 @@ const {
|
||||||
|
|
||||||
const filtersOpen = ref(false)
|
const filtersOpen = ref(false)
|
||||||
|
|
||||||
|
// Badge count on the Filters trigger so the user can see at a glance
|
||||||
|
// that hidden toggles (past-events, categories) are currently active
|
||||||
|
// even when the collapsible is closed.
|
||||||
|
const filterCount = computed(
|
||||||
|
() => selectedCategories.value.length + (showPast.value ? 1 : 0),
|
||||||
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
subscribe()
|
subscribe()
|
||||||
})
|
})
|
||||||
|
|
@ -50,16 +58,14 @@ function handleSelectEvent(event: Event) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="container mx-auto py-6 px-4">
|
<div class="container mx-auto py-4 px-4">
|
||||||
<!-- Page header -->
|
<!-- Page header -->
|
||||||
<div class="mb-4">
|
<h1 class="mb-3 text-xl sm:text-2xl font-bold text-foreground">
|
||||||
<h1 class="text-2xl sm:text-3xl font-bold text-foreground">
|
{{ t('events.title') }}
|
||||||
{{ t('events.title') }}
|
</h1>
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Search with dropdown overlay -->
|
<!-- Search with dropdown overlay -->
|
||||||
<div class="mb-4">
|
<div class="mb-3">
|
||||||
<EventSearchOverlay
|
<EventSearchOverlay
|
||||||
:events="events"
|
:events="events"
|
||||||
@select="handleSelectEvent"
|
@select="handleSelectEvent"
|
||||||
|
|
@ -67,44 +73,59 @@ function handleSelectEvent(event: Event) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Date picker strip (p'a semana style) -->
|
<!-- Date picker strip (p'a semana style) -->
|
||||||
<div class="mb-4">
|
<div class="mb-3">
|
||||||
<DatePickerStrip :selected-date="selectedDate" @select="selectDate" />
|
<DatePickerStrip :selected-date="selectedDate" @select="selectDate" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Temporal filter pills -->
|
<!-- Temporal filter pills -->
|
||||||
<div class="mb-4">
|
<div class="mb-3">
|
||||||
<TemporalFilterBar :model-value="temporal" @update:model-value="setTemporal" />
|
<TemporalFilterBar :model-value="temporal" @update:model-value="setTemporal" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Past-events filter chip. The role chips ("My tickets", "Hosting")
|
<!-- Filters collapsible (categories + past-events). Past events used
|
||||||
used to live here; they now sit in the standalone sidebar menu.
|
to live on its own row above the trigger; folded in here so the
|
||||||
"Past events" stays inline since past-browsing doesn't require
|
feed gets that vertical real estate by default. The Clear-all
|
||||||
an account and pairs visually with the temporal filters above. -->
|
affordance shares the trigger row when any filter is active so
|
||||||
<div class="mb-4 flex flex-wrap gap-2">
|
the old "Filters active" notice doesn't claim another row. -->
|
||||||
<Button
|
<Collapsible v-model:open="filtersOpen" class="mb-4">
|
||||||
:variant="showPast ? 'default' : 'outline'"
|
<div class="flex items-center gap-1">
|
||||||
size="sm"
|
<CollapsibleTrigger as-child>
|
||||||
class="gap-1.5"
|
<Button variant="ghost" size="sm" class="gap-1.5 px-2 text-muted-foreground">
|
||||||
@click="togglePast"
|
<SlidersHorizontal class="w-4 h-4" />
|
||||||
>
|
{{ t('events.filters.filters', 'Filters') }}
|
||||||
<History class="w-3.5 h-3.5" />
|
<span
|
||||||
{{ t('events.filters.pastEvents', 'Past events') }}
|
v-if="filterCount > 0"
|
||||||
</Button>
|
class="text-xs bg-primary text-primary-foreground rounded-full px-1.5"
|
||||||
</div>
|
>
|
||||||
|
{{ filterCount }}
|
||||||
<!-- Category filters (collapsible) -->
|
</span>
|
||||||
<Collapsible v-model:open="filtersOpen" class="mb-6">
|
<ChevronDown
|
||||||
<CollapsibleTrigger as-child>
|
class="w-3.5 h-3.5 transition-transform"
|
||||||
<Button variant="ghost" size="sm" class="gap-1.5 text-muted-foreground">
|
:class="{ 'rotate-180': filtersOpen }"
|
||||||
<SlidersHorizontal class="w-4 h-4" />
|
/>
|
||||||
Categories
|
</Button>
|
||||||
<span v-if="selectedCategories.length > 0" class="text-xs bg-primary text-primary-foreground rounded-full px-1.5">
|
</CollapsibleTrigger>
|
||||||
{{ selectedCategories.length }}
|
<Button
|
||||||
</span>
|
v-if="hasActiveFilters"
|
||||||
<ChevronDown class="w-3.5 h-3.5 transition-transform" :class="{ 'rotate-180': filtersOpen }" />
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
class="h-7 px-2 text-xs text-muted-foreground"
|
||||||
|
@click="resetFilters"
|
||||||
|
>
|
||||||
|
{{ t('events.filters.clearAll', 'Clear all') }}
|
||||||
</Button>
|
</Button>
|
||||||
</CollapsibleTrigger>
|
</div>
|
||||||
<CollapsibleContent class="mt-2">
|
<CollapsibleContent class="mt-2 space-y-3">
|
||||||
|
<Button
|
||||||
|
:variant="showPast ? 'default' : 'outline'"
|
||||||
|
size="sm"
|
||||||
|
class="gap-1.5"
|
||||||
|
@click="togglePast"
|
||||||
|
>
|
||||||
|
<History class="w-3.5 h-3.5" />
|
||||||
|
{{ t('events.filters.pastEvents', 'Past events') }}
|
||||||
|
</Button>
|
||||||
|
<Separator />
|
||||||
<CategoryFilterBar
|
<CategoryFilterBar
|
||||||
:selected="selectedCategories"
|
:selected="selectedCategories"
|
||||||
@toggle="toggleCategory"
|
@toggle="toggleCategory"
|
||||||
|
|
@ -113,14 +134,6 @@ function handleSelectEvent(event: Event) {
|
||||||
</CollapsibleContent>
|
</CollapsibleContent>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
|
|
||||||
<!-- Active filters indicator -->
|
|
||||||
<div v-if="hasActiveFilters" class="flex items-center gap-2 mb-4">
|
|
||||||
<span class="text-xs text-muted-foreground">Filters active</span>
|
|
||||||
<Button variant="ghost" size="sm" class="h-6 px-2 text-xs" @click="resetFilters">
|
|
||||||
Clear all
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Error state -->
|
<!-- Error state -->
|
||||||
<div v-if="error" class="mb-4 p-4 bg-destructive/10 text-destructive rounded-lg text-sm">
|
<div v-if="error" class="mb-4 p-4 bg-destructive/10 text-destructive rounded-lg text-sm">
|
||||||
{{ error }}
|
{{ error }}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue