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:
@@ -13,15 +13,49 @@
|
|||||||
<button @click="handleFilmsClick" :class="isRoute('/') && !activeAlgorithm ? 'nav-button-active' : 'nav-button'">Films</button>
|
<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>
|
<router-link to="/library" :class="isRoute('/library') && !activeAlgorithm ? 'nav-button-active' : 'nav-button'" @click="clearFilter">My List</router-link>
|
||||||
|
|
||||||
<!-- Algorithm Filters -->
|
<!-- 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
|
<button
|
||||||
v-for="algo in algorithms"
|
v-for="algo in algorithms"
|
||||||
:key="algo.id"
|
:key="algo.id"
|
||||||
@click="setAlgorithm(algo.id)"
|
@click="handleAlgoSelect(algo.id)"
|
||||||
:class="activeAlgorithm === algo.id ? 'nav-button-active' : 'nav-button'"
|
class="profile-menu-item flex items-center justify-between px-4 py-2.5 w-full text-left"
|
||||||
>
|
>
|
||||||
{{ algo.label }}
|
<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>
|
</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>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -205,23 +239,37 @@ const {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
activeAlgorithm,
|
activeAlgorithm,
|
||||||
|
activeAlgorithmLabel,
|
||||||
algorithms,
|
algorithms,
|
||||||
setAlgorithm: _setAlgorithm,
|
setAlgorithm: _setAlgorithm,
|
||||||
} = useContentDiscovery()
|
} = useContentDiscovery()
|
||||||
|
|
||||||
/**
|
const dropdownOpen = ref(false)
|
||||||
* When a filter is clicked, navigate to Films page if not already there,
|
const personaMenuOpen = ref(false)
|
||||||
* then apply the filter.
|
const algosMenuOpen = ref(false)
|
||||||
*/
|
|
||||||
function setAlgorithm(id: string) {
|
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)
|
_setAlgorithm(id as any)
|
||||||
|
algosMenuOpen.value = false
|
||||||
if (route.path !== '/') {
|
if (route.path !== '/') {
|
||||||
router.push('/')
|
router.push('/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dropdownOpen = ref(false)
|
/** Clear the active filter from the dropdown */
|
||||||
const personaMenuOpen = ref(false)
|
function handleAlgoClear() {
|
||||||
|
if (activeAlgorithm.value) {
|
||||||
|
_setAlgorithm(activeAlgorithm.value as any) // toggle off
|
||||||
|
}
|
||||||
|
algosMenuOpen.value = false
|
||||||
|
}
|
||||||
|
|
||||||
const userInitials = computed(() => {
|
const userInitials = computed(() => {
|
||||||
if (nostrActiveName.value) return nostrActiveName.value[0].toUpperCase()
|
if (nostrActiveName.value) return nostrActiveName.value[0].toUpperCase()
|
||||||
@@ -261,11 +309,13 @@ function clearFilter() {
|
|||||||
function toggleDropdown() {
|
function toggleDropdown() {
|
||||||
dropdownOpen.value = !dropdownOpen.value
|
dropdownOpen.value = !dropdownOpen.value
|
||||||
personaMenuOpen.value = false
|
personaMenuOpen.value = false
|
||||||
|
algosMenuOpen.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function togglePersonaMenu() {
|
function togglePersonaMenu() {
|
||||||
personaMenuOpen.value = !personaMenuOpen.value
|
personaMenuOpen.value = !personaMenuOpen.value
|
||||||
dropdownOpen.value = false
|
dropdownOpen.value = false
|
||||||
|
algosMenuOpen.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigateTo(path: string) {
|
function navigateTo(path: string) {
|
||||||
@@ -292,12 +342,16 @@ async function handleLogout() {
|
|||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
const dropdown = document.querySelector('.profile-dropdown')
|
const dropdown = document.querySelector('.profile-dropdown')
|
||||||
const personaDropdown = document.querySelector('.persona-dropdown')
|
const personaDropdown = document.querySelector('.persona-dropdown')
|
||||||
|
const algosDropdown = document.querySelector('.algos-dropdown')
|
||||||
if (dropdown && !dropdown.contains(event.target as Node)) {
|
if (dropdown && !dropdown.contains(event.target as Node)) {
|
||||||
dropdownOpen.value = false
|
dropdownOpen.value = false
|
||||||
}
|
}
|
||||||
if (personaDropdown && !personaDropdown.contains(event.target as Node)) {
|
if (personaDropdown && !personaDropdown.contains(event.target as Node)) {
|
||||||
personaMenuOpen.value = false
|
personaMenuOpen.value = false
|
||||||
}
|
}
|
||||||
|
if (algosDropdown && !algosDropdown.contains(event.target as Node)) {
|
||||||
|
algosMenuOpen.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<div v-if="showFilterSheet" class="filter-sheet-backdrop" @click.self="showFilterSheet = false">
|
<div v-if="showFilterSheet" class="filter-sheet-backdrop" @click.self="showFilterSheet = false">
|
||||||
<div class="filter-sheet">
|
<div class="filter-sheet">
|
||||||
<div class="filter-sheet-handle"></div>
|
<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">
|
<div class="flex flex-col gap-2">
|
||||||
<button
|
<button
|
||||||
v-for="algo in algorithms"
|
v-for="algo in algorithms"
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<span class="text-xs font-medium whitespace-nowrap">Films</span>
|
<span class="text-xs font-medium whitespace-nowrap">Films</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Filters (visible on Films and My List) -->
|
<!-- Algos (visible on Films and My List) -->
|
||||||
<button
|
<button
|
||||||
v-if="isOnFilmsPage || isActive('/library')"
|
v-if="isOnFilmsPage || isActive('/library')"
|
||||||
@click="showFilterSheet = true"
|
@click="showFilterSheet = true"
|
||||||
@@ -55,9 +55,10 @@
|
|||||||
:class="{ 'nav-tab-active': isFilterActive || showFilterSheet }"
|
:class="{ 'nav-tab-active': isFilterActive || showFilterSheet }"
|
||||||
>
|
>
|
||||||
<svg class="w-6 h-6 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<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>
|
</svg>
|
||||||
<span class="text-xs font-medium whitespace-nowrap">Filters</span>
|
<span class="text-xs font-medium whitespace-nowrap">Algos</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- My List -->
|
<!-- My List -->
|
||||||
|
|||||||
Reference in New Issue
Block a user