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

Update the Filters button #1861

Merged
merged 1 commit into from
Oct 4, 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
58 changes: 13 additions & 45 deletions src/components/VHeader/VFilterButton.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
<template>
<VButton
id="filter-button"
:variant="variant"
:variant="filtersAreApplied ? 'action-menu-muted' : 'action-menu'"
size="disabled"
class="align-center flex-shrink-0 gap-2 self-center py-2 font-semibold focus-visible:border-tx focus-visible:ring focus-visible:ring-pink"
:class="
filtersAreApplied
? 'flex-shrink-0 px-3'
: 'h-10 w-10 px-0 md:h-auto md:w-auto md:px-3'
"
class="align-center label-regular h-12 w-12 gap-2 self-center xl:w-auto xl:ps-3"
:class="[filtersAreApplied ? 'xl:pe-3' : 'xl:pe-4']"
:pressed="pressed"
:disabled="disabled"
aria-controls="filters"
:aria-label="mdMinLabel"
:aria-label="xlMinLabel"
@click="$emit('toggle')"
@keydown.tab.exact="$emit('tab', $event)"
>
<VIcon
:class="filtersAreApplied ? 'hidden' : 'block'"
:icon-path="filterIcon"
/>
<span class="hidden md:inline-block">{{ mdMinLabel }}</span>
<span class="md:hidden" :class="!filtersAreApplied && 'hidden'">{{
smMaxLabel
<span class="hidden xl:inline-block">{{ xlMinLabel }}</span>
<span class="xl:hidden" :class="{ hidden: !filtersAreApplied }">{{
lgMaxLabel
}}</span>
</VButton>
</template>

<script lang="ts">
import { computed, defineComponent, inject, ref } from '@nuxtjs/composition-api'
import { computed, defineComponent } from '@nuxtjs/composition-api'

import { useSearchStore } from '~/stores/search'
import { defineEvent } from '~/types/emits'
import type { ButtonVariant } from '~/types/button'
import { useI18n } from '~/composables/use-i18n'

import VButton from '~/components/VButton.vue'
Expand Down Expand Up @@ -63,55 +58,28 @@ export default defineComponent({
setup() {
const i18n = useI18n()
const searchStore = useSearchStore()
const isMinScreenMd = inject('isMinScreenMd', ref(false))
const isHeaderScrolled = inject('isHeaderScrolled', ref(false))
const filterCount = computed(() => searchStore.appliedFilterCount)
const filtersAreApplied = computed(() => filterCount.value > 0)

/**
* Determine the visual style of the button
* based on the viewport, the application of filters, and scrolling.
*/
const variant = computed(() => {
// Show the bordered state by default, unless below md
let value: ButtonVariant = isMinScreenMd.value
? 'action-menu-bordered'
: 'action-menu'

if (isHeaderScrolled.value) {
value = 'action-menu'
}
if (filtersAreApplied.value) {
value = 'action-menu-muted'
}
return value
})

/**
* This label's verbosity makes it useful for the aria-label
* where it is also used, especially on mobile where the
* label would just be the number of applied filters, and therefore
* basically useless as far as a label is concerned!
*/
const mdMinLabel = computed(() =>
const xlMinLabel = computed(() =>
filtersAreApplied.value
? i18n.tc('header.filter-button.with-count', filterCount.value)
: i18n.t('header.filter-button.simple')
)

const smMaxLabel = computed(() =>
isHeaderScrolled.value
? filterCount.value
: i18n.tc('header.filter-button.with-count', filterCount.value)
const lgMaxLabel = computed(() =>
filtersAreApplied ? filterCount.value : ''
)

return {
filterCount,
filterIcon,
mdMinLabel,
smMaxLabel,
variant,
isHeaderScrolled,
xlMinLabel,
lgMaxLabel,
filtersAreApplied,
}
},
Expand Down
33 changes: 18 additions & 15 deletions src/components/VHeader/meta/VFilterButton.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
Meta,
Story,
} from '@storybook/addon-docs'
import { provide, ref } from '@nuxtjs/composition-api'
import VFilterButton from '~/components/VHeader/VFilterButton.vue'
import { useSearchStore } from '~/stores/search'
import { filterData, mediaFilterKeys } from '~/constants/filters'
Expand All @@ -21,23 +20,24 @@ import { IMAGE } from '~/constants/media'
appliedFilters: {
type: 'number',
},
scrolled: {
type: 'boolean',
toggle: {
action: 'toggle',
},
isMinMd: {
type: 'boolean',
tab: {
action: 'tab',
},
}}
/>

export const Template = (args, { argTypes }) => ({
template: `<VFilterButton v-bind="args" />`,
template: `<VFilterButton v-bind="args" v-on="args" />`,
components: { VFilterButton },
props: Object.keys(argTypes),
setup() {
const searchStore = useSearchStore()
searchStore.setSearchType(IMAGE)
function applyNFilters(filterCount) {
searchStore.clearFilters()
const filterTypes = [...mediaFilterKeys[IMAGE]]
let filterIdx = 0
// Skip license type filters as they can disable license filters
Expand All @@ -56,12 +56,6 @@ export const Template = (args, { argTypes }) => ({
}
}
applyNFilters(args.appliedFilters)
if (args.scrolled) {
provide('isHeaderScrolled', ref(true))
}
if (args.isMinMd) {
provide('isMinScreenMd', ref(true))
}
return { args }
},
})
Expand All @@ -78,15 +72,24 @@ the field receives an input. It also emits the `search` event when the search
button is clicked.

<Canvas>
<Story name="Default">{Template.bind({})}</Story>
<Story
name="Default"
parameters={{
viewport: {
defaultViewport: 'lg',
},
}}
>
{Template.bind({})}
</Story>
</Canvas>

<Canvas>
<Story
name="Mobile Scrolled"
name="With text label"
parameters={{
viewport: {
defaultViewport: 'iphonex',
defaultViewport: 'xl',
},
}}
>
Expand Down
60 changes: 60 additions & 0 deletions test/storybook/visual-regression/v-filter-button-old.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { test } from '@playwright/test'

import breakpoints from '~~/test/playwright/utils/breakpoints'
import { makeGotoWithArgs } from '~~/test/storybook/utils/args'

const gotoWithArgs = makeGotoWithArgs(
'components-vheaderold-vfilterbuttonold--default-story'
)

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

test.describe('VFilterButtonOld', () => {
breakpoints.describeMd(({ expectSnapshot }) => {
test('no filters applied', async ({ page }) => {
await gotoWithArgs(page, { isMinMd: true })
await expectSnapshot('filter-button-old-at-rest', page)
})

test('no filters pressed', async ({ page }) => {
await gotoWithArgs(page, { isMinMd: true, pressed: true })
await expectSnapshot('filter-button-old-pressed', page)
})

test('filters applied', async ({ page }) => {
await gotoWithArgs(page, { isMinMd: true, appliedFilters: 2 })
await expectSnapshot('filter-button-old-2-filters', page)
})

test('filters applied and pressed', async ({ page }) => {
await gotoWithArgs(page, {
isMinMd: true,
appliedFilters: 2,
pressed: true,
})
await expectSnapshot('filter-button-old-2-filters-pressed', page)
})
})

breakpoints.describeXs(({ expectSnapshot }) => {
test('no filters applied and not scrolled', async ({ page }) => {
await gotoWithArgs(page)
await expectSnapshot('filter-button-old-no-filters-not-scrolled', page)
})

test('no filters but scrolled', async ({ page }) => {
await gotoWithArgs(page, { scrolled: true })
await expectSnapshot('filter-button-old-no-filters-scrolled', page)
})

test('2 filters not scrolled', async ({ page }) => {
await gotoWithArgs(page, { appliedFilters: 2 })
await expectSnapshot('filter-button-old-2-filters-not-scrolled', page)
})

test('2 filters and scrolled', async ({ page }) => {
await gotoWithArgs(page, { appliedFilters: 2, scrolled: true })
await expectSnapshot('filter-button-old-2-filters-scrolled', page)
})
})
})
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.
24 changes: 8 additions & 16 deletions test/storybook/visual-regression/v-filter-button.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@ const gotoWithArgs = makeGotoWithArgs(
'components-vheader-vfilterbutton--default-story'
)

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

test.describe('VFilterButton', () => {
breakpoints.describeMd(({ expectSnapshot }) => {
breakpoints.describeLg(({ expectSnapshot }) => {
test('no filters applied', async ({ page }) => {
await gotoWithArgs(page, { isMinMd: true })
await expectSnapshot('filter-button-at-rest', page)
})

test('no filters pressed', async ({ page }) => {
await gotoWithArgs(page, { isMinMd: true, pressed: true })
await gotoWithArgs(page, { pressed: true })
await expectSnapshot('filter-button-pressed', page)
})

test('filters applied', async ({ page }) => {
await gotoWithArgs(page, { isMinMd: true, appliedFilters: 2 })
await gotoWithArgs(page, { appliedFilters: 2 })
await expectSnapshot('filter-button-2-filters', page)
})

Expand All @@ -34,25 +36,15 @@ test.describe('VFilterButton', () => {
})
})

breakpoints.describeXs(({ expectSnapshot }) => {
test('no filters applied and not scrolled', async ({ page }) => {
breakpoints.describeXl(({ expectSnapshot }) => {
test('no filters applied', async ({ page }) => {
await gotoWithArgs(page)
await expectSnapshot('filter-button-no-filters-not-scrolled', page)
})

test('no filters but scrolled', async ({ page }) => {
await gotoWithArgs(page, { scrolled: true })
await expectSnapshot('filter-button-no-filters-scrolled', page)
})

test('2 filters not scrolled', async ({ page }) => {
test('2 filters', async ({ page }) => {
await gotoWithArgs(page, { appliedFilters: 2 })
await expectSnapshot('filter-button-2-filters-not-scrolled', page)
})

test('2 filters and scrolled', async ({ page }) => {
await gotoWithArgs(page, { appliedFilters: 2, scrolled: true })
await expectSnapshot('filter-button-2-filters-scrolled', page)
})
})
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
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.