Skip to content

Commit

Permalink
Update the search button (#2148)
Browse files Browse the repository at this point in the history
  • Loading branch information
obulat authored May 26, 2023
1 parent b37d199 commit b8dec83
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 109 deletions.
3 changes: 2 additions & 1 deletion frontend/src/components/VButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ const VButton = defineComponent({
/**
* The variant of the button.
*
* Plain removes all styles except the focus ring.
* Plain removes all styles except the focus ring. The button
* should set a border color, otherwise the browser default is used.
* Plain--avoid removes _all_ styles including the focus ring.
*/
variant: {
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/components/VHeader/VSearchBar/VSearchBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
</VInputField>
<VSearchButton
type="submit"
:size="size"
route="search"
@keydown.tab="handleSearchBlur"
/>
Expand Down Expand Up @@ -129,10 +128,7 @@ export default defineComponent({
const recentClasses = computed(() => {
// Calculated by adding 8px to all heights defined in `VInputField.vue`.
const FIELD_OFFSETS = {
small: "top-12",
medium: "top-14",
large: "top-16",
standalone: "top-[65px] md:top-[77px]",
} as const
return FIELD_OFFSETS[props.size]
})
Expand Down
71 changes: 14 additions & 57 deletions frontend/src/components/VHeader/VSearchBar/VSearchButton.vue
Original file line number Diff line number Diff line change
@@ -1,84 +1,41 @@
<template>
<VButton
:aria-label="$t('search.search')"
type="submit"
:aria-label="$t('search.search').toString()"
size="disabled"
:variant="route === 'home' ? 'filled-pink' : 'transparent-tx'"
class="heading-6 h-full flex-shrink-0 rounded-s-none"
variant="plain"
:class="[
route === 'home'
? 'w-[57px] whitespace-nowrap md:w-auto md:px-10 md:py-6'
: 'search-button p-0.5px ps-1.5px hover:bg-pink hover:text-white focus-visible:bg-pink focus-visible:text-white group-focus-within:border-pink group-focus-within:bg-pink group-focus-within:text-white group-focus-within:hover:bg-dark-pink group-hover:border-pink group-hover:bg-pink group-hover:text-white',
'h-full flex-shrink-0 rounded-s-none border-s-0 p-0.5px ps-1.5px focus-slim-filled hover:text-white focus-visible:border-s group-focus-within:border-tx group-focus-within:bg-pink group-focus-within:text-white group-focus-within:hover:bg-dark-pink group-hover:border-tx group-hover:bg-pink group-hover:text-white',
route === 'search' ? 'w-12' : 'w-14 sm:w-16',
{
'w-10 bg-dark-charcoal-10 md:w-12': route === 'search',
'border-black focus:border-tx group-focus-within:border-tx group-hover:border-tx group-focus:border-tx':
route === '404',
'border-tx bg-dark-charcoal-10 hover:bg-pink ': route === 'search',
'border-tx bg-pink text-white hover:!bg-dark-pink': route === 'home',
},
sizeClasses,
]"
>
<VIcon v-show="isIcon" name="search" />
<span v-show="!isIcon">{{ $t("search.search") }}</span>
<VIcon name="search" />
</VButton>
</template>

<script lang="ts">
import { defineComponent, computed, PropType } from "vue"
import { useUiStore } from "~/stores/ui"
import { defineComponent, PropType } from "vue"
import VIcon from "~/components/VIcon/VIcon.vue"
import VButton from "~/components/VButton.vue"
import type { FieldSize } from "~/components/VInputField/VInputField.vue"
/**
* The search button used in the search bar on the homepage and on the 404 page,
* and on the search page.
* The search button used in the search bar on the home, 404 and search pages.
*/
export default defineComponent({
name: "VSearchButton",
components: { VIcon, VButton },
props: {
size: {
type: String as PropType<FieldSize>,
required: true,
},
/**
* The current route determines the size and the style of the button.
*/
route: {
type: String as PropType<"home" | "404" | "search">,
validator: (v: string) => ["home", "404", "search"].includes(v),
required: true,
},
},
setup(props) {
const uiStore = useUiStore()
/**
* The search button has a text label on the homepage with a desktop layout,
* everywhere else it has an icon.
*/
const isIcon = computed(() => {
if (props.route !== "home") {
return true
} else {
return !uiStore.isDesktopLayout
}
})
const sizeClasses = computed(() =>
isIcon.value
? {
small: "w-10 md:w-12",
medium: "w-12",
large: "w-14",
standalone: "w-[57px] md:w-[69px]",
}[props.size]
: undefined
)
return { sizeClasses, isIcon }
},
})
</script>

<style scoped>
.search-button {
border-inline-start-width: 0;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<div
class="input-field search-field group flex h-full flex-grow items-center overflow-hidden rounded-sm rounded-e-none border border-e-0 p-0.5px pe-2 focus-within:border-1.5 focus-within:border-e-0 focus-within:p-0 focus-within:pe-2"
:class="[
isHomeRoute ? 'border-tx' : 'border-black',
route === 'home' ? 'border-tx' : 'border-black',
hasPopover ? 'focus-within:border-tx' : 'focus-within:border-pink',
]"
>
Expand All @@ -28,29 +28,16 @@
<!-- @slot Extra information goes here -->
<slot />
</div>
<VButton
type="submit"
:aria-label="$t('search.search').toString()"
size="disabled"
:variant="isHomeRoute ? 'filled-pink' : 'plain'"
class="h-full w-14 flex-shrink-0 rounded-s-none sm:w-16"
:class="{
'search-button border !border-black p-0.5px ps-1.5px hover:bg-pink hover:text-white focus:!border-tx focus-visible:bg-pink focus-visible:text-white group-focus-within:!border-tx group-focus-within:bg-pink group-focus-within:text-white group-focus-within:hover:bg-dark-pink group-hover:!border-tx group-hover:bg-pink group-hover:text-white group-focus:!border-tx':
!isHomeRoute,
}"
>
<VIcon name="search" />
</VButton>
<VSearchButton :route="route" />
</form>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, ref } from "vue"
import { defineComponent, PropType, ref } from "vue"
import { defineEvent } from "~/types/emits"
import VButton from "~/components/VButton.vue"
import VIcon from "~/components/VIcon/VIcon.vue"
import VSearchButton from "~/components/VHeader/VSearchBar/VSearchButton.vue"
/**
* Displays a search input for a search query and is attached to an action button
Expand All @@ -61,7 +48,7 @@ import VIcon from "~/components/VIcon/VIcon.vue"
*/
export default defineComponent({
name: "VStandaloneSearchBar",
components: { VButton, VIcon },
components: { VSearchButton },
props: {
route: {
type: String as PropType<"home" | "404">,
Expand All @@ -78,7 +65,7 @@ export default defineComponent({
emits: {
submit: defineEvent<[string]>(),
},
setup(props, { emit }) {
setup(_, { emit }) {
const inputRef = ref<HTMLInputElement | null>(null)
// Only emit `submit` if the input value is not blank
Expand All @@ -89,22 +76,10 @@ export default defineComponent({
}
}
const isHomeRoute = computed(() => props.route === "home")
return {
inputRef,
handleSearch,
isHomeRoute,
}
},
})
</script>
<style scoped>
.input-field {
border-inline-end-width: 0;
}
.search-button {
border-inline-start-width: 0;
}
</style>
7 changes: 1 addition & 6 deletions frontend/src/components/VInputField/VInputField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ import { ref, computed, defineComponent, PropType } from "vue"
import { defineEvent } from "~/types/emits"
export const FIELD_SIZES = {
small: "h-10 text-md",
medium: "h-12",
large: "h-14",
standalone: "h-full",
} as const
export type FieldSize = keyof typeof FIELD_SIZES
Expand Down Expand Up @@ -86,10 +83,8 @@ export default defineComponent({
v.every((item) => ["start", "end"].includes(item)),
},
/**
* Small size is for mobile header/scrolled
* Medium size is for desktop header
* Large size is for mobile header/non-scrolled
* Standalone size is for homepage
* Large size is for mobile header
*/
size: {
type: String as PropType<keyof typeof FIELD_SIZES>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import VInputField from "~/components/VInputField/VInputField.vue"
const props = {
fieldId: "input-id",
labelText: "Label",
size: "small",
size: "medium",
}

describe("VInputField", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,21 @@ import { render } from "~~/test/unit/test-utils/render"
import { useMatchHomeRoute } from "~/composables/use-match-routes"

import VSearchBar from "~/components/VHeader/VSearchBar/VSearchBar.vue"
import { FIELD_SIZES } from "~/components/VInputField/VInputField.vue"

jest.mock("~/composables/use-match-routes", () => ({
useMatchHomeRoute: jest.fn(),
}))

const sizes = ["small", "medium", "large", "standalone"]
const sizes = Object.keys(FIELD_SIZES)
const defaultPlaceholder = "Enter search query"

describe("VSearchBar", () => {
let options
beforeEach(() => {
options = {
props: { placeholder: defaultPlaceholder, size: "standalone" },
props: { placeholder: defaultPlaceholder, size: "medium" },
stubs: { ClientOnly: true },
mocks: {
$nuxt: {
context: {
app: { $ua: {} },
},
},
},
}
})

Expand Down

0 comments on commit b8dec83

Please sign in to comment.