Skip to content

Commit

Permalink
Use a modal for license explanation
Browse files Browse the repository at this point in the history
Signed-off-by: Olga Bulat <[email protected]>
  • Loading branch information
obulat committed Aug 22, 2024
1 parent 53c9bfe commit ac27177
Show file tree
Hide file tree
Showing 23 changed files with 173 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const close = () => {

<template>
<VModal
id="content-report"
ref="modalRef"
:label="$t('mediaDetails.contentReport.long')"
:hide-on-click-outside="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const handleSelect = (searchType: SearchType) => {

<template>
<VPopover
id="search-type-popover"
ref="contentMenuPopover"
:label="$t('searchType.label')"
placement="bottom-end"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const isMd = computed(() => uiStore.isBreakpoint("md"))
data-testid="external-sources-form"
>
<VModal
id="external-search-form"
variant="centered"
:hide-on-click-outside="true"
labelled-by="external-sources-button"
Expand Down
49 changes: 30 additions & 19 deletions frontend/src/components/VFilters/VFilterChecklist.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ import { useI18n } from "#imports"
import { useSearchStore } from "~/stores/search"
import type { FilterItem, FilterCategory } from "~/constants/filters"
import type { License } from "~/constants/license"
import { getElements } from "~/utils/license"
import VButton from "~/components/VButton.vue"
import VCheckbox from "~/components/VCheckbox/VCheckbox.vue"
import VIcon from "~/components/VIcon/VIcon.vue"
import VIconButton from "~/components/VIconButton/VIconButton.vue"
import VLicense from "~/components/VLicense/VLicense.vue"
import VLicenseExplanation from "~/components/VFilters/VLicenseExplanation.vue"
import VPopover from "~/components/VPopover/VPopover.vue"
import VIconButton from "~/components/VIconButton/VIconButton.vue"
type toggleFilterPayload = {
filterType: FilterCategory
Expand Down Expand Up @@ -69,6 +67,14 @@ const isLicense = (code: string): code is License => {
// Quick check that also prevents "`code` is declared but its value is never read" warning.
return !!code && props.filterType === "licenses"
}
const getTitle = (code: string) => {
return isLicense(code)
? t("filters.licenseExplanation.licenseDefinition")
: t("filters.licenseExplanation.markDefinition", {
mark: code.toUpperCase(),
})
}
</script>

<template>
Expand All @@ -93,11 +99,12 @@ const isLicense = (code: string): code is License => {
</VCheckbox>

<!-- License explanation -->
<VPopover
<VModal
v-if="isLicense(item.code)"
strategy="fixed"
:id="item.code"
variant="centered"
:hide-on-click-outside="true"
:label="$t('browsePage.aria.licenseExplanation')"
:trap-focus="false"
>
<template #trigger="{ a11yProps }">
<VButton
Expand All @@ -110,20 +117,24 @@ const isLicense = (code: string): code is License => {
<VIcon name="help" />
</VButton>
</template>
<template #default="{ close }">
<div class="relative">
<VIconButton
:label="getLicenseExplanationCloseAria(item.code)"
:icon-props="{ name: 'close' }"
variant="transparent-gray"
size="small"
class="!absolute end-1 top-1"
@click="close"
/>
<VLicenseExplanation :license="item.code" />
</div>
<template #title>
<h5 class="text-base font-semibold">
{{ getTitle(item.code) }}
</h5>
</template>
<template #close-button="{ close }">
<VIconButton
:label="getLicenseExplanationCloseAria"
:icon-props="{ name: 'close' }"
variant="transparent-gray"
size="small"
@click="close"
/>
</template>
<template #default>
<VLicenseExplanation :license="item.code" />
</template>
</VPopover>
</VModal>
</div>
</fieldset>
</template>
22 changes: 4 additions & 18 deletions frontend/src/components/VFilters/VLicenseExplanation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,10 @@ defineProps<{
</script>

<template>
<div class="license-explanation w-70 max-w-xs p-6">
<h5 class="text-base font-semibold">
<template v-if="isLicense(license)">{{
$t("filters.licenseExplanation.licenseDefinition")
}}</template>
<template v-else>{{
$t("filters.licenseExplanation.markDefinition", {
mark: license.toUpperCase(),
})
}}</template>
</h5>

<VLicenseElements
v-if="license"
size="small"
class="my-4"
:license="license"
/>
<div
class="license-explanation flex flex-col gap-y-4 p-6 pt-0 sm:p-9 sm:pt-0"
>
<VLicenseElements v-if="license" size="small" :license="license" />

<i18n-t
scope="global"
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/components/VHeader/VHeaderDesktop.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<script setup lang="ts">
/**
* The desktop search header.
*/
import { useNuxtApp } from "#imports"
import { computed, inject, ref } from "vue"
Expand All @@ -22,10 +25,6 @@ import VSearchTypePopover from "~/components/VContentSwitcher/VSearchTypePopover
import type { Ref } from "vue"
/**
* The desktop search header.
*/
const filterButtonRef = ref<InstanceType<typeof VFilterButton> | null>(null)
const searchBarRef = ref<InstanceType<typeof VSearchBar> | null>(null)
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/VHeader/VHeaderInternal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const {
onTriggerClick: internalOnTriggerClick,
triggerA11yProps,
} = useDialogControl({
id: "pages-menu",
visibleRef: isModalVisible,
nodeRef,
lockBodyScroll,
Expand Down Expand Up @@ -105,6 +106,7 @@ watch(route, () => {
<template v-if="triggerElement">
<VPopoverContent
v-if="isSm"
id="pages-menu"
z-index="popover"
:hide="closePageMenu"
:visible="isModalVisible"
Expand All @@ -121,6 +123,7 @@ watch(route, () => {
</VPopoverContent>
<VModalContent
v-else-if="!isSm"
id="pages-menu"
ref="modalContentRef"
aria-labelledby="menu-button"
:hide="closePageMenu"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ const props = withDefaults(
}
)
defineEmits<{
select: [SearchType]
}>()
defineEmits<{ select: [SearchType] }>()
const searchStore = useSearchStore()
const content = useSearchType()
Expand All @@ -66,10 +64,13 @@ const searchType = computed(() => content.getSearchTypeProps())
const clearFilters = () => {
searchStore.clearFilters()
}
const id = "content-settings-modal"
defineExpose({ id })
</script>

<template>
<VModalContent
:id="id"
:aria-label="$t('header.aria.menu')"
:hide-on-click-outside="true"
:hide="close"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,17 @@ const emit = defineEmits<{
close: []
}>() as SetupContext["emit"]
const contentSettingsRef = ref<
InstanceType<typeof VContentSettingsModalContent> | undefined
>()
const contentSettingsId = computed(() => contentSettingsRef.value?.id)
const {
close: closeContentSettings,
onTriggerClick: toggleContentSettings,
triggerA11yProps,
} = useDialogControl({
id: contentSettingsId,
visibleRef: contentSettingsOpen,
nodeRef: headerRef,
lockBodyScroll: true,
Expand Down Expand Up @@ -342,6 +348,7 @@ const handleTab = (
@keydown.tab.exact="handleTab($event, 'content-settings')"
/>
<VContentSettingsModalContent
ref="contentSettingsRef"
variant="two-thirds"
:visible="contentSettingsOpen"
:is-fetching="isFetching"
Expand All @@ -352,6 +359,7 @@ const handleTab = (
</form>
<VModalContent
v-if="isRecentVisible"
id="recent-searches"
:visible="true"
:hide="deactivate"
:trigger-element="searchInputRef"
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/VHomepageContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ const handleSelect = (searchType: SearchType) => {
closeContentSwitcher()
}
const contentSwitcherId = "homepage-content-switcher"
const {
close: closeContentSwitcher,
open: openContentSwitcher,
onTriggerClick,
triggerA11yProps,
} = useDialogControl({
id: contentSwitcherId,
visibleRef: isContentSwitcherVisible,
nodeRef,
lockBodyScroll,
Expand Down Expand Up @@ -108,6 +110,7 @@ const {
<template v-if="triggerElement">
<VPopoverContent
v-if="isLg"
:id="contentSwitcherId"
z-index="popover"
:hide="closeContentSwitcher"
:trap-focus="false"
Expand All @@ -124,6 +127,7 @@ const {

<VContentSettingsModalContent
v-else
:id="contentSwitcherId"
aria-labelledby="search-type-button"
:close="closeContentSwitcher"
:visible="isContentSwitcherVisible"
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/VLicense/VLicenseElements.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ const getLicenseDescription = (element: string) => {
</script>

<template>
<ul>
<ul class="flex flex-col gap-y-2 md:gap-y-4">
<li
v-for="element in elementNames"
:key="element"
class="mb-2 flex items-center gap-3 text-sm md:mb-4 md:text-base"
class="flex items-center gap-x-3 text-sm md:text-base"
>
<VIcon
view-box="0 0 30 30"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/VMediaInfo/VMediaLicense.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const sendVisitLicensePage = () => {
</script>

<template>
<div class="media-attribution">
<div class="media-attribution mb-2 md:mb-0">
<h3 class="description-bold md:heading-6 mb-4">
{{ headerText }}
</h3>
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/components/VModal/VModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import VModalContent from "~/components/VModal/VModalContent.vue"
* NB: Most of these technically default to `undefined` so that the underlying `VModalContent`
* default for each of them can take over.
*/
withDefaults(
const props = withDefaults(
defineProps<{
/**
* Whether the popover should hide when the <kbd>Escape</kbd> key is pressed.
Expand Down Expand Up @@ -81,6 +81,11 @@ withDefaults(
*/
mode?: ModalColorMode
modalContentClasses?: string
/**
* The id used to keep track of the modal in the open modal stack, to enable
* nested modals.
*/
id: string
}>(),
{
hideOnEsc: true,
Expand Down Expand Up @@ -123,6 +128,7 @@ const {
triggerA11yProps,
visible: visibleRef,
} = useDialogControl({
id: props.id,
lockBodyScroll: true,
nodeRef,
emit: emit as SetupContext["emit"],
Expand Down Expand Up @@ -152,6 +158,7 @@ defineExpose({
</div>
<VModalContent
v-if="triggerRef"
:id="id"
ref="modalContentRef"
:visible="visibleRef"
:trigger-element="triggerRef"
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/VModal/VModalContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ defineOptions({
const props = withDefaults(
defineProps<{
id: string
visible: boolean
hide: () => void
hideOnEsc?: boolean
Expand Down Expand Up @@ -64,6 +65,7 @@ const initialFocusElement = computed(
)
const dialogRef = ref<HTMLElement | null>(null)
const { onKeyDown, onBlur, deactivateFocusTrap } = useDialogContent({
id: propsRefs.id,
dialogElements: {
dialogRef,
initialFocusElementRef: initialFocusElement,
Expand Down Expand Up @@ -97,6 +99,7 @@ defineExpose({
<Teleport to="#teleports">
<div
v-show="visible"
:id="id"
class="backdrop h-dyn-screen min-h-dyn-screen fixed inset-0 z-40 flex justify-center overflow-y-auto"
:class="[
{ 'flex-col items-center': variant === 'centered' },
Expand All @@ -121,7 +124,7 @@ defineExpose({
variant === 'two-thirds',
'mt-auto w-full rounded-se-lg rounded-ss-lg bg-overlay':
variant === 'fit-content',
'm-6 max-w-90 rounded sm:m-0': variant === 'centered',
'm-6 max-w-90 rounded sm:m-0 sm:w-90': variant === 'centered',
},
]"
role="dialog"
Expand Down Expand Up @@ -154,7 +157,7 @@ defineExpose({
class="flex items-center justify-between p-5 ps-7 sm:p-7 sm:ps-9"
>
<slot name="title" />
<slot name="close-button">
<slot name="close-button" :close="handleClose">
<VIconButton
:label="$t('modal.close')"
:icon-props="{ name: 'close' }"
Expand Down
Loading

0 comments on commit ac27177

Please sign in to comment.