Collapse algorithm filters into Algos dropdown

- Replace inline filter buttons in desktop header with a single
  "Algos" dropdown that shows all discovery algorithms in a glass
  menu with checkmark for the active selection and a clear option
- Button label dynamically shows the active algorithm name or
  defaults to "Algos" when no filter is active
- Rename mobile tab bar "Filters" to "Algos" with a gear icon
- Rename bottom sheet title to "Algos" to match

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dorian
2026-02-12 12:35:46 +00:00
parent 0a7543cf32
commit 7c995edcc2
2 changed files with 75 additions and 20 deletions

View File

@@ -13,15 +13,49 @@
<button @click="handleFilmsClick" :class="isRoute('/') && !activeAlgorithm ? 'nav-button-active' : 'nav-button'">Films</button>
<router-link to="/library" :class="isRoute('/library') && !activeAlgorithm ? 'nav-button-active' : 'nav-button'" @click="clearFilter">My List</router-link>
<!-- Algorithm Filters -->
<button
v-for="algo in algorithms"
:key="algo.id"
@click="setAlgorithm(algo.id)"
:class="activeAlgorithm === algo.id ? 'nav-button-active' : 'nav-button'"
>
{{ algo.label }}
</button>
<!-- Algos Dropdown -->
<div class="relative algos-dropdown">
<button
@click="toggleAlgosMenu"
:class="activeAlgorithm ? 'nav-button-active' : 'nav-button'"
>
{{ activeAlgorithmLabel || 'Algos' }}
<svg class="w-3.5 h-3.5 ml-1.5 inline transition-transform" :class="{ 'rotate-180': algosMenuOpen }" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
</button>
<div v-if="algosMenuOpen" class="profile-menu absolute left-0 mt-2 w-52">
<div class="floating-glass-header py-2 rounded-xl">
<div class="px-3 py-1 text-xs text-white/40 uppercase tracking-wider">Discovery Algorithms</div>
<button
v-for="algo in algorithms"
:key="algo.id"
@click="handleAlgoSelect(algo.id)"
class="profile-menu-item flex items-center justify-between px-4 py-2.5 w-full text-left"
>
<span>{{ algo.label }}</span>
<svg
v-if="activeAlgorithm === algo.id"
class="w-4 h-4 text-white/80"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
</button>
<template v-if="activeAlgorithm">
<div class="border-t border-white/10 my-1"></div>
<button
@click="handleAlgoClear"
class="profile-menu-item flex items-center gap-3 px-4 py-2.5 text-white/50 w-full text-left text-sm"
>
Clear filter
</button>
</template>
</div>
</div>
</div>
</nav>
</div>
@@ -205,23 +239,37 @@ const {
const {
activeAlgorithm,
activeAlgorithmLabel,
algorithms,
setAlgorithm: _setAlgorithm,
} = useContentDiscovery()
/**
* When a filter is clicked, navigate to Films page if not already there,
* then apply the filter.
*/
function setAlgorithm(id: string) {
const dropdownOpen = ref(false)
const personaMenuOpen = ref(false)
const algosMenuOpen = ref(false)
function toggleAlgosMenu() {
algosMenuOpen.value = !algosMenuOpen.value
dropdownOpen.value = false
personaMenuOpen.value = false
}
/** Select an algorithm from the dropdown, navigate to Films if needed */
function handleAlgoSelect(id: string) {
_setAlgorithm(id as any)
algosMenuOpen.value = false
if (route.path !== '/') {
router.push('/')
}
}
const dropdownOpen = ref(false)
const personaMenuOpen = ref(false)
/** Clear the active filter from the dropdown */
function handleAlgoClear() {
if (activeAlgorithm.value) {
_setAlgorithm(activeAlgorithm.value as any) // toggle off
}
algosMenuOpen.value = false
}
const userInitials = computed(() => {
if (nostrActiveName.value) return nostrActiveName.value[0].toUpperCase()
@@ -261,11 +309,13 @@ function clearFilter() {
function toggleDropdown() {
dropdownOpen.value = !dropdownOpen.value
personaMenuOpen.value = false
algosMenuOpen.value = false
}
function togglePersonaMenu() {
personaMenuOpen.value = !personaMenuOpen.value
dropdownOpen.value = false
algosMenuOpen.value = false
}
function navigateTo(path: string) {
@@ -292,12 +342,16 @@ async function handleLogout() {
const handleClickOutside = (event: MouseEvent) => {
const dropdown = document.querySelector('.profile-dropdown')
const personaDropdown = document.querySelector('.persona-dropdown')
const algosDropdown = document.querySelector('.algos-dropdown')
if (dropdown && !dropdown.contains(event.target as Node)) {
dropdownOpen.value = false
}
if (personaDropdown && !personaDropdown.contains(event.target as Node)) {
personaMenuOpen.value = false
}
if (algosDropdown && !algosDropdown.contains(event.target as Node)) {
algosMenuOpen.value = false
}
}
onMounted(() => {

View File

@@ -5,7 +5,7 @@
<div v-if="showFilterSheet" class="filter-sheet-backdrop" @click.self="showFilterSheet = false">
<div class="filter-sheet">
<div class="filter-sheet-handle"></div>
<h3 class="text-white text-base font-semibold mb-4 text-center tracking-wide">Sort By</h3>
<h3 class="text-white text-base font-semibold mb-4 text-center tracking-wide">Algos</h3>
<div class="flex flex-col gap-2">
<button
v-for="algo in algorithms"
@@ -47,7 +47,7 @@
<span class="text-xs font-medium whitespace-nowrap">Films</span>
</button>
<!-- Filters (visible on Films and My List) -->
<!-- Algos (visible on Films and My List) -->
<button
v-if="isOnFilmsPage || isActive('/library')"
@click="showFilterSheet = true"
@@ -55,9 +55,10 @@
:class="{ 'nav-tab-active': isFilterActive || showFilterSheet }"
>
<svg class="w-6 h-6 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
<span class="text-xs font-medium whitespace-nowrap">Filters</span>
<span class="text-xs font-medium whitespace-nowrap">Algos</span>
</button>
<!-- My List -->