From ffb23aa6866de00ce93c26244a98ff00838c10f2 Mon Sep 17 00:00:00 2001 From: Fanny Chien Date: Wed, 2 Feb 2022 12:52:07 -0300 Subject: [PATCH 1/8] [FSSS-163] Feat: Style IconButton (#290) * Creates styled IconButton * Uses IconButton over Button on Navbar * Uses IconButton on CartSide bar * Uses IconButton on Filter * Renames props to otherProps * Fixes icon size and alignment * Updates icon sizes * Updates header paddings * Removes icon-button class and renames color * Uses IconButton over Button on CartToggle * Triggers CI with an empty commit * Triggers CI with an empty commit * Triggers CI with an empty commit Co-authored-by: Filipe W. Lima --- .../cart/CartSidebar/CartSidebar.tsx | 10 ++++--- .../cart/CartSidebar/cart-sidebar.scss | 10 ++----- src/components/cart/CartToggle/CartToggle.tsx | 9 +++--- .../cart/CartToggle/cart-toggle.scss | 18 +----------- src/components/common/Navbar/Navbar.tsx | 21 +++++++------- src/components/common/Navbar/navbar.scss | 15 ++-------- src/components/search/Filter/Filter.tsx | 12 ++++---- src/components/search/Filter/filter.scss | 11 +------ src/components/ui/IconButton/IconButton.tsx | 23 +++++++++++++++ src/components/ui/IconButton/icon-button.scss | 29 +++++++++++++++++++ src/components/ui/IconButton/index.ts | 1 + 11 files changed, 86 insertions(+), 73 deletions(-) create mode 100644 src/components/ui/IconButton/IconButton.tsx create mode 100644 src/components/ui/IconButton/icon-button.scss create mode 100644 src/components/ui/IconButton/index.ts diff --git a/src/components/cart/CartSidebar/CartSidebar.tsx b/src/components/cart/CartSidebar/CartSidebar.tsx index 2634ad579..fb6cc5a64 100644 --- a/src/components/cart/CartSidebar/CartSidebar.tsx +++ b/src/components/cart/CartSidebar/CartSidebar.tsx @@ -2,6 +2,7 @@ import React from 'react' import { useCart } from 'src/sdk/cart/useCart' import { useCheckoutButton } from 'src/sdk/cart/useCheckoutButton' import Button from 'src/components/ui/Button' +import IconButton from 'src/components/ui/IconButton' import { ArrowRight as ArrowRightIcon, X as XIcon, @@ -51,12 +52,13 @@ function CartSidebar() { {totalItems} - + /> }> Free shiping starts at $300 diff --git a/src/components/cart/CartSidebar/cart-sidebar.scss b/src/components/cart/CartSidebar/cart-sidebar.scss index 2b0b11be2..cd3dbdc5e 100644 --- a/src/components/cart/CartSidebar/cart-sidebar.scss +++ b/src/components/cart/CartSidebar/cart-sidebar.scss @@ -27,15 +27,11 @@ display: flex; align-items: center; justify-content: space-between; - padding: var(--space-5) var(--page-padding-phone) var(--space-4); + padding: var(--space-2) var(--page-padding-phone) var(--space-2); background-color: var(--bg-neutral-lightest); - button { - position: absolute; - right: calc(-1 * var(--page-padding-phone)); - margin-right: var(--space-0); - color: var(--color-text); - background-color: transparent; + .cart-sidebar__button { + margin-right: calc(-1 * var(--space-1)); } } diff --git a/src/components/cart/CartToggle/CartToggle.tsx b/src/components/cart/CartToggle/CartToggle.tsx index 71cd863c6..7fd637cdd 100644 --- a/src/components/cart/CartToggle/CartToggle.tsx +++ b/src/components/cart/CartToggle/CartToggle.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Button from 'src/components/ui/Button' +import IconButton from 'src/components/ui/IconButton' import { useCartToggleButton } from 'src/sdk/cart/useCartToggleButton' import { ShoppingCart as ShoppingCartIcon } from 'phosphor-react' @@ -9,13 +9,12 @@ function CartToggle() { const btnProps = useCartToggleButton() return ( - + icon={} + /> ) } diff --git a/src/components/cart/CartToggle/cart-toggle.scss b/src/components/cart/CartToggle/cart-toggle.scss index 9bac4fccd..9f3dc701f 100644 --- a/src/components/cart/CartToggle/cart-toggle.scss +++ b/src/components/cart/CartToggle/cart-toggle.scss @@ -1,19 +1,7 @@ @import "../../../styles/utilities.scss"; -.cart-toggle[data-store-button] { +.cart-toggle[data-store-icon-button] { position: relative; - display: flex; - align-items: center; - justify-content: center; - min-width: var(--tap-min-size); - min-height: var(--tap-min-size); - background-color: transparent; - border-width: 0; - border-radius: var(--border-radius-button); - cursor: pointer; - transition: background-color .5s ease; - - svg { color: var(--color-text); } &::after { --cart-toggle-size: var(--space-3); @@ -34,8 +22,4 @@ border-radius: var(--border-radius-pill); content: attr(data-items); } - - &:hover { - background-color: var(--bg-secondary-light); - } } diff --git a/src/components/common/Navbar/Navbar.tsx b/src/components/common/Navbar/Navbar.tsx index b1b38a6ca..c214bf17e 100644 --- a/src/components/common/Navbar/Navbar.tsx +++ b/src/components/common/Navbar/Navbar.tsx @@ -4,7 +4,7 @@ import { List as UIList } from '@faststore/ui' import CartToggle from 'src/components/cart/CartToggle' import Logo from 'src/components/ui/Logo' import Link from 'src/components/ui/Link' -import Button from 'src/components/ui/Button' +import IconButton from 'src/components/ui/IconButton' import { List as ListIcon, X as XIcon } from 'phosphor-react' import SignInLink from 'src/components/ui/SignInLink' import SlideOver from 'src/components/ui/SlideOver' @@ -50,13 +50,12 @@ function Navbar() {
- + /> - + />
diff --git a/src/components/common/Navbar/navbar.scss b/src/components/common/Navbar/navbar.scss index 3fd43b3fa..88fe70754 100644 --- a/src/components/common/Navbar/navbar.scss +++ b/src/components/common/Navbar/navbar.scss @@ -31,10 +31,6 @@ } .navbar__menu[data-store-button] { - color: var(--color-text); - background-color: transparent; - border: 0; - @include media(">=notebook") { display: none; } } @@ -87,17 +83,10 @@ display: flex; align-items: center; justify-content: space-between; - padding: var(--space-3) 0; + padding-bottom: var(--space-2); .navbar__button { - position: absolute; - right: calc(-1 * var(--page-padding-phone)); - display: flex; - margin-right: var(--space-1); - padding: var(--space-1); - color: var(--color-text-display); - background-color: transparent; - border: 0; + margin-right: calc(-1 * var(--space-1)); } } diff --git a/src/components/search/Filter/Filter.tsx b/src/components/search/Filter/Filter.tsx index 06138c163..c86151b9e 100644 --- a/src/components/search/Filter/Filter.tsx +++ b/src/components/search/Filter/Filter.tsx @@ -6,6 +6,7 @@ import type { } from '@generated/graphql' import useWindowDimensions from 'src/hooks/useWindowDimensions' import Button from 'src/components/ui/Button' +import IconButton from 'src/components/ui/IconButton' import { X as XIcon } from 'phosphor-react' import SlideOver from 'src/components/ui/SlideOver' @@ -183,17 +184,16 @@ function Filter({

Filters

- + />
+ ) +} + +export default IconButton diff --git a/src/components/ui/IconButton/icon-button.scss b/src/components/ui/IconButton/icon-button.scss new file mode 100644 index 000000000..eabc8f1f5 --- /dev/null +++ b/src/components/ui/IconButton/icon-button.scss @@ -0,0 +1,29 @@ +@import "../../../styles/utilities"; + +[data-store-icon-button] { + display: flex; + align-items: center; + justify-content: center; + width: var(--tap-min-size); + height: var(--tap-min-size); + color: var(--color-text); + background-color: transparent; + border: 0; + border-radius: var(--border-radius-button); + transition: background-color .5s ease; + + &:focus { outline: none; } + &:focus-visible { @include button-focus-ring; } + + &:hover, &:focus { background-color: var(--bg-secondary-light); } + + &:active { + color: var(--color-text-display); + background-color: var(--color-secondary-1); + } + + &:disabled, &[data-button-disabled="true"] { + color: var(--color-text-disabled); + background-color: var(--bg-disabled); + } +} diff --git a/src/components/ui/IconButton/index.ts b/src/components/ui/IconButton/index.ts new file mode 100644 index 000000000..9de6d2c2d --- /dev/null +++ b/src/components/ui/IconButton/index.ts @@ -0,0 +1 @@ +export { default } from './IconButton' From 0769b16a4c0e1c9061014ba89f59719d4dda6af6 Mon Sep 17 00:00:00 2001 From: "Filipe W. Lima" Date: Wed, 2 Feb 2022 13:55:03 -0300 Subject: [PATCH 2/8] Fix a SonarQube warning (#297) ## What's the purpose of this pull request? Fix a [SonarQube warning](https://github.com/vtex-sites/base.store/runs/5025104180#:~:text=15M/61M%0AINFO%3A%20%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D%2D-,ANNOTATIONS,-Check%20warning%20on) in a piece of the code by following its suggestion of removing a temporary variable. ## How to test it? The last commit should not have SonarQube trigger the warning anymore. Before|After -|- ![Screen Shot 2022-02-01 at 16 42 27](https://user-images.githubusercontent.com/381395/152039613-343f1236-ac76-4dcc-9a73-48ce992f92bf.png)|![Screen Shot 2022-02-01 at 16 42 31](https://user-images.githubusercontent.com/381395/152039598-958c00b8-5041-4f6d-aa8e-b3e93999bec3.png) --- src/components/ui/QuantitySelector/QuantitySelector.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/ui/QuantitySelector/QuantitySelector.tsx b/src/components/ui/QuantitySelector/QuantitySelector.tsx index 69b0a74d9..ebee0a16d 100644 --- a/src/components/ui/QuantitySelector/QuantitySelector.tsx +++ b/src/components/ui/QuantitySelector/QuantitySelector.tsx @@ -36,9 +36,8 @@ export function QuantitySelector({ function validateQuantityBounds(n: number): number { const maxValue = min ? Math.max(n, min) : n - const minValue = max ? Math.min(maxValue, max) : maxValue - return minValue + return max ? Math.min(maxValue, max) : maxValue } function validateInput(e: React.FormEvent) { From a9d6dfbf9d44a868169ab5274f1af1a37af47328 Mon Sep 17 00:00:00 2001 From: Renata Motta Date: Thu, 3 Feb 2022 10:55:07 -0300 Subject: [PATCH 3/8] [FSSS-162] General fixes on Beta components (#287) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removes unnecessary padding from breadcrumb * Fixes select click behavior * Improves Button Secondary states * Simplifies disabled buttons styling * Unifies cursor on Buttons and LinkButtons * Fixes Accordion click area and cursor * Attempts to fix menu buttons on mobile * Improves navbar button position * Attempts to unify focus on all interactive elements * Changes theme-color from safari * Unifies focus * Fixes LinkButton's disabled state * Fixes typo * Updates disabled button token to a more semantical one Co-authored-by: Fanny Chien * Changes focus-ring to focus-ring-visible when possible * Improves FocusEvent on LinkButton Co-Authored-By: Eduardo Formiga * Updates SkuSelector's focus * Fixes merge bugs * Change use of && as safe-guard to 'if' * Aligns Filters title * Adds { after 'if' condition * Rerun tests * Trigger CI with an empty commit Co-authored-by: Fanny Chien Co-authored-by: Eduardo Formiga Co-authored-by: Heitor Carvalho Co-authored-by: Lucas Feijó --- gatsby-config.js | 2 +- .../common/SearchInput/search-input.scss | 7 ++- src/components/search/Filter/filter.scss | 5 +- src/components/search/Sort/sort.scss | 9 +-- src/components/ui/Accordion/accordion.scss | 19 +++++-- src/components/ui/Breadcrumb/breadcrumb.scss | 2 - src/components/ui/Button/LinkButton.tsx | 13 ++++- src/components/ui/Button/buttons.scss | 57 ++++++++++--------- src/components/ui/Checkbox/checkbox.scss | 8 +-- src/components/ui/IconButton/icon-button.scss | 9 ++- src/components/ui/Link/link.scss | 9 ++- .../QuantitySelector/quantity-selector.scss | 41 ++++++++++--- .../ui/SkuSelector/sku-selector.scss | 28 +++++++-- src/styles/pages/product-listing.scss | 3 +- src/styles/utilities.scss | 46 ++++++++++----- 15 files changed, 183 insertions(+), 75 deletions(-) diff --git a/gatsby-config.js b/gatsby-config.js index ab8e05be1..b9682aa85 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -42,7 +42,7 @@ module.exports = { start_url: '/', icon: 'src/images/icon.png', background_color: '#E31C58', - theme_color: '#E31C58', + theme_color: '#ffffff', display: 'standalone', cache_busting_mode: 'none', }, diff --git a/src/components/common/SearchInput/search-input.scss b/src/components/common/SearchInput/search-input.scss index 393663b24..1f7272a8a 100644 --- a/src/components/common/SearchInput/search-input.scss +++ b/src/components/common/SearchInput/search-input.scss @@ -15,7 +15,12 @@ border-radius: var(--border-radius-default); transition: box-shadow .2s ease, border .2s ease; - &:focus { @include input-focus-ring; } + &:hover { + border-color: var(--color-border-input-selected); + box-shadow: 0 0 0 var(--border-width-0) var(--color-border-input-selected); + } + + @include input-focus-ring; } [data-store-icon] { display: block; } diff --git a/src/components/search/Filter/filter.scss b/src/components/search/Filter/filter.scss index 199363bc2..875e71be6 100644 --- a/src/components/search/Filter/filter.scss +++ b/src/components/search/Filter/filter.scss @@ -2,7 +2,10 @@ .filter[data-store-filter] { > .title-small { - margin-bottom: var(--space-3); + display: flex; + align-items: center; + height: var(--product-listing-row-height); + margin-bottom: var(--space-0); @include media("=notebook") { height: var(--space-6); } @@ -42,5 +42,6 @@ position: absolute; right: var(--space-2); color: var(--color-link); + pointer-events: none; } } diff --git a/src/components/ui/Accordion/accordion.scss b/src/components/ui/Accordion/accordion.scss index 1fad33d74..30bc99bf7 100644 --- a/src/components/ui/Accordion/accordion.scss +++ b/src/components/ui/Accordion/accordion.scss @@ -9,15 +9,20 @@ border-bottom: 1px solid var(--color-border-display); @include media(">=notebook") { - padding: 0 var(--space-4); - &:last-child { border-bottom: 0; } } } - [data-accordion-item] [data-store-button] { + [data-accordion-panel] { + @include media(">=notebook") { + padding-right: var(--space-4); + padding-left: var(--space-4); + } + } + + [data-store-button] { display: inline-flex; align-items: center; justify-content: space-between; @@ -26,9 +31,15 @@ color: var(--color-text); background-color: transparent; border: 0; + cursor: pointer; + + @include media(">=notebook") { + padding-right: var(--space-4); + padding-left: var(--space-4); + } } - [data-accordion-item] [data-store-icon] { + [data-store-icon] { display: flex; } } diff --git a/src/components/ui/Breadcrumb/breadcrumb.scss b/src/components/ui/Breadcrumb/breadcrumb.scss index a0ce5dd3e..395cfaafd 100644 --- a/src/components/ui/Breadcrumb/breadcrumb.scss +++ b/src/components/ui/Breadcrumb/breadcrumb.scss @@ -2,8 +2,6 @@ [data-store-breadcrumb] { width: 100%; - padding-top: var(--space-2); - padding-bottom: var(--space-2); [data-breadcrumb-list] { display: flex; diff --git a/src/components/ui/Button/LinkButton.tsx b/src/components/ui/Button/LinkButton.tsx index 013b2c5e6..c00f82f9b 100644 --- a/src/components/ui/Button/LinkButton.tsx +++ b/src/components/ui/Button/LinkButton.tsx @@ -1,6 +1,7 @@ -import React from 'react' +import React, { useRef } from 'react' import type { LinkProps } from '@faststore/ui' import { Icon as UIIcon, Link as UILink } from '@faststore/ui' +import type { FocusEvent } from 'react' import type { UIButtonProps } from './Button' @@ -21,13 +22,23 @@ function LinkButton({ className = '', ...otherProps }: Props) { + const linkRef = useRef(null) + return ( { + e.preventDefault() + + if (disabled) { + linkRef.current?.blur() + } + }} {...otherProps} > {iconPosition === 'left' && } diff --git a/src/components/ui/Button/buttons.scss b/src/components/ui/Button/buttons.scss index a5da0167d..2fdc40ba5 100644 --- a/src/components/ui/Button/buttons.scss +++ b/src/components/ui/Button/buttons.scss @@ -1,5 +1,12 @@ @import "../../../styles/utilities"; +[data-store-button] { + border-radius: var(--border-radius-button); + transition: background-color .5s ease, box-shadow .5s ease; + + @include focus-ring-visible; +} + .button[data-store-button], .link-button[data-store-button] { display: inline-flex; align-items: center; @@ -10,11 +17,7 @@ text-decoration: none; column-gap: var(--space-2); border: 0; - border-radius: var(--border-radius-button); - transition: background-color .5s ease; - - &:focus { outline: none; } - &:focus-visible { @include button-focus-ring; } + cursor: default; &:disabled, &[data-button-disabled="true"] { cursor: not-allowed; @@ -29,11 +32,6 @@ &:active { background-color: var(--bg-secondary-pressed); } - &:disabled, &[data-button-disabled="true"] { - color: var(--color-neutral-6); - background-color: var(--bg-disabled); - } - &[data-button-inverse] { color: var(--color-text-display); background-color: var(--bg-neutral-lightest); @@ -47,23 +45,27 @@ &[data-button-variant="secondary"] { color: var(--color-text-display); background-color: transparent; - border: 2px solid var(--bg-secondary-default); - - &:hover, &:focus { background-color: var(--bg-darken-hover); } + border: var(--border-width-1) solid var(--bg-secondary-default); - &:active { background-color: var(--bg-darken-pressed); } + &:hover, &:focus { + color: var(--color-text-inverse); + background-color: var(--bg-secondary-default); + } - &:disabled, &[data-button-disabled="true"] { - color: var(--color-neutral-6); - background-color: var(--bg-disabled); - border: 0; + &:active { + background-color: var(--bg-secondary-hover); + border-color: var(--bg-secondary-hover); } &[data-button-inverse] { color: var(--color-text-inverse); border-color: var(--color-border-light); - &:hover, &:focus { background-color: var(--bg-lighten-hover); } - &:active { background-color: var(--bg-lighten-pressed); } + + &:hover, &:focus { + color: var(--color-text-display); + background-color: var(--bg-neutral-lightest); + } + &:active { background-color: var(--bg-secondary-light); } } } @@ -78,11 +80,6 @@ background-color: var(--color-secondary-1); } - &:disabled, &[data-button-disabled="true"] { - color: var(--color-neutral-6); - background-color: var(--bg-disabled); - } - &[data-button-inverse] { color: var(--color-text-display); background-color: var(--bg-neutral-lightest); @@ -93,6 +90,14 @@ } } + &[data-button-variant] { + &:disabled, &[data-button-disabled="true"] { + color: var(--color-text-disabled); + background-color: var(--bg-disabled); + border: 0; + } + } + [data-store-icon] { display: flex; } @@ -103,7 +108,7 @@ text-decoration: none; } - &[data-button-disabled="true"] { + &[data-button-disabled="true"]:active { pointer-events: none; } } diff --git a/src/components/ui/Checkbox/checkbox.scss b/src/components/ui/Checkbox/checkbox.scss index 20a57f5e5..ac69d41ac 100644 --- a/src/components/ui/Checkbox/checkbox.scss +++ b/src/components/ui/Checkbox/checkbox.scss @@ -14,6 +14,8 @@ transition: border .2s ease, background-color .2s ease, box-shadow .2s ease; appearance: none; + @include input-focus-ring; + &::before { position: absolute; top: rem(3px); @@ -28,13 +30,10 @@ content: ""; } - &:focus { - @include focus-ring; - } - &:hover { background-color: var(--bg-secondary-light); border-color: var(--color-text); + box-shadow: 0 0 0 var(--border-width-0) var(--color-border-input-selected); } &:checked { @@ -48,6 +47,7 @@ &:hover { background-color: var(--bg-secondary-hover); + box-shadow: none; } } diff --git a/src/components/ui/IconButton/icon-button.scss b/src/components/ui/IconButton/icon-button.scss index eabc8f1f5..45d6f06d2 100644 --- a/src/components/ui/IconButton/icon-button.scss +++ b/src/components/ui/IconButton/icon-button.scss @@ -12,8 +12,13 @@ border-radius: var(--border-radius-button); transition: background-color .5s ease; - &:focus { outline: none; } - &:focus-visible { @include button-focus-ring; } + span { + display: flex; + align-items: center; + justify-content: center; + } + + @include focus-ring-visible; &:hover, &:focus { background-color: var(--bg-secondary-light); } diff --git a/src/components/ui/Link/link.scss b/src/components/ui/Link/link.scss index 9744025ff..13b4e56da 100644 --- a/src/components/ui/Link/link.scss +++ b/src/components/ui/Link/link.scss @@ -1,4 +1,11 @@ -@import "../../../styles/vendors/include-media"; +@import "../../../styles/scaffold.scss"; + +a, [data-store-link] { + border-radius: var(--border-radius-default); + transition: box-shadow .5s ease; + + @include focus-ring-visible; +} [data-store-link] { min-width: auto; diff --git a/src/components/ui/QuantitySelector/quantity-selector.scss b/src/components/ui/QuantitySelector/quantity-selector.scss index 463d9d905..d93fd268e 100644 --- a/src/components/ui/QuantitySelector/quantity-selector.scss +++ b/src/components/ui/QuantitySelector/quantity-selector.scss @@ -1,3 +1,34 @@ +@import "../../../styles/utilities"; + +@mixin quantity-selector-focus-ring { + @media not all and (min-resolution: .001dpcm) { // Target only Safari browsers + @supports (-webkit-appearance:none) { + // Use `focus` instead of `focus-visible` due to Safari's lack of support + &:focus { + outline: none; + box-shadow: none; + + [data-store-icon] { + @include focus-ring; + + background-color: var(--bg-secondary-light); + } + } + } + } + + &:focus-visible { + outline: none; + box-shadow: none; + + [data-store-icon] { + @include focus-ring; + + background-color: var(--bg-secondary-light); + } + } +} + [data-store-quantity-selector] { display: flex; flex-direction: row; @@ -35,6 +66,8 @@ border: 0; border-radius: var(--border-radius-default); + @include quantity-selector-focus-ring; + [data-store-icon] { display: flex; align-items: center; @@ -51,14 +84,6 @@ cursor: not-allowed; [data-store-icon] { color: var(--color-border-input-disabled); } } - - &:focus-visible { - outline: none; - - [data-store-icon] { - box-shadow: inset 0 0 0 var(--border-width-1) var(--color-border-input-selected); - } - } } &:hover:not([data-store-quantity-selector="disabled"]) { diff --git a/src/components/ui/SkuSelector/sku-selector.scss b/src/components/ui/SkuSelector/sku-selector.scss index 4b1f3b1f0..438092579 100644 --- a/src/components/ui/SkuSelector/sku-selector.scss +++ b/src/components/ui/SkuSelector/sku-selector.scss @@ -1,5 +1,26 @@ @import "../../../styles/utilities.scss"; +@mixin sku-selector-focus-ring { + @media not all and (min-resolution: .001dpcm) { // Target only Safari browsers + @supports (-webkit-appearance:none) { + // Use `focus` instead of `focus-visible` due to Safari's lack of support + &:focus + span { + border-color: var(--color-border-input-selected); + border-width: var(--border-width-1); + + @include focus-ring; + } + } + } + + &:focus-visible + span { + border-color: var(--color-border-input-selected); + border-width: var(--border-width-1); + + @include focus-ring; + } +} + [data-store-sku-selector] { display: flex; flex-wrap: wrap; @@ -37,12 +58,7 @@ height: 100%; opacity: 0; - &:focus-visible + span { - border-color: var(--color-border-input-selected); - border-width: var(--border-width-1); - - @include focus-ring; - } + @include sku-selector-focus-ring; &:hover:not(:disabled):not(:checked) + span { border-color: var(--color-border-input-selected); diff --git a/src/styles/pages/product-listing.scss b/src/styles/pages/product-listing.scss index 13fc01e20..7eec64d98 100644 --- a/src/styles/pages/product-listing.scss +++ b/src/styles/pages/product-listing.scss @@ -2,6 +2,7 @@ .product-listing { padding-top: 0; + --product-listing-row-height: var(--space-6); @include media(">=notebook") { padding-top: var(--page-padding-notebook); @@ -35,6 +36,7 @@ @include media(">=notebook") { display: grid; grid-template-columns: repeat(12, 1fr); + grid-templat-rows: var(--product-listing-row-height) auto; padding-right: var(--page-padding-notebook); padding-left: var(--page-padding-notebook); column-gap: var(--space-4); @@ -49,7 +51,6 @@ grid-row: span 2; grid-column: 1 / span 3; align-self: start; - padding-top: var(--space-1); } } diff --git a/src/styles/utilities.scss b/src/styles/utilities.scss index f2ca8e2b4..b936524c9 100644 --- a/src/styles/utilities.scss +++ b/src/styles/utilities.scss @@ -14,22 +14,42 @@ $base: 16px !default; @return #{$rem}rem; } -@mixin button-focus-ring { - outline: none; - box-shadow: 0 0 0 1px var(--bg-neutral-lightest), 0 0 0 var(--border-width-2) var(--bg-focus-ring); -} - @mixin input-focus-ring { - border-color: var(--color-border-input-selected); - outline: none; - box-shadow: - 0 0 0 1px var(--bg-neutral-lightest), - 0 0 0 var(--border-width-2) var(--bg-focus-ring), - inset 0 0 0 var(--border-width-0) var(--color-border-input-selected); + @media not all and (min-resolution: .001dpcm) { // Target only Safari browsers + @supports (-webkit-appearance:none) { // Use `focus` instead of `focus-visible` + &:hover:focus, + &:focus { // due to Safari's lack of support + border-color: var(--color-border-input-selected); + outline: none; + box-shadow: + 0 0 0 1px var(--bg-body), + 0 0 0 var(--border-width-2) var(--bg-focus-ring), + inset 0 0 0 var(--border-width-0) var(--color-border-input-selected); + } + } + } + + &:focus-visible, + &:hover:focus-visible { + border-color: var(--color-border-input-selected); + outline: none; + box-shadow: + 0 0 0 1px var(--bg-body), + 0 0 0 var(--border-width-2) var(--bg-focus-ring), + inset 0 0 0 var(--border-width-0) var(--color-border-input-selected); + } } -// Supports safari browsers @mixin focus-ring { outline: none; - box-shadow: 0 0 0 1px var(--bg-neutral-lightest), 0 0 0 var(--border-width-2) var(--bg-focus-ring); + box-shadow: 0 0 0 1px var(--bg-body), 0 0 0 var(--border-width-2) var(--bg-focus-ring); +} + +@mixin focus-ring-visible { + @media not all and (min-resolution: .001dpcm) { // Target only Safari browsers + @supports (-webkit-appearance:none) { // Use `focus` instead of `focus-visible` + &:focus { @include focus-ring; } // due to Safari's lack of support + } + } + &:focus-visible { @include focus-ring; } } From 96ea67b079f9ec2da962b4f709ba0dea25a5cf98 Mon Sep 17 00:00:00 2001 From: Eduardo Formiga Date: Thu, 3 Feb 2022 13:30:19 -0300 Subject: [PATCH 4/8] [FSSS-170] Chore: tweaks search page (#293) * Removes unused title * Extracts css from product-gallery section * Tweaks SROnly component * Adds SROnly h1 title to search page * Fixes typo --- .../ProductGallery/ProductGallery.tsx | 2 + .../ProductGallery/product-gallery.scss | 150 +++++++++++++++++ src/components/ui/SROnly/SROnly.tsx | 8 +- src/pages/s.tsx | 6 +- src/styles/pages/product-listing.scss | 151 +----------------- 5 files changed, 162 insertions(+), 155 deletions(-) create mode 100644 src/components/sections/ProductGallery/product-gallery.scss diff --git a/src/components/sections/ProductGallery/ProductGallery.tsx b/src/components/sections/ProductGallery/ProductGallery.tsx index 0f04c9ba8..f53dfc64e 100644 --- a/src/components/sections/ProductGallery/ProductGallery.tsx +++ b/src/components/sections/ProductGallery/ProductGallery.tsx @@ -11,6 +11,8 @@ import { import { useGalleryQuery } from './useGalleryQuery' import { useOrderedFacets } from './useOrderedFacets' +import './product-gallery.scss' + const GalleryPage = lazy(() => import('./ProductGalleryPage')) const Sort = lazy(() => import('src/components/search/Sort')) const Filter = lazy(() => import('src/components/search/Filter')) diff --git a/src/components/sections/ProductGallery/product-gallery.scss b/src/components/sections/ProductGallery/product-gallery.scss new file mode 100644 index 000000000..c82e41239 --- /dev/null +++ b/src/components/sections/ProductGallery/product-gallery.scss @@ -0,0 +1,150 @@ +@import "../../../styles/scaffold.scss"; + +.product-listing { + padding-top: 0; + --product-listing-row-height: var(--space-6); + + @include media(">=notebook") { + padding-top: var(--page-padding-notebook); + } +} + +// Temporary till we have skeletons. +.product-listing__data-loading { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + padding-top: var(--space-5); +} + +.product-listing__content-grid { + display: flex; + flex-direction: column; + padding-right: 0; + padding-left: 0; + + @include media(">=notebook") { + display: grid; + grid-template-rows: var(--product-listing-row-height) auto; + grid-template-columns: repeat(12, 1fr); + padding-right: var(--page-padding-notebook); + padding-left: var(--page-padding-notebook); + column-gap: var(--space-4); + row-gap: var(--space-0); + } +} + +.product-listing__filters { + @include media(">=notebook") { + position: sticky; + top: var(--grid-gap-0); + grid-row: span 2; + grid-column: 1 / span 3; + align-self: start; + } +} + +.product-listing__sort { + display: flex; + align-items: center; + justify-content: space-between; + order: 1; + width: 100%; + min-height: rem(68px); + padding: var(--space-1) var(--space-3) var(--space-2); + background-color: var(--bg-neutral-lightest); + + @include media(">=notebook") { + grid-column: 6 / span 7; + justify-content: flex-end; + order: unset; + min-height: initial; + padding: 0; + } +} + +.product-listing__results-count { + display: flex; + align-items: center; + justify-content: center; + order: 2; + min-height: rem(45px); + padding: var(--space-2) var(--space-3); + background-color: var(--bg-neutral-light); + + @include media(">=notebook") { + grid-column: 4 /span 2; + justify-content: left; + order: unset; + min-height: initial; + padding: 0; + background-color: unset; + } +} + +.product-listing__results { + --padding: var(--space-1); + + order: 3; + padding: var(--padding) var(--padding) 0; + background-color: var(--bg-neutral-light); + + @include media(">=notebook") { + grid-column: 4 / span 9; + order: unset; + padding: 0; + background-color: unset; + } + + .product-card[data-store-card] { min-width: 100%; } +} + +.product-listing__results-sponsored { + margin: var(--space-1) calc(-1 * var(--padding)); + padding: var(--space-4) var(--space-3); + background-color: var(--bg-neutral-lightest); + + @include media(">=notebook") { + margin: var(--space-6) 0; + padding: 0; + + [data-store-tiles] { + column-gap: var(--grid-gap-0); + row-gap: 0; + } + } + + h3 { margin-bottom: var(--space-1); } +} + +.product-listing__pagination { + display: flex; + align-items: center; + justify-content: center; + min-height: var(--space-13); + margin-right: calc(-1 * var(--padding)); + margin-left: calc(-1 * var(--padding)); + padding: var(--space-4); + background-color: var(--bg-neutral-lightest); + + @include media(">=notebook") { + padding: var(--space-1) var(--space-2); + } + + &--top { + margin-bottom: var(--padding); + } + + &--bottom { + margin-top: var(--padding); + } + + [data-store-button] { + width: 100%; + + @include media(">=notebook") { + width: fit-content; + } + } +} diff --git a/src/components/ui/SROnly/SROnly.tsx b/src/components/ui/SROnly/SROnly.tsx index 918b13f50..8756c9cb2 100644 --- a/src/components/ui/SROnly/SROnly.tsx +++ b/src/components/ui/SROnly/SROnly.tsx @@ -1,13 +1,17 @@ +import type { ElementType } from 'react' import React from 'react' import './sr-only.scss' interface Props { text: string + as?: ElementType } -function SROnly({ text }: Props) { - return {text} +function SROnly({ text, as }: Props) { + const Component = as ?? 'span' + + return {text} } export default SROnly diff --git a/src/pages/s.tsx b/src/pages/s.tsx index f7d84c0b4..40566d26a 100644 --- a/src/pages/s.tsx +++ b/src/pages/s.tsx @@ -10,6 +10,7 @@ import type { SearchPageQueryQueryVariables, } from '@generated/graphql' import { GatsbySeo } from 'gatsby-plugin-next-seo' +import SROnly from 'src/components/ui/SROnly' export type Props = PageProps< SearchPageQueryQuery, @@ -26,7 +27,7 @@ function Page(props: Props) { const { locale } = useSession() const searchParams = useSearchParams(props.location) - const title = site?.siteMetadata?.title ?? '' + const title = 'Search Results | FastStore' if (!searchParams) { return null @@ -56,8 +57,7 @@ function Page(props: Props) { Sections: Components imported from '../components/sections' only. Do not import or render components from any other folder in here. */} -

{title}

- + ) diff --git a/src/styles/pages/product-listing.scss b/src/styles/pages/product-listing.scss index 7eec64d98..287798bb4 100644 --- a/src/styles/pages/product-listing.scss +++ b/src/styles/pages/product-listing.scss @@ -1,163 +1,14 @@ -@import "../scaffold.scss"; - -.product-listing { - padding-top: 0; - --product-listing-row-height: var(--space-6); - - @include media(">=notebook") { - padding-top: var(--page-padding-notebook); - } -} +@import "../vendors/include-media"; .product-listing__breadcrumb { padding-top: var(--space-3); padding-bottom: var(--space-3); } -// Temporary till we have skeletons. -.product-listing__data-loading { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - padding-top: var(--space-5); -} - .product-listing__hero { width: 100%; } -.product-listing__content-grid { - display: flex; - flex-direction: column; - padding-right: 0; - padding-left: 0; - - @include media(">=notebook") { - display: grid; - grid-template-columns: repeat(12, 1fr); - grid-templat-rows: var(--product-listing-row-height) auto; - padding-right: var(--page-padding-notebook); - padding-left: var(--page-padding-notebook); - column-gap: var(--space-4); - row-gap: var(--space-0); - } -} - -.product-listing__filters { - @include media(">=notebook") { - position: sticky; - top: var(--grid-gap-0); - grid-row: span 2; - grid-column: 1 / span 3; - align-self: start; - } -} - -.product-listing__sort { - display: flex; - align-items: center; - justify-content: space-between; - order: 1; - width: 100%; - min-height: rem(68px); - padding: var(--space-1) var(--space-3) var(--space-2); - background-color: var(--bg-neutral-lightest); - - @include media(">=notebook") { - grid-column: 6 / span 7; - justify-content: flex-end; - order: unset; - min-height: initial; - padding: 0; - } -} - -.product-listing__results-count { - display: flex; - align-items: center; - justify-content: center; - order: 2; - min-height: rem(45px); - padding: var(--space-2) var(--space-3); - background-color: var(--bg-neutral-light); - - @include media(">=notebook") { - grid-column: 4 /span 2; - justify-content: left; - order: unset; - min-height: initial; - padding: 0; - background-color: unset; - } -} - -.product-listing__results { - --padding: var(--space-1); - - order: 3; - padding: var(--padding) var(--padding) 0; - background-color: var(--bg-neutral-light); - - @include media(">=notebook") { - grid-column: 4 / span 9; - order: unset; - padding: 0; - background-color: unset; - } - - .product-card[data-store-card] { min-width: 100%; } -} - -.product-listing__results-sponsored { - margin: var(--space-1) calc(-1 * var(--padding)); - padding: var(--space-4) var(--space-3); - background-color: var(--bg-neutral-lightest); - - @include media(">=notebook") { - margin: var(--space-6) 0; - padding: 0; - - [data-store-tiles] { - column-gap: var(--grid-gap-0); - row-gap: 0; - } - } - - h3 { margin-bottom: var(--space-1); } -} - -.product-listing__pagination { - display: flex; - align-items: center; - justify-content: center; - min-height: var(--space-13); - margin-right: calc(-1 * var(--padding)); - margin-left: calc(-1 * var(--padding)); - padding: var(--space-4); - background-color: var(--bg-neutral-lightest); - - @include media(">=notebook") { - padding: var(--space-1) var(--space-2); - } - - &--top { - margin-bottom: var(--padding); - } - - &--bottom { - margin-top: var(--padding); - } - - [data-store-button] { - width: 100%; - - @include media(">=notebook") { - width: fit-content; - } - } -} - .product-listing__scroll-top { display: flex; justify-content: center; From ee340801a79ff5611a755fea37da4bd74804c3cb Mon Sep 17 00:00:00 2001 From: Heitor Carvalho Date: Thu, 3 Feb 2022 21:50:02 -0300 Subject: [PATCH 5/8] [FSSS-164] Extract UISelect from Sort to its own component (#299) * Extract UISelect from Sort to its own component * Rename data-ui-select to data-select * Change attribute className to classes * Remove whitespace * Remove aria-label property from Sort * Make 'id' a required attribute for Select * Change 'SelectOptions' type to Record * Use className attribute instead of classes Co-authored-by: Fanny Chien --- src/components/search/Sort/Sort.tsx | 31 ++++------ src/components/ui/Select/Select.tsx | 56 +++++++++++++++++++ src/components/ui/Select/index.tsx | 1 + .../Sort/sort.scss => ui/Select/select.scss} | 2 +- 4 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 src/components/ui/Select/Select.tsx create mode 100644 src/components/ui/Select/index.tsx rename src/components/{search/Sort/sort.scss => ui/Select/select.scss} (98%) diff --git a/src/components/search/Sort/Sort.tsx b/src/components/search/Sort/Sort.tsx index 9c228fbbf..24ff7dfe8 100644 --- a/src/components/search/Sort/Sort.tsx +++ b/src/components/search/Sort/Sort.tsx @@ -1,9 +1,6 @@ import { useSearch } from '@faststore/sdk' import React from 'react' -import { Select as UISelect } from '@faststore/ui' -import { CaretDown as CaretDownIcon } from 'phosphor-react' - -import './sort.scss' +import Select from 'src/components/ui/Select' const OptionsMap = { price_desc: 'Price, descending', @@ -25,23 +22,15 @@ function Sort() { } = useSearch() return ( -
- - setSort(keys[e.target.selectedIndex])} - value={sort} - aria-label="Product Sort" - id="select-sort" - > - {keys.map((key) => ( - - ))} - - -
+