Migrate to Vue 3 and Vite
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
161
js/src/views/CategoriesView.vue
Normal file
161
js/src/views/CategoriesView.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<div class="container mx-auto py-4 md:py-12 px-2 md:px-60">
|
||||
<main>
|
||||
<div class="flex flex-wrap items-center justify-center gap-3 md:gap-4">
|
||||
<CategoryCard
|
||||
v-for="category in promotedCategories"
|
||||
:key="category.key"
|
||||
:category="category"
|
||||
:with-details="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mx-auto w-full max-w-lg rounded-2xl dark:bg-gray-800 p-2 mt-10"
|
||||
>
|
||||
<div
|
||||
class="card"
|
||||
animation="slide"
|
||||
:open="isLicencePanelOpen"
|
||||
@open="isLicencePanelOpen = !isLicencePanelOpen"
|
||||
:aria-id="'contentIdForA11y5'"
|
||||
>
|
||||
<div>
|
||||
<button
|
||||
class="flex w-full justify-between rounded-lg px-4 py-2 text-left text-sm font-medium dark:text-zinc-300"
|
||||
>
|
||||
{{ t("Category illustrations credits") }}
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
:class="isLicencePanelOpen ? 'transform rotate-90' : ''"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="{2}"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9 5l7 7-7 7"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex flex-col dark:text-zinc-300 gap-2 py-4 px-1">
|
||||
<p
|
||||
v-for="(categoryLicence, key) in categoriesPicturesLicences"
|
||||
:key="key"
|
||||
class="flex flex-row gap-1 items-center"
|
||||
>
|
||||
<a
|
||||
:href="categoryLicence.source.url"
|
||||
target="_blank"
|
||||
class="shrink-0"
|
||||
>
|
||||
<picture class="brightness-50">
|
||||
<source
|
||||
:srcset="`/img/categories/${key.toLowerCase()}.jpg 2x, /img/categories/${key.toLowerCase()}.jpg`"
|
||||
media="(min-width: 1000px)"
|
||||
/>
|
||||
<source
|
||||
:srcset="`/img/categories/${key.toLowerCase()}.jpg 2x, /img/categories/${key.toLowerCase()}-small.jpg`"
|
||||
media="(min-width: 300px)"
|
||||
/>
|
||||
<img
|
||||
class="w-full h-12 w-12 object-cover"
|
||||
:src="`/img/categories/${key.toLowerCase()}.jpg`"
|
||||
:srcset="`/img/categories/${key.toLowerCase()}-small.jpg `"
|
||||
alt=""
|
||||
/>
|
||||
</picture>
|
||||
</a>
|
||||
<span
|
||||
class="flex-0"
|
||||
v-html="
|
||||
t(
|
||||
'Illustration picture for “{category}” by {author} on {source} ({license})',
|
||||
{
|
||||
category: eventCategoryLabel(key),
|
||||
author: imageAuthor(categoryLicence.author),
|
||||
source: imageSource(categoryLicence.source),
|
||||
license: imageLicense(categoryLicence),
|
||||
}
|
||||
)
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import CategoryCard from "@/components/Categories/CategoryCard.vue";
|
||||
|
||||
import { computed, ref } from "vue";
|
||||
import { CATEGORY_STATISTICS } from "@/graphql/statistics";
|
||||
import { useQuery } from "@vue/apollo-composable";
|
||||
import { CategoryStatsModel } from "@/types/stats.model";
|
||||
import {
|
||||
categoriesPicturesLicences,
|
||||
CategoryPictureLicencing,
|
||||
CategoryPictureLicencingElement,
|
||||
} from "@/components/Categories/constants";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
const { result: configResult } = useQuery<{ config: IConfig }>(CONFIG);
|
||||
|
||||
const config = computed(() => configResult.value?.config);
|
||||
|
||||
const eventCategories = computed(() => config.value?.eventCategories ?? []);
|
||||
|
||||
const eventCategoryLabel = (categoryId: string): string | undefined => {
|
||||
return eventCategories.value.find(({ id }) => categoryId == id)?.label;
|
||||
};
|
||||
|
||||
const { result: categoryStatsResult } = useQuery<{
|
||||
categoryStatistics: CategoryStatsModel[];
|
||||
}>(CATEGORY_STATISTICS);
|
||||
const categoryStats = computed(
|
||||
() => categoryStatsResult.value?.categoryStatistics ?? []
|
||||
);
|
||||
|
||||
const promotedCategories = computed((): CategoryStatsModel[] => {
|
||||
return categoryStats.value
|
||||
.map(({ key, number }) => ({
|
||||
key,
|
||||
number,
|
||||
label: eventCategoryLabel(key),
|
||||
}))
|
||||
.filter(
|
||||
({ key, number, label }) =>
|
||||
key !== "MEETING" && number >= 1 && label !== undefined
|
||||
)
|
||||
.sort((a, b) => a.label.localeCompare(b.label));
|
||||
});
|
||||
|
||||
const imageAuthor = (author: CategoryPictureLicencingElement) =>
|
||||
`<a target="_blank" class="underline font-medium" href="${author?.url}">${author?.name}</a>`;
|
||||
const imageSource = (source: CategoryPictureLicencingElement) =>
|
||||
`<a target="_blank" class="underline font-medium" href="${source?.url}">${source?.name}</a>`;
|
||||
|
||||
const imageLicense = (categoryLicence: CategoryPictureLicencing): string => {
|
||||
let license = categoryLicence?.license;
|
||||
if (categoryLicence?.source?.name === "Unsplash") {
|
||||
license = {
|
||||
name: "Unsplash License",
|
||||
url: "https://unsplash.com/license",
|
||||
};
|
||||
}
|
||||
return `<a target="_blank" class="underline font-medium" href="${license?.url}">${license?.name}</a>`;
|
||||
};
|
||||
|
||||
const isLicencePanelOpen = ref(false);
|
||||
</script>
|
||||
Reference in New Issue
Block a user