Skip to content

Commit

Permalink
Add VByLine under the feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat committed Oct 7, 2023
1 parent 26491cc commit e5c7d26
Show file tree
Hide file tree
Showing 2 changed files with 288 additions and 0 deletions.
210 changes: 210 additions & 0 deletions frontend/src/components/VMediaInfo/VByLine/VByLine.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
<template>
<div
ref="containerRef"
class="relative flex max-w-full sm:-ms-1"
:class="buttonsMargin"
>
<div
class="buttons-container max-w-full"
:class="{ [`m${scrollButtonPosition}-10`]: shouldScroll }"
>
<div
ref="buttonsRef"
class="buttons flex justify-start gap-x-3 overflow-x-scroll sm:gap-x-1"
:class="{ [`faded-overflow-${scrollButtonPosition}`]: shouldScroll }"
>
<VButton
v-if="showCreator"
as="VLink"
size="small"
has-icon-start
class="label-bold"
:variant="buttonVariant"
:href="
getCollectionPath({ type: mediaType, source: sourceSlug, creator })
"
>
<VIcon name="person" /><span class="w-max">{{ creator }}</span>
</VButton>
<VButton
as="VLink"
size="small"
has-icon-start
class="label-bold"
:variant="buttonVariant"
:href="getCollectionPath({ type: mediaType, source: sourceSlug })"
><VIcon name="institution" /><span class="w-max">{{
sourceName
}}</span>
</VButton>
</div>
</div>
<div
v-if="shouldScroll"
class="absolute z-10 h-8 w-8 bg-white"
:class="scrollButton.style"
>
<VIconButton
:icon-props="{ name: scrollButton.icon, rtlFlip: true }"
label="scroll"
variant="transparent-gray"
size="small"
@click="scroll"
/>
</div>
</div>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, ref } from "vue"
import { useElementSize, useScroll, watchDebounced } from "@vueuse/core"
import { useUiStore } from "~/stores/ui"
import { useI18n } from "~/composables/use-i18n"
import type { SupportedMediaType } from "~/constants/media"
import VButton from "~/components/VButton.vue"
import VIcon from "~/components/VIcon/VIcon.vue"
import VIconButton from "~/components/VIconButton/VIconButton.vue"
/**
* A link to a collection page, either a source or a creator.
*/
export default defineComponent({
name: "VByLine",
components: { VIconButton, VIcon, VButton },
props: {
creator: {
type: String,
},
sourceName: {
type: String,
required: true,
},
sourceSlug: {
type: String,
required: true,
},
mediaType: {
type: String as PropType<SupportedMediaType>,
required: true,
},
},
setup(props) {
const containerRef = ref<HTMLElement | null>(null)
const buttonsRef = ref<HTMLElement | null>(null)
const uiStore = useUiStore()
const buttonVariant = computed(() =>
uiStore.isBreakpoint("sm") ? "transparent-gray" : "filled-gray"
)
const showCreator = computed(() => {
return props.creator && props.creator !== "Unidentified"
})
const shouldScroll = ref(false)
const { x } = useScroll(buttonsRef)
const { width: containerWidth } = useElementSize(containerRef)
const { width: buttonsWidth } = useElementSize(buttonsRef)
watchDebounced(
[buttonsWidth, containerWidth],
() => {
shouldScroll.value = buttonsWidth.value >= containerWidth.value
},
{ debounce: 500 }
)
const i18n = useI18n()
const dir = computed(() => i18n.localeProperties.dir ?? "ltr")
// end, start
const scrollButtonPosition = ref<"e" | "s">("e")
const scroll = () => {
let scrollValue = x.value ? 0 : buttonsWidth.value
if (dir.value === "rtl") {
scrollValue = -scrollValue
}
buttonsRef.value?.scroll({
left: scrollValue,
behavior: "smooth",
})
scrollButtonPosition.value =
scrollButtonPosition.value === "e" ? "s" : "e"
}
watchDebounced(
x,
(xValue) => {
const distFromStart = Math.abs(xValue)
const distFromEnd =
(buttonsRef.value?.scrollWidth ?? 0) -
distFromStart -
containerWidth.value
if (distFromEnd < 1) {
scrollButtonPosition.value = "s"
} else if (distFromStart < 1) scrollButtonPosition.value = "e"
},
{ debounce: 100 }
)
const buttonsMargin = computed(() => {
return shouldScroll.value ? `p${scrollButtonPosition.value}-8` : ""
})
const scrollButton = computed(() => {
if (scrollButtonPosition.value === "e") {
return { style: "end-0 ms-2", icon: "chevron-forward" }
} else {
return { style: "start-0 me-2", icon: "chevron-back" }
}
})
// TODO: implement this function in the search store.
const getCollectionPath = ({
type,
source,
creator,
}: {
type: SupportedMediaType
source: string
creator?: string
}) => {
console.log(type, source, creator)
return "/"
}
return {
buttonVariant,
showCreator,
containerRef,
buttonsRef,
buttonsMargin,
scroll,
shouldScroll,
scrollButton,
scrollButtonPosition,
getCollectionPath,
}
},
})
</script>

<style scoped>
.faded-overflow-e:dir(ltr),
.faded-overflow-s:dir(rtl) {
mask-image: linear-gradient(to left, transparent, white 20%);
}
.faded-overflow-e:dir(rtl),
.faded-overflow-s:dir(ltr) {
mask-image: linear-gradient(to right, transparent, white 20%);
}
.buttons::-webkit-scrollbar {
width: 0 !important;
}
.buttons {
scrollbar-width: none;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
ArgsTable,
Canvas,
Description,
Meta,
Story,
} from "@storybook/addon-docs"
import { supportedMediaTypes } from "~/constants/media"
import { useProviderStore } from "~/stores/provider"

import VByLine from "~/components/VMediaInfo/VByLine/VByLine.vue"

export const Template = (args) => ({
template: `<div class="wrapper w-full inline-flex p-4"><VByLine v-bind="args" /></div>`,
components: { VByLine },
setup() {
const providerStore = useProviderStore()
providerStore.getProviders().then(/** */)
return { args }
},
})

<Meta
title="Components/VByLine"
component={VByLine}
argTypes={{
mediaType: {
control: "select",
options: supportedMediaTypes,
},
creator: {
control: "text",
},
sourceName: {
control: "text",
},
sourceSlug: {
control: "text",
},
}}
/>

# VByLine

<Description of={VByLine} />

<ArgsTable of={VByLine} />

<Canvas>
<Story
name="default"
args={{
mediaType: "image",
creator: "kellascat",
sourceSlug: "met",
sourceName: "Metropolitan Museum",
}}
>
{Template.bind({})}
</Story>
</Canvas>

## Long titles use scrolling

<Canvas>
<Story
name="long"
args={{
mediaType: "image",
creator: "Roland Folger Coffin, American, 1826–1888",
sourceSlug: "smithsonian_cooper_hewitt_museum",
sourceName:
"Smithsonian Institution: Cooper Hewitt, Smithsonian Design Museum",
}}
>
{Template.bind({})}
</Story>
</Canvas>

0 comments on commit e5c7d26

Please sign in to comment.