Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update VCollectionHeader.vue #3365

Merged
merged 1 commit into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 75 additions & 27 deletions frontend/src/components/VCollectionHeader/VCollectionHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,18 @@
import { computed, defineComponent, PropType } from "vue"

import { useUiStore } from "~/stores/ui"
import type { Collection } from "~/types/search"
import type { CollectionParams } from "~/types/search"
import { useAnalytics } from "~/composables/use-analytics"

import VButton from "~/components/VButton.vue"
import { useProviderStore } from "~/stores/provider"
import { SupportedMediaType } from "~/constants/media"

import { useI18nResultsCount } from "~/composables/use-i18n-utilities"

import { useMediaStore } from "~/stores/media"

import VIcon from "~/components/VIcon/VIcon.vue"
import VButton from "~/components/VButton.vue"

const icons = {
tag: "tag",
Expand All @@ -55,55 +62,96 @@ export default defineComponent({
name: "VCollectionHeader",
components: { VIcon, VButton },
props: {
collection: {
type: String as PropType<Collection>,
required: true,
},
/**
* The name of the tag/creator/source. The source name should be the display
* name, not the code.
*/
title: {
type: String,
collectionParams: {
type: Object as PropType<CollectionParams>,
required: true,
},
slug: {
creatorUrl: {
type: String,
},
url: {
type: String,
},
/**
* The label showing the result count, to display below the title.
* Should be built by the parent component.
*/
resultsLabel: {
type: String,
mediaType: {
type: String as PropType<SupportedMediaType>,
required: true,
},
},
setup(props) {
const providerStore = useProviderStore()
const uiStore = useUiStore()

const iconName = computed(() => icons[props.collection])
const iconName = computed(() => icons[props.collectionParams.collection])
const collection = computed(() => props.collectionParams.collection)

const sourceName = computed(() => {
if (props.collectionParams.collection === "tag") {
return ""
}
return providerStore.getProviderName(
props.collectionParams.source,
props.mediaType
)
})

const title = computed(() => {
if (props.collectionParams.collection === "tag") {
return props.collectionParams.tag
} else if (props.collectionParams.collection === "creator") {
return props.collectionParams.creator
}
return sourceName.value
})

const url = computed(() => {
if (props.collectionParams.collection === "tag") {
return undefined
} else if (props.collectionParams.collection === "creator") {
return props.creatorUrl
}
return providerStore.getSourceUrl(
props.collectionParams.source,
props.mediaType
)
})
const { getI18nCollectionResultCountLabel } = useI18nResultsCount()

const resultsLabel = computed(() => {
const resultsCount = useMediaStore().results[props.mediaType].count
if (props.collectionParams.collection === "creator") {
return getI18nCollectionResultCountLabel(
resultsCount,
props.mediaType,
"creator",
{ source: sourceName.value }
)
}
return getI18nCollectionResultCountLabel(
resultsCount,
props.mediaType,
props.collectionParams.collection
)
})

const isMd = computed(() => uiStore.isBreakpoint("md"))

const { sendCustomEvent } = useAnalytics()

const sendAnalyticsEvent = () => {
if (!props.url || !props.slug) return
if (props.collectionParams.collection === "tag") return

const eventName =
props.collection === "creator"
props.collectionParams.collection === "creator"
? "VISIT_CREATOR_LINK"
: "VISIT_SOURCE_LINK"
sendCustomEvent(eventName, {
url: props.url,
source: props.slug,
url: url.value,
source: props.collectionParams.source,
})
}

return {
collection,
title,
resultsLabel,
url,
iconName,
isMd,
sendAnalyticsEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,98 @@ import {
Meta,
Story,
} from "@storybook/addon-docs"
import { useProviderStore } from "~/stores/provider"

import VCollectionHeader from "~/components/VCollectionHeader/VCollectionHeader.vue"
import { useMediaStore } from "@/stores/media"

<Meta title="Components/VCollectionHeader" component={VCollectionHeader} />

export const imageProviders = [
{
source_name: "smithsonian_african_american_history_museum",
display_name:
"Smithsonian Institution: National Museum of African American History and Culture",
source_url: "https://nmaahc.si.edu",
logo_url: null,
media_count: 10895,
},
{
source_name: "flickr",
display_name: "Flickr",
source_url: "https://www.flickr.com",
logo_url: null,
media_count: 505849755,
},
{
source_name: "met",
display_name: "Metropolitan Museum of Art",
source_url: "https://www.metmuseum.org",
logo_url: null,
media_count: 396650,
},
]

export const imageProviderNames = [
"smithsonian_african_american_history_museum",
"flickr",
"met",
]

export const AllCollectionsTemplate = (args) => ({
template: `
<div class="wrapper w-full p-2 flex flex-col gap-2 bg-dark-charcoal-06">
<VCollectionHeader v-for="collection in args.collections" :key="collection.collectionName" v-bind="collection" class="bg-white"/>
</div>`,
components: { VCollectionHeader },
setup() {
const providerStore = useProviderStore()
providerStore.$patch({
providers: { image: imageProviders },
sourceNames: { image: imageProviderNames },
})
const mediaStore = useMediaStore()
mediaStore.$patch({
results: { image: { count: 10000 } },
})
return { args }
},
})

export const collections = [
{
collectionName: "tag",
collection: "tag",
title: "cat",
resultsLabel: "10000 audio files with the selected tag",
collectionParams: {
collection: "tag",
tag: "cat",
},
mediaType: "image",
},
{
collectionName: "source",
collection: "source",
title: "Metropolitan Museum of Art",
url: "https://www.metmuseum.org/",
resultsLabel: "10000 images provided by this source",
collectionParams: {
collection: "source",
source: "met",
},
mediaType: "image",
},
{
collectionName: "creator",
collection: "creator",
title: "iocyoungreporters",
url: "https://www.flickr.com/photos/126018610@N05",
resultsLabel: "10000 images. iocyoungreporters, Flickr",
collectionParams: {
collection: "creator",
source: "flickr",
creator: "iocyoungreporters",
},
mediaType: "image",
creatorUrl: "https://www.flickr.com/photos/126018610@N05",
},
{
collectionName: "source-with-long-name",
collection: "source",
title:
"Smithsonian Institution: National Museum of African American History and Culture",
url: "https://nmaahc.si.edu",
resultsLabel: "10000 images provided by this source",
collectionParams: {
collection: "source",
source: "smithsonian_african_american_history_museum",
},
mediaType: "image",
},
]

Expand Down
73 changes: 65 additions & 8 deletions frontend/src/composables/use-i18n-utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { useGetLocaleFormattedNumber } from "~/composables/use-get-locale-format
import { useI18n } from "~/composables/use-i18n"
import type { SupportedMediaType, SupportedSearchType } from "~/constants/media"
import { ALL_MEDIA, AUDIO, IMAGE } from "~/constants/media"
import { Collection } from "~/types/search"

/**
* Not using dynamically-generated keys to ensure that
* correct line is shown in the 'po' locale files
*/
const i18nKeys = {
const searchResultKeys = {
[ALL_MEDIA]: {
noResult: "browsePage.allNoResults",
result: "browsePage.allResultCount",
Expand All @@ -24,6 +25,52 @@ const i18nKeys = {
more: "browsePage.contentLink.audio.countMore",
},
}
const collectionKeys = {
source: {
[IMAGE]: {
noResult: "collection.resultCountLabel.source.image.zero",
result: "collection.resultCountLabel.source.image.count",
more: "collection.resultCountLabel.source.image.countMore",
},
[AUDIO]: {
noResult: "collection.resultCountLabel.source.audio.zero",
result: "collection.resultCountLabel.source.audio.count",
more: "collection.resultCountLabel.source.audio.countMore",
},
},
creator: {
[IMAGE]: {
noResult: "collection.resultCountLabel.creator.image.zero",
result: "collection.resultCountLabel.creator.image.count",
more: "collection.resultCountLabel.creator.image.countMore",
},
[AUDIO]: {
noResult: "collection.resultCountLabel.creator.audio.zero",
result: "collection.resultCountLabel.creator.audio.count",
more: "collection.resultCountLabel.creator.audio.countMore",
},
},
tag: {
[IMAGE]: {
noResult: "collection.resultCountLabel.tag.image.zero",
result: "collection.resultCountLabel.tag.image.count",
more: "collection.resultCountLabel.tag.image.countMore",
},
[AUDIO]: {
noResult: "collection.resultCountLabel.tag.audio.zero",
result: "collection.resultCountLabel.tag.audio.count",
more: "collection.resultCountLabel.tag.audio.countMore",
},
},
}

function getCountKey(resultsCount: number) {
return resultsCount === 0
? "noResult"
: resultsCount >= 10000
? "more"
: "result"
}

/**
* Returns the localized text for the number of search results.
Expand All @@ -38,13 +85,8 @@ export function useI18nResultsCount() {
resultsCount: number,
searchType: SupportedSearchType
) => {
const countKey =
resultsCount === 0
? "noResult"
: resultsCount >= 10000
? "more"
: "result"
return i18nKeys[searchType][countKey]
const countKey = getCountKey(resultsCount)
return searchResultKeys[searchType][countKey]
}

/**
Expand All @@ -62,6 +104,20 @@ export function useI18nResultsCount() {
mediaType,
})
}
const getI18nCollectionResultCountLabel = (
resultCount: number,
mediaType: SupportedMediaType,
collectionType: Collection,
params: Record<string, string> | undefined = undefined
) => {
const key =
collectionKeys[collectionType][mediaType][getCountKey(resultCount)]
return i18n.tc(key, resultCount, {
localeCount: getLocaleFormattedNumber(resultCount),
...params,
})
}

/**
* Returns the localized text for the number of search results, using corresponding
* pluralization rules and decimal separators.
Expand All @@ -76,6 +132,7 @@ export function useI18nResultsCount() {
return {
getI18nCount,
getI18nContentLinkLabel,
getI18nCollectionResultCountLabel,
getLoading,
}
}
Loading