Skip to content

Commit

Permalink
Update the full audio layout on the single result page (#2933)
Browse files Browse the repository at this point in the history
* Add tests for additional search views single result page

* Add snapshots

* Add tapes for single result thumbnails

* Update snapshots

* Add wait for h1 to make sure that the page has navigated

* Update the full audio track

* Put updated single audio detail page changes behind flag

* Update snapshot

* Update xs VGetMediaButton and h1 styles

* Update xs snapshots

* Update pages single result pw test

* Revert tape changes

* Update snapshots (new tags)

* Refactor to make removing flag from template easier
  • Loading branch information
obulat authored Oct 19, 2023
1 parent 93b64b5 commit 0d95b62
Show file tree
Hide file tree
Showing 31 changed files with 170 additions and 79 deletions.
19 changes: 19 additions & 0 deletions frontend/src/components/VAudioTrack/VAudioTrack.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@
</template>

<template #play-pause="playPauseProps">
<VAudioControl
v-if="layout === 'full' && additionalSearchViews"
ref="playPauseRef"
size="medium"
:status="status"
v-bind="playPauseProps"
@toggle="handleToggle"
/>
<VPlayPause
v-else
ref="playPauseRef"
:status="status"
v-bind="playPauseProps"
Expand Down Expand Up @@ -71,6 +80,7 @@ import {
import { useActiveMediaStore } from "~/stores/active-media"
import { useMediaStore } from "~/stores/media"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import { AUDIO } from "~/constants/media"
import {
Expand All @@ -88,6 +98,7 @@ import { defineEvent } from "~/types/emits"
import type { AudioTrackClickEvent } from "~/types/events"
import VAudioControl from "~/components/VAudioTrack/VAudioControl.vue"
import VPlayPause from "~/components/VAudioTrack/VPlayPause.vue"
import VWaveform from "~/components/VAudioTrack/VWaveform.vue"
import VFullLayout from "~/components/VAudioTrack/layouts/VFullLayout.vue"
Expand All @@ -104,6 +115,7 @@ import VWarningSuppressor from "~/components/VWarningSuppressor.vue"
export default defineComponent({
name: "VAudioTrack",
components: {
VAudioControl,
VPlayPause,
VWaveform,
VLink,
Expand Down Expand Up @@ -571,6 +583,11 @@ export default defineComponent({
}
}
const featureFlagStore = useFeatureFlagStore()
const additionalSearchViews = computed(() =>
featureFlagStore.isOn("additional_search_views")
)
return {
status,
message,
Expand All @@ -597,6 +614,8 @@ export default defineComponent({
playPauseRef,
waveformRef,
additionalSearchViews,
}
},
})
Expand Down
81 changes: 49 additions & 32 deletions frontend/src/components/VAudioTrack/layouts/VFullLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,41 @@
</div>
</div>
<div
v-if="additionalSearchViews"
class="mx-auto grid grid-cols-1 grid-rows-[auto,auto] gap-6 p-6 pb-0 lg:mb-6 lg:max-w-5xl lg:flex-nowrap"
>
<div class="row-start-1 flex justify-between gap-x-6 sm:col-start-2">
<slot name="play-pause" size="medium" />
<VGetMediaButton
:media="audio"
media-type="audio"
class="col-start-2 !w-full px-0 sm:!w-auto sm:flex-shrink-0"
/>
</div>

<div
class="audio-info row-start-2 flex w-full flex-col justify-center sm:col-start-1 sm:row-start-1 lg:w-auto"
>
<h1 class="heading-6 lg:line-clamp-2">{{ audio.title }}</h1>
<div
class="subtitle mt-1 flex flex-col gap-2 text-base leading-snug lg:flex-row lg:items-center"
>
<i18n as="span" path="audioTrack.creator" class="font-semibold">
<template #creator>
<VLink
class="rounded-sm p-px focus-visible:outline-none focus-visible:ring focus-visible:ring-pink"
:href="audio.creator_url"
:send-external-link-click-event="false"
>
{{ audio.creator }}
</VLink>
</template>
</i18n>
</div>
</div>
</div>
<div
v-else
class="items-top mx-auto mt-6 flex flex-row flex-wrap gap-6 px-6 lg:max-w-5xl lg:flex-nowrap"
>
<slot name="play-pause" :size="isSmall ? 'small' : 'large'" />
Expand All @@ -40,31 +75,19 @@
</VLink>
</template>
</i18n>

<span
class="hidden text-dark-charcoal-70 lg:block"
aria-hidden="true"
>{{ $t("interpunct") }}</span
>

<div>{{ timeFmt(audio.duration || 0, true) }}</div>
</div>
</div>

<VButton
as="VLink"
:href="audio.foreign_landing_url"
size="large"
variant="filled-pink"
has-icon-end
show-external-icon
:external-icon-size="6"
class="description-bold order-1 my-1 ms-auto flex-shrink-0 lg:order-2"
:send-external-link-click-event="false"
@click="sendGetMediaEvent"
>
{{ $t("audioDetails.weblink") }}
</VButton>
<VGetMediaButton
media-type="audio"
:media="audio"
class="order-1 my-1 ms-auto flex-shrink-0 lg:order-2"
/>
</div>
</div>
</template>
Expand All @@ -75,15 +98,14 @@ import { computed, defineComponent, PropType } from "vue"
import type { AudioDetail } from "~/types/media"
import { timeFmt } from "~/utils/time-fmt"
import { AudioSize, AudioStatus, audioFeatures } from "~/constants/audio"
import { AUDIO } from "~/constants/media"
import { useAnalytics } from "~/composables/use-analytics"
import { useFeatureFlagStore } from "~/stores/feature-flag"
import VButton from "~/components/VButton.vue"
import VLink from "~/components/VLink.vue"
import VGetMediaButton from "~/components/VMediaInfo/VGetMediaButton.vue"
export default defineComponent({
name: "VFullLayout",
components: { VButton, VLink },
components: { VGetMediaButton, VLink },
props: {
audio: {
type: Object as PropType<AudioDetail>,
Expand All @@ -101,25 +123,20 @@ export default defineComponent({
},
},
setup(props) {
const { sendCustomEvent } = useAnalytics()
const isSmall = computed(() => props.size === "s")
const sendGetMediaEvent = () => {
sendCustomEvent("GET_MEDIA", {
id: props.audio.id,
provider: props.audio.provider,
mediaType: AUDIO,
})
}
const featureFlagStore = useFeatureFlagStore()
const additionalSearchViews = computed(() => {
return featureFlagStore.isOn("additional_search_views")
})
return {
timeFmt,
isSmall,
audioFeatures,
sendGetMediaEvent,
additionalSearchViews,
}
},
})
Expand Down
54 changes: 54 additions & 0 deletions frontend/src/components/VMediaInfo/VGetMediaButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<template>
<VButton
as="VLink"
:href="media.foreign_landing_url"
size="large"
variant="filled-pink"
has-icon-end
show-external-icon
:external-icon-size="6"
class="description-bold"
:send-external-link-click-event="false"
@click="sendGetMediaEvent"
>
{{ $t(`${mediaType}Details.weblink`) }}
</VButton>
</template>
<script lang="ts">
import { defineComponent, PropType } from "vue"
import { useAnalytics } from "~/composables/use-analytics"
import type { SupportedMediaType } from "~/constants/media"
import type { Media } from "~/types/media"
import VButton from "~/components/VButton.vue"
export default defineComponent({
name: "VGetMediaButton",
components: { VButton },
props: {
media: {
type: Object as PropType<Media>,
required: true,
},
mediaType: {
type: String as PropType<SupportedMediaType>,
required: true,
},
},
setup(props) {
const { sendCustomEvent } = useAnalytics()
const sendGetMediaEvent = () => {
sendCustomEvent("GET_MEDIA", {
id: props.media.id,
provider: props.media.provider,
mediaType: props.mediaType,
})
}
return {
sendGetMediaEvent,
}
},
})
</script>
2 changes: 2 additions & 0 deletions frontend/src/pages/audio/_id/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ import VMediaDetails from "~/components/VMediaInfo/VMediaDetails.vue"
import VSafetyWall from "~/components/VSafetyWall/VSafetyWall.vue"
import VSingleResultControls from "~/components/VSingleResultControls.vue"
import VAudioThumbnail from "~/components/VAudioThumbnail/VAudioThumbnail.vue"
import VErrorSection from "~/components/VErrorSection/VErrorSection.vue"
export default defineComponent({
name: "AudioDetailPage",
components: {
VErrorSection,
VAudioThumbnail,
VSingleResultControls,
VSafetyWall,
Expand Down
23 changes: 7 additions & 16 deletions frontend/src/pages/image/_id/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,11 @@
id="title-button"
class="flex flex-row flex-wrap justify-between gap-x-6 md:mt-6 md:flex-row-reverse"
>
<VButton
as="VLink"
:href="image.foreign_landing_url"
variant="filled-pink"
class="description-bold mb-4 !w-full flex-initial md:mb-0 md:!w-max"
show-external-icon
:external-icon-size="6"
has-icon-end
size="large"
:send-external-link-click-event="false"
@click="sendGetMediaEvent"
>
{{ $t("imageDetails.weblink") }}
</VButton>
<VGetMediaButton
:media="image"
media-type="image"
class="mb-4 !w-full flex-initial md:mb-0 md:!w-max"
/>
<div class="description-bold flex flex-1 flex-col justify-center">
<h1 class="description-bold md:heading-5 line-clamp-2">
{{ image.title }}
Expand Down Expand Up @@ -124,25 +115,25 @@ import { useSingleResultStore } from "~/stores/media/single-result"
import { singleResultMiddleware } from "~/middleware/single-result"
import VBone from "~/components/VSkeleton/VBone.vue"
import VButton from "~/components/VButton.vue"
import VLink from "~/components/VLink.vue"
import VMediaReuse from "~/components/VMediaInfo/VMediaReuse.vue"
import VRelatedImages from "~/components/VImageDetails/VRelatedImages.vue"
import VSketchFabViewer from "~/components/VSketchFabViewer.vue"
import VSafetyWall from "~/components/VSafetyWall/VSafetyWall.vue"
import VSingleResultControls from "~/components/VSingleResultControls.vue"
import VMediaDetails from "~/components/VMediaInfo/VMediaDetails.vue"
import VGetMediaButton from "~/components/VMediaInfo/VGetMediaButton.vue"
import errorImage from "~/assets/image_not_available_placeholder.png"
export default defineComponent({
name: "VImageDetailsPage",
components: {
VGetMediaButton,
VMediaDetails,
VSingleResultControls,
VSafetyWall,
VBone,
VButton,
VLink,
VMediaReuse,
VRelatedImages,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,53 @@ import {
openFirstResult,
pathWithDir,
preparePageForTests,
setCookies,
} from "~~/test/playwright/utils/navigation"

import { supportedMediaTypes } from "~/constants/media"

test.describe.configure({ mode: "parallel" })

for (const mediaType of supportedMediaTypes) {
for (const dir of languageDirections) {
breakpoints.describeEvery(({ breakpoint, expectSnapshot }) => {
test(`${mediaType} ${dir} single-result page snapshots from search results`, async ({
page,
}) => {
await preparePageForTests(page, breakpoint)
await page.route("**", (route) => {
const url = route.request().url()
// For audio, use the generated image instead of requesting the
// thumbnail.
if (
url.endsWith(".jpg") ||
(url.endsWith("/thumb/") && url.includes("/audio/"))
) {
route.abort()
} else {
route.continue()
}
})
for (const isOn of [true, false]) {
for (const mediaType of supportedMediaTypes) {
for (const dir of languageDirections) {
breakpoints.describeEvery(({ breakpoint, expectSnapshot }) => {
test(`${mediaType} ${dir} single-result page snapshots from search results, additional search views: ${isOn}`, async ({
page,
}) => {
await setCookies(page.context(), {
features: { additional_search_views: isOn ? "on" : "off" },
})
await preparePageForTests(page, breakpoint)
await page.route("**", (route) => {
const url = route.request().url()
// For audio, use the generated image instead of requesting the
// thumbnail.
if (
url.endsWith(".jpg") ||
(url.endsWith("/thumb/") && url.includes("/audio/"))
) {
route.abort()
} else {
route.continue()
}
})

await goToSearchTerm(page, "birds", { dir, mode: "SSR" })
await goToSearchTerm(page, "birds", { dir, mode: "SSR" })

// This will include the "Back to results" link.
await openFirstResult(page, mediaType)
await expectSnapshot(
`${mediaType}-${dir}-from-search-results`,
page,
{ fullPage: true },
{ maxDiffPixelRatio: 0.01 }
)
// This will include the "Back to results" link.
await openFirstResult(page, mediaType)
await expectSnapshot(
`${mediaType}-${dir}-from-search-results${
isOn ? "-with-additional-search-views" : ""
}`,
page,
{ fullPage: true },
{ maxDiffPixelRatio: 0.01 }
)
})
})
})
}
}
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 0d95b62

Please sign in to comment.