Skip to content

Commit

Permalink
feat(filter): added filter common component (#1027)
Browse files Browse the repository at this point in the history
* feat(filter): added filter common component

* refactor(lint): fixed lint errors

* refactor(format): fixed formatting issues

* feat(test): added test cases

* refactor(lint): fixed formatting and lint

* Remove unneeded test and comment out use for now

* Minor fixes for frontend linting checks

* Get rid of unused constant

---------

Co-authored-by: Andrew Tavis McAllister <[email protected]>
  • Loading branch information
Hasteerp and andrewtavis authored Dec 10, 2024
1 parent 3387bed commit a56ef26
Show file tree
Hide file tree
Showing 9 changed files with 389 additions and 15 deletions.
6 changes: 3 additions & 3 deletions frontend/components/SearchBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
>
<TooltipBase
class="invisible -mt-8"
:text="$t('components.search_bar.slash_tooltip_label')"
:text="$t('components._global.slash_tooltip_label')"
/>
<p class="-mt-[0.075rem]">/</p>
</div>
Expand All @@ -51,7 +51,7 @@
>
<TooltipBase
class="invisible -mt-8"
:text="$t('components.search_bar.command_tooltip_label')"
:text="$t('components._global.command_tooltip_label')"
/>
<p>⌘k</p>
</div>
Expand All @@ -61,7 +61,7 @@
>
<TooltipBase
class="invisible -mt-8"
:text="$t('components.search_bar.control_tooltip_label')"
:text="$t('components._global.control_tooltip_label')"
/>
<p>⌃k</p>
</div>
Expand Down
33 changes: 33 additions & 0 deletions frontend/components/btn/BtnTag.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<template>
<button
:id="id"
class="btn-base-class rounded-md xl:rounded-lg"
:class="[
btnDynamicClass,
!cta && 'style-cta bg-[#C8C8C8] hover:bg-[#C8C8C8]/70',
cta && 'style-cta',
]"
:aria-label="$t(ariaLabel)"
>
<BtnIconsLabel
:label="label"
:hideLabelOnMobile="hideLabelOnMobile"
:leftIcon="leftIcon"
:rightIcon="rightIcon"
:iconSize="iconSize"
:counter="counter"
/>
</button>
</template>

<script setup lang="ts">
import type { BtnAction } from "~/types/btn-props";
import { getBtnDynamicClass } from "~/utils/btnUtils";
const props = defineProps<BtnAction>();
const btnDynamicClass = getBtnDynamicClass(
props.cta,
props.fontSize,
props.isDisabled
);
</script>
263 changes: 263 additions & 0 deletions frontend/components/page/PageFilter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
<template>
<div class="card-style flex flex-col px-3 py-4 md:px-5">
<div class="relative flex w-full flex-col">
<!-- Header with Tabs -->
<div class="mb-4 flex items-center justify-between">
<h2 class="text-2xl font-semibold">Filter</h2>
<div
class="inline-flex overflow-hidden rounded-lg border border-primary-text"
>
<button
v-for="(tab, index) in tabs"
@click="activeTab = tab.id"
:key="tab.id"
:class="[
'px-4 py-2',
activeTab === tab.id
? 'bg-cta-orange text-primary-text'
: 'bg-[#C8C8C8] text-primary-text hover:bg-[#C8C8C8]/70',
index !== tabs.length - 1 ? 'border-r border-primary-text' : '',
]"
>
{{ tab.name }}
</button>
</div>
</div>

<!-- Search Input -->
<div
class="elem-shadow-sm flex select-none items-center justify-between rounded-md bg-layer-2 py-1 pl-[12px] text-left text-distinct-text transition duration-200 focus-within:mb-[-3px] focus-within:border-2 focus-within:border-link-text"
>
<div class="flex flex-1 items-center space-x-2 pl-1">
<Icon
class="my-1 h-4 w-4 flex-shrink-0"
:name="IconMap.SEARCH"
size="1em"
/>
<div class="min-w-0 flex-1">
<label for="input-search" class="sr-only">{{
"Search to filter"
}}</label>
<input
v-model="searchQuery"
@focus="onFocus"
@blur="onFocusLost"
ref="input"
id="input-search"
class="w-full text-ellipsis bg-transparent py-2 outline-none"
type="text"
placeholder="Search to filter"
/>
</div>
</div>
<div
ref="hotkeyIndicators"
class="transition-duration-200 flex flex-shrink-0 space-x-1 pr-1 transition-opacity"
>
<div
class="has-tooltip flex rounded-md bg-highlight px-2 py-[0.125rem] text-center text-sm text-distinct-text"
>
<TooltipBase
class="invisible -mt-8"
:text="$t('components._global.slash_tooltip_label')"
/>
<p class="-mt-[0.075rem]">/</p>
</div>
<div
v-if="isMacOS"
class="has-tooltip flex rounded-md bg-highlight px-2 py-[0.125rem] text-center text-sm text-distinct-text"
>
<TooltipBase
class="invisible -mt-8"
:text="$t('components._global.command_tooltip_label')"
/>
<p>⌘k</p>
</div>
<div
v-else
class="has-tooltip flex rounded-md bg-highlight px-2 py-[0.125rem] text-center text-sm text-distinct-text"
>
<TooltipBase
class="invisible -mt-8"
:text="$t('components._global.control_tooltip_label')"
/>
<p>⌃k</p>
</div>
</div>
</div>

<!-- Tag Sections -->
<div
v-for="(section, sectionIndex) in sections"
:key="sectionIndex"
class="mt-4"
>
<h3 class="mb-3 flex items-center gap-2">
<span
class="font-redhat flex items-center text-[22px] font-[600] leading-[29.11px]"
>
{{ section.title }}
<Icon
v-if="section.icon"
:name="section.icon"
class="ml-2 h-4 w-4 text-primary-text"
/>
</span>
</h3>
<!-- <GridFilterTags :tags="['Berlin', 'Activism', 'Eco']" class="mt-3" /> -->
<div class="flex flex-wrap gap-2">
<BtnTag
v-for="tag in section.tags"
@click="toggleTag(tag)"
@keydown.enter="toggleTag(tag)"
:key="tag.id"
class="flex max-h-[40px]"
:cta="tag.selected"
:label="tag.name"
fontSize="sm"
:ariaLabel="$t(tag.name)"
/>
</div>
</div>
</div>
</div>
</template>

<script setup lang="ts">
import { useMagicKeys, whenever } from "@vueuse/core";
import { ref } from "vue";
import { IconMap } from "~/types/icon-map";
interface Tag {
id: number;
name: string;
selected: boolean;
}
interface TagSection {
title: string;
tags: Tag[];
icon?: string;
}
interface Tab {
id: string;
name: string;
}
const props = defineProps<{
sections: TagSection[];
tabs: Tab[];
}>();
const { isMacOS } = useDevice();
const searchQuery = ref("");
const input = ref();
const hotkeyIndicators = ref();
const isInputFocused = ref(false);
const { slash } = useMagicKeys({
passive: false,
onEventFired(e) {
if (e.key === "/" && e.type === "keydown") e.preventDefault();
},
});
whenever(slash, () => {
setTimeout(() => {
if (input.value) {
input.value.focus();
}
}, 0);
});
const onFocus = () => {
hotkeyIndicators.value.classList.add("hide");
setTimeout(() => {
isInputFocused.value = true;
hotkeyIndicators.value.classList.add("hidden");
}, 200);
};
const onFocusLost = () => {
hotkeyIndicators.value.classList.remove("hidden");
isInputFocused.value = false;
setTimeout(() => {
hotkeyIndicators.value.classList.remove("hide");
}, 200);
};
const emit = defineEmits<{
"filter-change": [
{
search: string;
activeTab: string;
selectedTags: number[];
},
];
}>();
const toggleTag = (tag: Tag) => {
tag.selected = !tag.selected;
emitChange();
};
const emitChange = () => {
emit("filter-change", {
search: searchQuery.value,
activeTab: activeTab.value,
selectedTags: props.sections[0].tags
.filter((t) => t.selected)
.map((t) => t.id),
});
};
watch(searchQuery, () => {
emitChange();
});
const activeTab = ref(props.tabs[0]?.id || "");
watch(activeTab, () => {
emitChange();
});
</script>

<style scoped>
.hide {
opacity: 0;
}
.search-enter-active {
transition: opacity 0.25s ease;
transition-delay: 0.125s;
}
.search-leave-active {
transition: opacity 0.25s ease;
}
.search-enter-from,
.search-leave-to {
opacity: 0;
}
.search-enter-from {
transition-delay: 0.25s;
}
.shortcuts-enter-active {
transition: opacity 0.25s ease;
transition-delay: 0.375s;
}
.shortcuts-leave-active {
transition: opacity 0.125s ease;
}
.shortcuts-enter-from,
.shortcuts-leave-to {
opacity: 0;
}
</style>
6 changes: 3 additions & 3 deletions frontend/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,9 @@
"components.page_community_footer.need_help_text_2_1": "Gehen Sie rüber zu",
"components.page_community_footer.need_help_text_2_3": "wo Sie Fehler melden oder Funktionen anfordern können",
"components.page_community_footer.visit_our": "Besuchen Sie unsere",
"components.search_bar.command_tooltip_label": "Drücken Sie \"⌘ + k\", um zu einer Seite zu springen",
"components.search_bar.control_tooltip_label": "Drücken Sie \"⌘ + k\", um zu einer Seite zu springen",
"components.search_bar.slash_tooltip_label": "Zum Suchen „/“ drücken",
"components._global.command_tooltip_label": "Drücken Sie \"⌘ + k\", um zu einer Seite zu springen",
"components._global.control_tooltip_label": "Drücken Sie \"⌘ + k\", um zu einer Seite zu springen",
"components._global.slash_tooltip_label": "Zum Suchen „/“ drücken",
"components.shield_private.private": "Privat",
"components.sidebar_left.location_search_placeholder": "Nach Ort filtern",
"components.sidebar_left.orgs_search_placeholder": "Nach Organisationen filtern",
Expand Down
6 changes: 3 additions & 3 deletions frontend/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@
"components.page_community_footer.need_help_text_2_1": "Head over to",
"components.page_community_footer.need_help_text_2_3": "where you can report bugs or request features",
"components.page_community_footer.visit_our": "Visit our",
"components.search_bar.command_tooltip_label": "Press \"\u2318 + k\" to jump to a page",
"components.search_bar.control_tooltip_label": "Press \"^ + k\" to jump to a page",
"components.search_bar.slash_tooltip_label": "Press \"/\" to search",
"components._global.command_tooltip_label": "Press \"\u2318 + k\" to jump to a page",
"components._global.control_tooltip_label": "Press \"^ + k\" to jump to a page",
"components._global.slash_tooltip_label": "Press \"/\" to search",
"components.shield_private.private": "Private",
"components.sidebar_left.location_search_placeholder": "Filter by location",
"components.sidebar_left.orgs_search_placeholder": "Filter by orgs",
Expand Down
6 changes: 3 additions & 3 deletions frontend/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@
"components.page_community_footer.need_help_text_2_1": "Dirigez-vous vers",
"components.page_community_footer.need_help_text_2_3": "où vous pourrez signaler des bogues ou demander des fonctionnalités",
"components.page_community_footer.visit_our": "Visiter notre",
"components.search_bar.command_tooltip_label": "Presser \"⌘ + k\" pour sauter vers une page",
"components.search_bar.control_tooltip_label": "Presser \"^ + k\" pour sauter vers une page",
"components.search_bar.slash_tooltip_label": "Pressez \"/\" pour chercher",
"components._global.command_tooltip_label": "Presser \"⌘ + k\" pour sauter vers une page",
"components._global.control_tooltip_label": "Presser \"^ + k\" pour sauter vers une page",
"components._global.slash_tooltip_label": "Pressez \"/\" pour chercher",
"components.shield_private.private": "Privé",
"components.sidebar_left.location_search_placeholder": "Filtrer par emplacement",
"components.sidebar_left.orgs_search_placeholder": "filtrer par orgs",
Expand Down
6 changes: 3 additions & 3 deletions frontend/i18n/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@
"components.page_community_footer.need_help_text_2_1": "Dirija-se para",
"components.page_community_footer.need_help_text_2_3": "onde pode reportar bugs ou solicitar funcionalidades",
"components.page_community_footer.visit_our": "Visite o nosso",
"components.search_bar.command_tooltip_label": "Pressione \"⌘ + k\" para saltar para uma página",
"components.search_bar.control_tooltip_label": "Pressione \"^ + k\" para saltar para uma página",
"components.search_bar.slash_tooltip_label": "Pressione \"/\" para pesquisar",
"components._global.command_tooltip_label": "Pressione \"⌘ + k\" para saltar para uma página",
"components._global.control_tooltip_label": "Pressione \"^ + k\" para saltar para uma página",
"components._global.slash_tooltip_label": "Pressione \"/\" para pesquisar",
"components.shield_private.private": "Privado",
"components.sidebar_left.location_search_placeholder": "Filtrar por localização",
"components.sidebar_left.orgs_search_placeholder": "Filtrar por organizações",
Expand Down
Loading

0 comments on commit a56ef26

Please sign in to comment.