Skip to content

Commit

Permalink
#527 reset CardTopicSelection functionalithy - ready for a11y work
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtavis committed Jan 7, 2024
1 parent 94735a0 commit cb57435
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 77 deletions.
115 changes: 73 additions & 42 deletions frontend/components/card/CardTopicSelection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,74 @@
</p>
<input
v-model="query"
@focus="inputFocus = true"
id="query"
:display-value="() => query"
:placeholder="$t('components.card-topic-selection.selector-placeholder')"
class="w-full py-2 pl-4 text-light-special-text dark:text-dark-special-text bg-light-header dark:bg-dark-header rounded-md elem-shadow-sm focus-brand"
class="w-full py-2 pl-4 rounded-md text-light-special-text dark:text-dark-special-text bg-light-header dark:bg-dark-header elem-shadow-sm focus-brand"
/>
<TabGroup
manual
:defaultIndex="0"
class="flex flex-col gap-2 md:flex-row md:items-center"
<ul class="hidden gap-2 sm:flex sm:flex-wrap">
<ShieldTopic
v-for="t of filteredTopics"
@click="selectTopic(t)"
@keydown.enter.prevent="selectTopic(t)"
:key="t.value"
:topic="t.label"
class="max-sm:w-full"
:active="isActiveTopic(t.value)"
:isSelector="true"
/>
</ul>
<ul
class="flex flex-col gap-2 sm:hidden"
:class="{
'pb-2': moreOptionsShown || inputFocus || filteredTopics.length,
}"
>
<TabList>
<Tab
v-for="topic of filteredTopics"
@click="selectTopic(topic)"
@keydown.enter.prevent="selectTopic(topic)"
:key="topic.value"
:value="topic.value"
multiple
as="template"
class="flex justify-between px-4 py-2 rounded-lg cursor-pointer select-none md:px-2 gap-2 elem-shadow-sm"
>
<div
:class="{
'style-cta': isActiveTopic(topic.value),
'style-cta-secondary': !isActiveTopic(topic.value),
}"
>
<span class="flex items-center gap-2">
<Icon :name="topic.icon" size="20" />
{{ $t(topic.label) }}
</span>
<Icon v-if="isActiveTopic(topic.value)" name="bi:x-lg" size="20" />
</div>
</Tab>
</TabList>
</TabGroup>
<ShieldTopic
v-if="moreOptionsShown || inputFocus"
v-for="t of filteredTopics"
@click="selectTopic(t)"
@keydown.enter.prevent="selectTopic(t)"
:key="t.value + '-selected-only'"
:topic="t.label"
class="max-sm:w-full"
:active="isActiveTopic(t.value)"
:isSelector="true"
/>
<ShieldTopic
v-else
v-for="t of selectedTopicTags.sort((a, b) =>
a.value.localeCompare(b.value)
)"
@click="selectTopic(t)"
@keydown.enter.prevent="selectTopic(t)"
:key="t.value"
:topic="t.label"
class="max-sm:w-full"
:active="isActiveTopic(t.value)"
:isSelector="true"
/>
</ul>
<a
@click="
moreOptionsShown =
inputFocus == true ? (moreOptionsShown = false) : !moreOptionsShown;
inputFocus = false;
"
class="cursor-pointer link-text sm:hidden"
>
<div v-if="!moreOptionsShown && !inputFocus">
{{ $t("components.card-topic-selection.view-all-topics") }}
</div>
<div v-else>
{{ $t("components.card-topic-selection.hide-all-topics") }}
</div>
</a>
</div>
</template>

<script setup lang="ts">
import { Tab, TabGroup, TabList } from "@headlessui/vue";
import type { Topic, TopicsTag } from "~/types/topics";
import { GLOBAL_TOPICS } from "~/types/topics";
Expand All @@ -57,6 +84,8 @@ const props = defineProps({
},
});
const moreOptionsShown = ref(false);
const inputFocus = ref(false);
const emit = defineEmits(["update:modelValue"]);
const value = computed<Topic[]>({
Expand All @@ -82,12 +111,9 @@ const selectTopic = (topic: TopicsTag) => {
value.value = updatedValue;
};
const topics = computed((): TopicsTag[] => {
return [
...selectedTopicTags.value,
...GLOBAL_TOPICS.filter((topic) => !isActiveTopic(topic.value)),
];
});
function isActiveTopic(topic: Topic) {
return value.value.includes(topic);
}
const selectedTopicTags = computed(() => {
return value.value
Expand All @@ -97,13 +123,18 @@ const selectedTopicTags = computed(() => {
.filter((tag) => tag) as TopicsTag[];
});
const topics = computed((): TopicsTag[] => {
return [
...selectedTopicTags.value.sort((a, b) => a.value.localeCompare(b.value)),
...GLOBAL_TOPICS.filter((topic) => !isActiveTopic(topic.value)).sort(
(a, b) => a.value.localeCompare(b.value)
),
];
});
const filteredTopics = computed(() => {
return topics.value.filter((topic) => {
return topic.value.includes(query.value.trim().toLowerCase());
});
});
function isActiveTopic(topic: Topic) {
return value.value.includes(topic);
}
</script>
19 changes: 10 additions & 9 deletions frontend/components/combobox/ComboboxTopics.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
@focus="handleInputFocus"
@blur="inputFocussed = false"
class="py-2 pl-4 border rounded-lg style-cta selection:bg-light-highlight dark:selection:bg-white/20"
:displayValue="(_) => displayValue()"
:displayValue="(_) => $t(displayValue())"
/>
<div
class="absolute inset-y-0 right-0 flex items-center pr-3 text-light-text dark:text-dark-cta-orange"
Expand All @@ -30,7 +30,7 @@
>
<ComboboxOptions
id="isVisibleElement"
class="absolute w-full py-1 mt-1 overflow-auto text-base max-h-60 rounded-md bg-light-distinct dark:bg-dark-distinct elem-shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm"
class="absolute w-full mt-1 overflow-auto text-base max-h-60 rounded-md bg-light-distinct dark:bg-dark-distinct elem-shadow-lg ring-1 ring-black/5 focus:outline-none sm:text-sm"
>
<div
v-if="filteredTopics.length === 0 && query !== ''"
Expand All @@ -55,7 +55,7 @@
}"
>
<span class="block truncate">
{{ topic.name }}
{{ $t(topic.name) }}
</span>
<span
v-if="selected"
Expand Down Expand Up @@ -85,13 +85,14 @@ import {
ComboboxOptions,
TransitionRoot,
} from "@headlessui/vue";
import { GLOBAL_TOPICS } from "~/types/topics";
const topics = [
{ id: 1, name: "All topics" },
{ id: 2, name: "Environment" },
{ id: 3, name: "Animal rights" },
{ id: 4, name: "Racial justice" },
];
const topics = [{ id: 1, name: "_global.topics.all-topics" }];
let nextId = topics.length + 1;
for (const t of GLOBAL_TOPICS) {
topics.push({ id: nextId++, name: t.label });
}
const selectedTopic = ref(topics[0]);
const query = ref("");
Expand Down
34 changes: 23 additions & 11 deletions frontend/components/shield/ShieldTopic.vue
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
<template>
<div
class="flex items-center justify-between pl-2 pr-3 border rounded-full w-max h-max hover:cursor-pointer style-cta elem-shadow-sm"
class="flex items-center justify-between border w-max h-max cursor-pointer style-cta elem-shadow-sm space-x-2"
:class="{
'style-cta': active,
'style-cta-secondary': !active,
'pl-2 pr-3 rounded-full': !isSelector,
'py-1 sm:py-0 rounded-lg pl-4 pr-5 sm:pl-2 sm:pr-3': isSelector,
}"
>
<Icon
class="flex-shrink-0 w-5 h-5 my-1 rounded-full"
name="bi:globe"
size="1em"
/>
<p class="pl-2 text-base font-bold text-center select-none">
{{ topic }}
</p>
<div class="flex items-center" :class="{ 'max-sm:flex-grow': isSelector }">
<Icon class="flex-shrink-0 w-5 h-5 my-1" name="bi:globe" size="1em" />
<p class="pl-2 text-base font-bold text-center select-none">
{{ $t(topic) }}
</p>
</div>
<Icon v-if="active && isSelector" name="bi:x-lg" size="20" />
</div>
</template>

<script setup lang="ts">
defineProps<{
export interface Props {
topic: string;
}>();
active?: boolean;
isSelector?: boolean;
}
withDefaults(defineProps<Props>(), {
active: true,
isSelector: false,
});
</script>
24 changes: 22 additions & 2 deletions frontend/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,28 @@
"_global.tasks_lower": "tasks",
"_global.team": "Team",
"_global.team_lower": "team",
"_global.topics.activism": "Activism",
"_global.topics.accessibility": "Accessibility",
"_global.topics.all-topics": "All Topics",
"_global.topics.animal-rights": "Animal Rights",
"_global.topics.children-rights": "Children's Rights",
"_global.topics.democracy": "Democracy",
"_global.topics.education": "Education",
"_global.topics.elders": "Elder Rights",
"_global.topics.emergency-relief": "Emergency Relief",
"_global.topics.environment": "Environment",
"_global.topics.justice": "Justice",
"_global.topics.expression": "Expression",
"_global.topics.health": "Health",
"_global.topics.housing": "Housing",
"_global.topics.labor": "Labor Rights",
"_global.topics.lgbtqia": "LGBTQIA+",
"_global.topics.migration": "Migration",
"_global.topics.mobility": "Mobility",
"_global.topics.nutrition": "Nutrition",
"_global.topics.peace-resolution": "Peace and Resolution",
"_global.topics.racial-justice": "Racial Justice",
"_global.topics.technology-privacy": "Technology and Privacy",
"_global.topics.transparency": "Transparency",
"_global.topics.women": "Women's Rights",
"_global.trademark-policy": "Trademark policy",
"components._global.connect": "Connect",
"components._global.copyright": "Copyright \u00a9 2023 activist.",
Expand Down Expand Up @@ -173,6 +191,8 @@
"components.card-search-result-resource.img-alt-text": "The resource logo of",
"components.card-topic-selection.header": "Topics",
"components.card-topic-selection.selector-placeholder": "Type to filter topics",
"components.card-topic-selection.view-all-topics": "View all topics",
"components.card-topic-selection.hide-all-topics": "Hide all topics",
"components.combobox-topics.no-matching-topics": "No matching topics.",
"components.feed-item.img-alt-text": "A social media post's image.",
"components.footer._global.activist-tagline": "Open-source, nonprofit activism platform.",
Expand Down
2 changes: 1 addition & 1 deletion frontend/pages/organizations/create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const formData = ref({
description: "",
tagline: "",
social_accounts: [],
topics: ["justice", "activism"],
topics: [],
});
const submit = async () => {
Expand Down
Loading

0 comments on commit cb57435

Please sign in to comment.