Skip to content

Commit

Permalink
Fix server rendering
Browse files Browse the repository at this point in the history
Signed-off-by: Olga Bulat <obulat@gmail.com>
  • Loading branch information
obulat committed Dec 2, 2023
1 parent aa4ae2b commit f1c64be
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 233 deletions.
35 changes: 33 additions & 2 deletions frontend/src/components/VCollectionPage.vue
Expand Up @@ -9,14 +9,14 @@
/>
<VAudioCollection
v-if="results.type === 'audio'"
collection-label="audio collection"
:collection-label="collectionLabel"
:fetch-state="fetchState"
kind="collection"
:results="results.items"
/>
<VImageGrid
v-if="results.type === 'image'"
image-grid-label="image collection"
:image-grid-label="collectionLabel"
:fetch-state="fetchState"
kind="collection"
:results="results.items"
Expand All @@ -32,6 +32,8 @@ import type { SupportedMediaType } from "~/constants/media"
import { Results } from "~/types/result"
import { useI18n } from "~/composables/use-i18n"
import VCollectionHeader from "~/components/VCollectionHeader/VCollectionHeader.vue"
import VAudioCollection from "~/components/VSearchResultsGrid/VAudioCollection.vue"
import VImageGrid from "~/components/VSearchResultsGrid/VImageGrid.vue"
Expand All @@ -46,6 +48,7 @@ export default defineComponent({
},
},
setup(props) {
const i18n = useI18n()
const mediaStore = useMediaStore()
const fetchState = computed(() => mediaStore.fetchState)
Expand All @@ -64,11 +67,39 @@ export default defineComponent({
const searchStore = useSearchStore()
const collectionParams = computed(() => searchStore.collectionParams)
const collectionLabel = computed(() => {
const collection = collectionParams.value?.collection
switch (collection) {
case "tag":
return i18n
.t(`collection.ariaLabel.tag.${props.mediaType}`, {
tag: collectionParams.value?.tag,
})
.toString()
case "source":
return i18n
.t(`collection.ariaLabel.source.${props.mediaType}`, {
source: collectionParams.value?.source,
})
.toString()
case "creator":
return i18n
.t(`collection.ariaLabel.creator.${props.mediaType}`, {
creator: collectionParams.value?.creator,
source: collectionParams.value?.source,
})
.toString()
default:
return ""
}
})
return {
fetchState,
results,
creatorUrl,
collectionParams,
collectionLabel,
}
},
})
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/locales/scripts/en.json5
Expand Up @@ -774,6 +774,20 @@
source: "Open source site",
creator: "Open creator page",
},
ariaLabel: {
creator: {
audio: "Audio files by {creator} in {source}",
image: "Images by {creator} in {source}",
},
source: {
audio: "Audio files from {source}",
image: "Images from {source}",
},
tag: {
audio: "Audio files with the tag {tag}",
image: "Images with the tag {tag}",
},
},
resultCountLabel: {
creator: {
audio: {
Expand Down
15 changes: 15 additions & 0 deletions frontend/src/middleware/collection.ts
@@ -0,0 +1,15 @@
import { useFeatureFlagStore } from "~/stores/feature-flag"

import type { Middleware } from "@nuxt/types"

export const collectionMiddleware: Middleware = async ({
$pinia,
error: nuxtError,
}) => {
if (!useFeatureFlagStore($pinia).isOn("additional_search_views")) {
nuxtError({
statusCode: 404,
message: "Additional search views are not enabled",
})
}
}
30 changes: 12 additions & 18 deletions frontend/src/pages/audio/source/_.vue
Expand Up @@ -3,41 +3,35 @@
</template>

<script lang="ts">
import { defineComponent, useFetch } from "@nuxtjs/composition-api"
import { defineComponent, useFetch, useRoute } from "@nuxtjs/composition-api"
import { useMediaStore } from "~/stores/media"
import { useSearchStore } from "~/stores/search"
import { validateCollectionParams } from "~/utils/validate-collection-params"
import { parseCollectionPath } from "~/utils/parse-collection-path"
import { AUDIO } from "~/constants/media"
import { collectionMiddleware } from "~/middleware/collection"
import VCollectionPage from "~/components/VCollectionPage.vue"
export default defineComponent({
name: "VAudioSourcePage",
components: { VCollectionPage },
layout: "content-layout",
/**
* Validate the dynamic path parameters and update the search store.
* Shows an error page if `validate` returns `false`.
*/
validate({ params, $pinia }): boolean {
const mediaType = AUDIO
const collectionParams = validateCollectionParams({
firstParam: "source",
mediaType,
params,
$pinia,
})
if (!collectionParams) return false
useSearchStore($pinia).setCollectionState(collectionParams, mediaType)
return true
},
middleware: collectionMiddleware,
setup() {
const route = useRoute()
const collectionParams = parseCollectionPath(route.value.params.pathMatch)
if (!collectionParams) {
throw new Error("Invalid collection path")
}
useSearchStore().setCollectionState(collectionParams, AUDIO)
const mediaStore = useMediaStore()
useFetch(async () => {
await mediaStore.fetchMedia()
})
return {}
},
})
</script>
30 changes: 12 additions & 18 deletions frontend/src/pages/audio/tag/_tag.vue
Expand Up @@ -3,41 +3,35 @@
</template>

<script lang="ts">
import { defineComponent, useFetch } from "@nuxtjs/composition-api"
import { defineComponent, useFetch, useRoute } from "@nuxtjs/composition-api"
import { useMediaStore } from "~/stores/media"
import { useSearchStore } from "~/stores/search"
import { validateCollectionParams } from "~/utils/validate-collection-params"
import { AUDIO } from "~/constants/media"
import type { TagCollection } from "~/types/search"
import { collectionMiddleware } from "~/middleware/collection"
import VCollectionPage from "~/components/VCollectionPage.vue"
export default defineComponent({
name: "VAudioTagPage",
components: { VCollectionPage },
layout: "content-layout",
/**
* Validate the dynamic path parameters and update the search store.
* Shows an error page if `validate` returns `false`.
*/
validate({ params, $pinia }): boolean {
const mediaType = AUDIO
const collectionParams = validateCollectionParams({
firstParam: "tag",
mediaType,
params,
$pinia,
})
if (!collectionParams) return false
useSearchStore($pinia).setCollectionState(collectionParams, mediaType)
return true
},
middleware: collectionMiddleware,
setup() {
const route = useRoute()
const collectionParams: TagCollection = {
tag: route.value.params.tag,
collection: "tag",
}
useSearchStore().setCollectionState(collectionParams, AUDIO)
const mediaStore = useMediaStore()
useFetch(async () => {
await mediaStore.fetchMedia()
})
return {}
},
})
</script>
29 changes: 11 additions & 18 deletions frontend/src/pages/image/source/_.vue
Expand Up @@ -3,41 +3,34 @@
</template>

<script lang="ts">
import { defineComponent, useFetch } from "@nuxtjs/composition-api"
import { defineComponent, useFetch, useRoute } from "@nuxtjs/composition-api"
import { useMediaStore } from "~/stores/media"
import { useSearchStore } from "~/stores/search"
import { validateCollectionParams } from "~/utils/validate-collection-params"
import { parseCollectionPath } from "~/utils/parse-collection-path"
import { IMAGE } from "~/constants/media"
import { collectionMiddleware } from "~/middleware/collection"
import VCollectionPage from "~/components/VCollectionPage.vue"
export default defineComponent({
name: "VImageSourcePage",
components: { VCollectionPage },
layout: "content-layout",
/**
* Validate the dynamic path parameters and update the search store.
* Shows an error page if `validate` returns `false`.
*/
validate({ params, $pinia }): boolean {
const mediaType = IMAGE
const collectionParams = validateCollectionParams({
firstParam: "source",
mediaType,
params,
$pinia,
})
if (!collectionParams) return false
useSearchStore($pinia).setCollectionState(collectionParams, mediaType)
return true
},
middleware: collectionMiddleware,
setup() {
const route = useRoute()
const collectionParams = parseCollectionPath(route.value.params.pathMatch)
if (!collectionParams) {
throw new Error("Invalid collection path")
}
useSearchStore().setCollectionState(collectionParams, IMAGE)
const mediaStore = useMediaStore()
useFetch(async () => {
await mediaStore.fetchMedia()
})
return {}
},
})
</script>
34 changes: 12 additions & 22 deletions frontend/src/pages/image/tag/_tag.vue
Expand Up @@ -3,45 +3,35 @@
</template>

<script lang="ts">
import { defineComponent, useFetch } from "@nuxtjs/composition-api"
import { defineComponent, useFetch, useRoute } from "@nuxtjs/composition-api"
import { useMediaStore } from "~/stores/media"
import { useSearchStore } from "~/stores/search"
import { validateCollectionParams } from "~/utils/validate-collection-params"
import { IMAGE } from "~/constants/media"
import { collectionMiddleware } from "~/middleware/collection"
import type { TagCollection } from "~/types/search"
import VCollectionPage from "~/components/VCollectionPage.vue"
export default defineComponent({
name: "VImageTagPage",
components: { VCollectionPage },
layout: "content-layout",
/**
* Validate the dynamic path parameters.
*
* Shows an error page if `validate` returns `false`.
*
* @param params - the path parameters: `mediaType`, `collection` and `pathMatch` for the rest.
* @param $pinia - passed to update the store with the validated data.
*/
validate({ params, $pinia }): boolean {
const mediaType = IMAGE
const collectionParams = validateCollectionParams({
firstParam: "tag",
mediaType,
params,
$pinia,
})
if (!collectionParams) return false
useSearchStore($pinia).setCollectionState(collectionParams, mediaType)
return true
},
middleware: collectionMiddleware,
setup() {
const route = useRoute()
const collectionParams: TagCollection = {
tag: route.value.params.tag,
collection: "tag",
}
useSearchStore().setCollectionState(collectionParams, IMAGE)
const mediaStore = useMediaStore()
useFetch(async () => {
await mediaStore.fetchMedia()
})
return {}
},
})
</script>
24 changes: 24 additions & 0 deletions frontend/src/utils/parse-collection-path.ts
@@ -0,0 +1,24 @@
import { CreatorCollection, SourceCollection } from "~/types/search"

export function parseCollectionPath(
pathMatch: string
): SourceCollection | CreatorCollection | null {
// Build collection params.
// pathMatch is the part of the path after the collection name:
//`/sourceName` or `/sourceName/creator/creatorName`.
const pathMatchParts = pathMatch
.split("/")
.map((part) => part.trim())
.filter((part) => part !== "")

if (pathMatchParts.length === 1) {
return { collection: "source", source: pathMatchParts[0] }
} else if (pathMatchParts.length === 3 && pathMatchParts[1] === "creator") {
return {
collection: "creator",
creator: pathMatchParts[2],
source: pathMatchParts[0],
}
}
return null
}

0 comments on commit f1c64be

Please sign in to comment.