Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Update footer to match new mockups #2015

Merged
merged 10 commits into from
Dec 14, 2022
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
144 changes: 81 additions & 63 deletions src/components/VFooter/VFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,29 @@
<footer
ref="footerEl"
class="footer flex flex-col gap-10 px-6 py-10"
:class="variantNames"
:class="[
...variantNames,
isContentMode ? 'footer-content' : 'footer-internal',
]"
>
<!-- Logo and links -->
<div v-if="isContentMode" class="logo-and-links flex flex-col gap-10">
<VLink href="/" class="text-dark-charcoal">
<div v-if="isContentMode" class="logo-and-links flex flex-col gap-y-10">
<VLink href="/" class="logo text-dark-charcoal">
<VBrand class="text-[18px]" />
</VLink>
<nav>
<ul class="nav-list grid grid-cols-2 gap-6 text-sm">
<li v-for="page in allPages" :key="page.id">
<VLink
class="text-dark-charcoal"
:href="page.link"
show-external-icon
>{{ $t(page.name) }}</VLink
>
</li>
</ul>
<VPageLinks
class="nav-list label-regular"
:style="linkColumnHeight"
nav-link-classes="py-2"
/>
</nav>
</div>

<!-- Locale chooser and WordPress affiliation graphic -->
<div class="locale-and-wp flex flex-col justify-between gap-10">
<div class="locale-and-wp flex flex-col justify-between gap-y-10">
<VLanguageSelect v-bind="languageProps" class="language max-w-full" />
<VLink
href="https://wordpress.org"
class="text-dark-charcoal hover:no-underline"
>
<i18n
tag="div"
path="footer.wordpress-affiliation"
class="flex h-full flex-row items-center gap-2 text-sm"
>
<template #wordpress>
<WordPress class="aria-hidden" />
<span class="sr-only">WordPress</span>
</template>
</i18n>
</VLink>
<VWordPressLink mode="light" />
</div>
</footer>
</template>
Expand All @@ -53,20 +37,21 @@ import {
ref,
} from '@nuxtjs/composition-api'

import usePages from '~/composables/use-pages'
import { CSSProperties } from '@vue/runtime-dom'

import usePages from '~/composables/use-pages'
import useResizeObserver from '~/composables/use-resize-observer'

import { SCREEN_SIZES } from '~/constants/screens'

import type { SelectFieldProps } from '~/components/VSelectField/VSelectField.vue'
import { useUiStore } from '~/stores/ui'

import type { SelectFieldProps } from '~/components/VSelectField/VSelectField.vue'
import VLink from '~/components/VLink.vue'
import VBrand from '~/components/VBrand/VBrand.vue'

import VLanguageSelect from '~/components/VLanguageSelect/VLanguageSelect.vue'

import WordPress from '~/assets/wordpress.svg?inline'
import VPageLinks from '~/components/VHeader/VPageLinks.vue'
import VWordPressLink from '~/components/VHeader/VWordPressLink.vue'

/**
* The footer is the section displayed at the bottom of a page. It can contain
Expand All @@ -75,10 +60,11 @@ import WordPress from '~/assets/wordpress.svg?inline'
export default defineComponent({
name: 'VFooter',
components: {
VWordPressLink,
VPageLinks,
VLanguageSelect,
VLink,
VBrand,
WordPress,
},
props: {
/**
Expand All @@ -89,76 +75,108 @@ export default defineComponent({
mode: {
type: String as PropType<'internal' | 'content'>,
required: false,
default: undefined,
},
languageProps: {
type: Object as PropType<SelectFieldProps>,
default: () => ({}),
},
},
setup(props) {
const uiStore = useUiStore()
const { all: allPages, current: currentPage } = usePages(true)

const isContentMode = computed(() => {
if (props.mode) {
return props.mode === 'content'
} else {
return ['search', 'audio', 'image'].some((prefix) =>
currentPage.value?.startsWith(prefix)
)
}
})
const isContentMode = computed(() => props.mode === 'content')
zackkrida marked this conversation as resolved.
Show resolved Hide resolved

/** JS-based responsiveness */
const footerEl = ref<HTMLElement | null>(null)
const { dimens: footerDimens } = useResizeObserver(footerEl)
const initialWidth = SCREEN_SIZES[uiStore.breakpoint]
const { dimens: footerDimens } = useResizeObserver(footerEl, {
initialWidth,
})

/**
* Return a list of all breakpoints that are smaller than the current screen width. This allows us to use the smallest variant class to target CSS styles.
*
* I.e., with a width at 1200, the footer will have `footer-2xl footer-lg`. Using `footer-lg`, we can apply styles to both `footer-2xl` and `footer-lg`.
*/
const variantNames = computed(() =>
Object.entries(SCREEN_SIZES)
.filter(([, val]) => footerDimens.value.width >= val)
.map(([key]) => `footer-${key}`)
)

const linkColumnHeight = computed<CSSProperties>(() => ({
'--link-col-height': Math.ceil(Object.keys(allPages).length / 2),
}))

return {
isContentMode,
allPages,
currentPage,

footerEl,
variantNames,
linkColumnHeight,
}
},
})
</script>

<style>
.footer.footer-sm .nav-list {
@apply flex flex-row gap-8;
/* wrapper element styles */
.footer-sm {
@apply px-6;
}

.footer.footer-sm .locale-and-wp {
@apply flex-row;
.footer-lg {
@apply gap-y-8 px-10;
}
.footer-internal {
@apply pt-6;
}
.footer-internal.footer-lg {
@apply pt-10;
}

.footer.footer-sm .language {
@apply max-w-[12.5rem];
/* footer > logo-and-links styles */
.footer-sm .logo-and-links {
@apply grid grid-flow-col grid-cols-2;
}

.footer.footer-md .logo-and-links {
@apply flex-row items-center justify-between;
.footer-lg .logo-and-links {
@apply flex flex-row items-center justify-between;
}

.footer.footer-lg {
@apply px-10;
/* logo-and-links > nav-list styles */

.nav-list {
@apply grid grid-flow-col grid-cols-2 items-center gap-y-2 gap-x-10;
/*
We set the number of rows in JS to have 2 equally distributed link columns.
*/
grid-template-rows: repeat(var(--link-col-height, 3), auto);
}

.footer.footer-xl {
@apply flex-row gap-8;
.footer-lg .nav-list {
@apply flex gap-x-6;
}

.footer.footer-xl .logo-and-links {
@apply flex-grow;
/* locale-and-wp locale chooser and WordPress affiliation graphic styles */
.footer-content.footer-sm .locale-and-wp {
@apply grid grid-cols-2 items-center;
}
.footer-content.footer-lg .locale-and-wp,
.footer-internal.footer-sm .locale-and-wp {
@apply flex flex-row items-center justify-between;
}

.footer.footer-xl .locale-and-wp {
@apply flex-grow;
/* element styles */
.footer-sm .logo {
@apply self-start pt-2;
}
.footer .language {
width: 100% !important;
}
.footer-sm .language {
@apply max-w-[12.5rem];
}
</style>
46 changes: 25 additions & 21 deletions src/components/VHeader/VHeaderInternal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
class="main-header z-30 flex h-20 w-full items-stretch justify-between gap-x-2 bg-white py-4 pe-3 ps-6 md:py-4 md:px-7"
>
<VHomeLink variant="dark" />
<nav class="justify-stretch md:justify-stretch hidden ms-auto md:flex">
<VPageLinks mode="dark" variant="inline" @close="closeModal" />
<nav class="md:justify-stretch hidden ms-auto md:flex">
<VPageLinks
mode="light"
class="md:justify-stretch flex hidden flex-row items-center gap-8 text-sm ms-auto md:flex"
nav-link-classes="ps-3"
@close="closeModal"
/>
</nav>
<div class="flex md:hidden">
<VModal
Expand Down Expand Up @@ -40,22 +45,15 @@
</div>
</template>
<template #default>
<VPageLinks mode="light" variant="column" @close="closeModal" />
<VLink
href="https://wordpress.org"
class="text-white hover:no-underline focus-visible:rounded-sm focus-visible:outline-none focus-visible:ring focus-visible:ring-pink focus-visible:ring-offset-1 focus-visible:ring-offset-tx"
>
<i18n
tag="p"
path="footer.wordpress-affiliation"
class="mt-auto flex flex-row items-center text-sm"
>
<template #wordpress>
<WordPress class="aria-hidden text-white" />
<span class="sr-only">WordPress</span>
</template>
</i18n>
</VLink>
<nav>
<VPageLinks
mode="dark"
class="mt-3 flex flex-col items-end gap-y-2"
nav-link-classes="heading-5 py-3"
@close="closeModal"
/>
</nav>
<VWordPressLink class="mt-auto" mode="dark" />
</template>
</VModal>
</div>
Expand All @@ -77,17 +75,23 @@ import { useUiStore } from '~/stores/ui'

import VHomeLink from '~/components/VHeader/VHomeLink.vue'
import VIconButton from '~/components/VIconButton/VIconButton.vue'
import VLink from '~/components/VLink.vue'
import VPageLinks from '~/components/VHeader/VPageLinks.vue'
import VModal from '~/components/VModal/VModal.vue'

import VWordPressLink from '~/components/VHeader/VWordPressLink.vue'

import closeIcon from '~/assets/icons/close.svg'
import menuIcon from '~/assets/icons/menu.svg'
import WordPress from '~/assets/wordpress.svg?inline'

export default defineComponent({
name: 'VHeaderInternal',
components: { VHomeLink, VIconButton, VLink, VModal, VPageLinks, WordPress },
components: {
VWordPressLink,
VHomeLink,
VIconButton,
VModal,
VPageLinks,
},
setup() {
const menuButtonRef = ref<InstanceType<typeof VIconButton> | null>(null)

Expand Down
51 changes: 19 additions & 32 deletions src/components/VHeader/VPageLinks.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,19 @@
<template>
<ul
class="flex"
:class="[
mode === 'dark' ? 'text-dark-charcoal' : 'bg-dark-charcoal text-white',
variant === 'inline'
? 'flex-row items-center gap-8 text-sm'
: 'mt-3 flex-col items-end',
]"
:class="
mode === 'light' ? 'text-dark-charcoal' : 'bg-dark-charcoal text-white'
"
>
<li
<VNavLink
v-for="page in allPages"
:key="page.id"
:class="{ 'heading-5': variant === 'column' }"
:link="page.link"
:mode="mode"
:is-active="currentPage === page.id"
:class="navLinkClasses"
@click="onClick(page.link)"
>{{ $t(page.name) }}</VNavLink
>
<VLink
class="rounded-sm py-3 focus-visible:outline-none focus-visible:ring focus-visible:ring-pink focus-visible:ring-offset-1 focus-visible:ring-offset-tx"
:class="[
{ 'font-bold': currentPage === page.id },
mode === 'dark' ? 'text-dark-charcoal' : 'text-white',
variant === 'inline' ? '' : 'ps-3',
]"
:href="page.link"
show-external-icon
@click="onClick(page.link)"
>{{ $t(page.name) }}</VLink
>
</li>
</ul>
</template>

Expand All @@ -38,17 +26,17 @@ import {

import usePages from '~/composables/use-pages'

import VLink from '~/components/VLink.vue'
import VNavLink from '~/components/VNavLink/VNavLink.vue'

export default defineComponent({
name: 'VPageLinks',
components: {
VLink,
VNavLink,
},
props: {
/**
* In `light` mode, the links are white and the background is dark charcoal.
* In `dark` mode (in the modal), the links are dark charcoal and the background is transparent.
* In `dark` mode (in the modal), the links are white and the background is dark charcoal.
* In `light` mode, the links are dark charcoal and the background is transparent.
*
* @default 'light'
*/
Expand All @@ -57,14 +45,13 @@ export default defineComponent({
default: 'light',
},
/**
* In `inline` mode, the links are displayed horizontally. It is used in the desktop header.
* In `column` mode, the links are displayed vertically. It is used in the mobile modal.
* Pass the tailwind classes to style the nav links.
*
* @default 'inline'
* @default ''
*/
variant: {
type: String as PropType<'inline' | 'column'>,
default: 'inline',
navLinkClasses: {
type: String,
default: '',
},
},
setup(_, { emit }) {
Expand Down
Loading