From 3855ed7a6a638dc48de70b2896eb9ac952d01a99 Mon Sep 17 00:00:00 2001 From: Olga Bulat Date: Mon, 6 Dec 2021 20:15:20 +0300 Subject: [PATCH 01/24] Add VHeader stub Rename VSearchBar and VSearchButton and move to VHeader Add VLogoLoader to VHeader and adjust header styles --- package.json | 1 + .../License/meta/VLicense.stories.mdx | 2 +- src/components/VHeader/README.md | 11 +++ src/components/VHeader/VHeader.vue | 80 +++++++++++++++++++ .../VSearchBar/VSearchBar.vue} | 6 +- .../VSearchBar/VSearchButton.vue} | 2 +- .../VSearchBar/meta/VSearchBar.stories.mdx} | 22 ++--- .../VHeader/meta/VHeader.stories.mdx | 40 ++++++++++ src/components/VLogoLoader/VLogoLoader.vue | 3 +- src/composables/use-event-listener.js | 11 +-- src/composables/use-media-query.js | 3 +- src/composables/use-window-scroll.js | 43 ++++++++++ src/composables/window.js | 2 + src/layouts/default.vue | 8 +- src/layouts/with-nav-search.vue | 10 ++- src/pages/search.vue | 3 +- .../Header/SearchBar/search-bar.spec.js | 2 +- 17 files changed, 218 insertions(+), 31 deletions(-) create mode 100644 src/components/VHeader/README.md create mode 100644 src/components/VHeader/VHeader.vue rename src/components/{Header/SearchBar/SearchBar.vue => VHeader/VSearchBar/VSearchBar.vue} (92%) rename src/components/{Header/SearchBar/SearchButton.vue => VHeader/VSearchBar/VSearchButton.vue} (96%) rename src/components/{Header/SearchBar/meta/SearchBar.stories.mdx => VHeader/VSearchBar/meta/VSearchBar.stories.mdx} (76%) create mode 100644 src/components/VHeader/meta/VHeader.stories.mdx create mode 100644 src/composables/use-window-scroll.js create mode 100644 src/composables/window.js diff --git a/package.json b/package.json index 6afc44fd00..62faeb681e 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "lodash.findindex": "^4.6.0", "lodash.isempty": "^4.4.0", "lodash.sortby": "^4.7.0", + "lodash.throttle": "^4.1.1", "nuxt": "^2.15.4", "reakit-utils": "^0.15.2", "uuid": "^8.3.2", diff --git a/src/components/License/meta/VLicense.stories.mdx b/src/components/License/meta/VLicense.stories.mdx index 6cbdd10d19..98d588bf02 100644 --- a/src/components/License/meta/VLicense.stories.mdx +++ b/src/components/License/meta/VLicense.stories.mdx @@ -6,7 +6,7 @@ import { Story, } from '@storybook/addon-docs' -import VLicense from '~/components/license/VLicense.vue' +import VLicense from '~/components/License/VLicense.vue' diff --git a/src/components/VHeader/README.md b/src/components/VHeader/README.md new file mode 100644 index 0000000000..cf9f9f98f9 --- /dev/null +++ b/src/components/VHeader/README.md @@ -0,0 +1,11 @@ +#VHeader + +The sticky header at the top of the page. On the homepage and the content pages, it shows the +Openverse logo and page links ??and Search bar??, and on the Search page it additionally has +a Content Switcher, "burger menu" for page links, and a filters button. +On mobile, the header only shows the logo and close button when the overlay (pages, content +switcher, or filters) is open. + +## Components +### VLogoLoader +### VFilterButton diff --git a/src/components/VHeader/VHeader.vue b/src/components/VHeader/VHeader.vue new file mode 100644 index 0000000000..88497a9b60 --- /dev/null +++ b/src/components/VHeader/VHeader.vue @@ -0,0 +1,80 @@ + + + diff --git a/src/components/Header/SearchBar/SearchBar.vue b/src/components/VHeader/VSearchBar/VSearchBar.vue similarity index 92% rename from src/components/Header/SearchBar/SearchBar.vue rename to src/components/VHeader/VSearchBar/VSearchBar.vue index fd9b7044ca..5a309abc4f 100644 --- a/src/components/Header/SearchBar/SearchBar.vue +++ b/src/components/VHeader/VSearchBar/VSearchBar.vue @@ -12,7 +12,7 @@ - + @@ -20,7 +20,7 @@ import { computed } from '@nuxtjs/composition-api' import InputField from '~/components/InputField/InputField.vue' -import SearchButton from '~/components/Header/SearchBar/SearchButton.vue' +import VSearchButton from '~/components/VHeader/VSearchBar/VSearchButton.vue' /** * Displays a text field for a search query and is attached to an action button @@ -31,7 +31,7 @@ export default { name: 'SearchBar', components: { InputField, - SearchButton, + VSearchButton, }, inheritAttrs: false, model: { diff --git a/src/components/Header/SearchBar/SearchButton.vue b/src/components/VHeader/VSearchBar/VSearchButton.vue similarity index 96% rename from src/components/Header/SearchBar/SearchButton.vue rename to src/components/VHeader/VSearchBar/VSearchButton.vue index 86c8394cb9..38da6083b6 100644 --- a/src/components/Header/SearchBar/SearchButton.vue +++ b/src/components/VHeader/VSearchBar/VSearchButton.vue @@ -15,7 +15,7 @@ import VIconButton from '~/components/VIconButton/VIconButton.vue' import searchIcon from '~/assets/icons/search.svg' export default { - name: 'SearchButton', + name: 'VSearchButton', components: { VIconButton }, inheritAttrs: false, setup() { diff --git a/src/components/Header/SearchBar/meta/SearchBar.stories.mdx b/src/components/VHeader/VSearchBar/meta/VSearchBar.stories.mdx similarity index 76% rename from src/components/Header/SearchBar/meta/SearchBar.stories.mdx rename to src/components/VHeader/VSearchBar/meta/VSearchBar.stories.mdx index 1851645ad0..403c4964e4 100644 --- a/src/components/Header/SearchBar/meta/SearchBar.stories.mdx +++ b/src/components/VHeader/VSearchBar/meta/VSearchBar.stories.mdx @@ -5,11 +5,11 @@ import { Meta, Story, } from '@storybook/addon-docs' -import SearchBar from '~/components/Header/SearchBar/SearchBar.vue' +import VSearchBar from '~/components/VHeader/VSearchBar/VSearchBar.vue' ({ template: ` - + 12,345 results - `, - components: { SearchBar }, + `, + components: { VSearchBar }, props: Object.keys(argTypes), }) # Search bar - + - + The component emits an `input` event with the new contents of the field whenever the field receives an input. It also emits the `search` event when the search @@ -56,13 +56,13 @@ representing the search query. export const vModelTemplate = () => ({ template: `
- + {{ text.length }} - + {{ text }}
`, - components: { SearchBar }, + components: { VSearchBar }, data() { return { text: 'Hello, World!', @@ -74,7 +74,7 @@ export const vModelTemplate = () => ({ {vModelTemplate.bind({})} -The `SearchBar` component passes all attributes down to the inner `InputField` +The `VSearchBar` component passes all attributes down to the inner `InputField` which itself applies all its attributes to its inner `` element. So it's easy `` attributes like placeholders or HTML validations. diff --git a/src/components/VHeader/meta/VHeader.stories.mdx b/src/components/VHeader/meta/VHeader.stories.mdx new file mode 100644 index 0000000000..0644acf8f2 --- /dev/null +++ b/src/components/VHeader/meta/VHeader.stories.mdx @@ -0,0 +1,40 @@ +import { + ArgsTable, + Canvas, + Description, + Meta, + Story, +} from '@storybook/addon-docs' +import VHeader from '~/components/VHeader/VHeader.vue' + + + +export const Template = (args, { argTypes }) => ({ + template: ` + `, + components: { VHeader }, + props: Object.keys(argTypes), +}) + +# VHeader + + + + + +The header component. Fixed on scroll, search bar, content switcher, pages menu and filters button. + + + {Template.bind({})} + diff --git a/src/components/VLogoLoader/VLogoLoader.vue b/src/components/VLogoLoader/VLogoLoader.vue index ce4ddac143..7f1fd9aa37 100644 --- a/src/components/VLogoLoader/VLogoLoader.vue +++ b/src/components/VLogoLoader/VLogoLoader.vue @@ -51,8 +51,7 @@ export default defineComponent({ * @param {import('@nuxtjs/composition-api').SetupContext} context */ setup() { - const defaultWindow = typeof window !== 'undefined' ? window : undefined - const prefersReducedMotion = useReducedMotion({ window: defaultWindow }) + const prefersReducedMotion = useReducedMotion() return { prefersReducedMotion } }, diff --git a/src/composables/use-event-listener.js b/src/composables/use-event-listener.js index 5ce9f30368..266a349003 100644 --- a/src/composables/use-event-listener.js +++ b/src/composables/use-event-listener.js @@ -12,18 +12,19 @@ import { * @param {import('@nuxtjs/composition-api').Ref | EventTarget} target The target can be a reactive ref which adds flexibility * @param {string} event * @param {(e: Event) => void} handler + * @param {any} options */ -export function useEventListener(target, event, handler) { - // if its a reactive ref, use a watcher +export function useEventListener(target, event, handler, options = {}) { + // if it's a reactive ref, use a watcher if (isRef(target)) { watch(target, (value, oldValue) => { oldValue?.removeEventListener(event, handler) - value?.addEventListener(event, handler) + value?.addEventListener(event, handler, options) }) } else { - // otherwise use the mounted hook + // otherwise, use the mounted hook onMounted(() => { - target.addEventListener(event, handler) + target.addEventListener(event, handler, options) }) } // clean it up diff --git a/src/composables/use-media-query.js b/src/composables/use-media-query.js index d253064d69..3dd7b7abb9 100644 --- a/src/composables/use-media-query.js +++ b/src/composables/use-media-query.js @@ -2,6 +2,7 @@ which, in turn, is ported from https://github.com/logaretm/vue-use-web by Abdelrahman Awad */ import { onBeforeUnmount, ref } from '@nuxtjs/composition-api' import { SCREEN_SIZES } from '~/constants/screens.js' +import { defaultWindow } from '~/composables/window' /** * Reactive Media Query. @@ -10,7 +11,7 @@ import { SCREEN_SIZES } from '~/constants/screens.js' * @param options */ export function useMediaQuery(query, options = {}) { - const { window } = options + const { window = defaultWindow } = options if (!window) return ref(false) const mediaQuery = window.matchMedia(query) diff --git a/src/composables/use-window-scroll.js b/src/composables/use-window-scroll.js new file mode 100644 index 0000000000..3713de4bce --- /dev/null +++ b/src/composables/use-window-scroll.js @@ -0,0 +1,43 @@ +// code taken from Vueuse +import throttle from 'lodash.throttle' +import { defaultWindow } from '~/composables/window' +import { ref } from '@nuxtjs/composition-api' +import { useEventListener } from '~/composables/use-event-listener' + +/** + * + * @param {object} options + * @param {Window} [options.window] + * @param {number} [options.throttleMs] - time to throttle the scroll handler. + * Set to 0 to remove throttling + */ +export function useWindowScroll({ + window = defaultWindow, + throttleMs = 200, +} = {}) { + if (!window) { + return { + x: ref(0), + y: ref(0), + } + } + + const x = ref(window.pageXOffset) + const y = ref(window.pageYOffset) + + const scrollHandler = () => { + x.value = window.pageXOffset + y.value = window.pageYOffset + } + + const handler = throttleMs + ? throttle(scrollHandler, throttleMs) + : scrollHandler + + useEventListener(window, 'scroll', handler, { + capture: false, + passive: true, + }) + + return { x, y } +} diff --git a/src/composables/window.js b/src/composables/window.js new file mode 100644 index 0000000000..2fa7b45ef5 --- /dev/null +++ b/src/composables/window.js @@ -0,0 +1,2 @@ +export const isClient = typeof window !== 'undefined' +export const defaultWindow = isClient ? window : undefined diff --git a/src/layouts/default.vue b/src/layouts/default.vue index 6d213583b6..2a51eb1b32 100644 --- a/src/layouts/default.vue +++ b/src/layouts/default.vue @@ -1,8 +1,8 @@