diff --git a/docs/TEMPLATES_CONFIG.md b/docs/TEMPLATES_CONFIG.md index 36cb71cbc..dc057d582 100644 --- a/docs/TEMPLATES_CONFIG.md +++ b/docs/TEMPLATES_CONFIG.md @@ -15,7 +15,7 @@ Snap templates is entirely configuration based. The configuration defines which | `autocomplete` | Autocomplete feature target declarations | | `recommendation` | Recommendation feature target declarations | -Here is a minimal example starting configuration to enable search and autocomplete using the `bocachica` theme. +Here is a minimal example starting configuration to enable search and autocomplete using the `pike` theme. ```jsx import { SnapTemplates } from '@athoscommerce/snap-preact'; @@ -27,7 +27,7 @@ new SnapTemplates({ currency: 'usd', }, theme: { - extends: 'bocachica', + extends: 'pike', }, search: { targets: [ diff --git a/docs/TEMPLATES_THEMING.md b/docs/TEMPLATES_THEMING.md index 27c8f648d..00f0f7cfd 100644 --- a/docs/TEMPLATES_THEMING.md +++ b/docs/TEMPLATES_THEMING.md @@ -5,7 +5,7 @@ Theming in Snap Templates is the primary method of customizing a template. A the new SnapTemplates({ ... theme: { - extends: 'bocachica', + extends: 'base', styles: globalStyles, resultComponent: 'Result', variables: { ... }, @@ -61,7 +61,7 @@ Each theme will have a common set of shared variables (ie. colors and breakpoint new SnapTemplates({ ... theme: { - extends: 'bocachica', + extends: 'base', variables: { breakpoints: { mobile: 768, tablet: 1024, desktop: 1280 }, colors: { @@ -96,7 +96,7 @@ const globalStyles = (theme) => { new SnapTemplates({ ... theme: { - extends: 'bocachica', + extends: 'base', style: globalStyles, }, ... @@ -120,7 +120,7 @@ import { css } from '@emotion/react'; new SnapTemplates({ ... theme: { - extends: 'bocachica', + extends: 'base', overrides: { default: { image: { @@ -153,7 +153,7 @@ Here's an example that demonstrates targeting specific subcomponents: new SnapTemplates({ ... theme: { - extends: 'bocachica', + extends: 'base', overrides: { default: { 'carousel icon.next': { @@ -191,7 +191,7 @@ In the following example, the number of columns for the `search results` compone new SnapTemplates({ ... theme: { - extends: 'bocachica', + extends: 'base', overrides: { default: { 'search results': { diff --git a/package-lock.json b/package-lock.json index 6fd82af38..4a3bd915a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10170,6 +10170,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -10187,6 +10188,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -10204,6 +10206,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -10221,6 +10224,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -10238,6 +10242,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -10255,6 +10260,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -10272,6 +10278,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -10289,6 +10296,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -10306,6 +10314,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -10323,6 +10332,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -17177,31 +17187,6 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", diff --git a/packages/snap-preact-demo/public/snap/bundle.html b/packages/snap-preact-demo/public/snap/bundle.html index d30f9d9da..9d4db2366 100644 --- a/packages/snap-preact-demo/public/snap/bundle.html +++ b/packages/snap-preact-demo/public/snap/bundle.html @@ -1,231 +1,284 @@ - - + + - + + + + Product Detail Page - - - - - - - - - - + - - -
-
- -
- - -
- -
-
-
- -
-
-
-
- -
- - -
-
- - + - + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/cart.html b/packages/snap-preact-demo/public/snap/cart.html index 1bb3127f3..b8b13b2e4 100644 --- a/packages/snap-preact-demo/public/snap/cart.html +++ b/packages/snap-preact-demo/public/snap/cart.html @@ -1,262 +1,300 @@ - - + + - - Cart Page - - - - - - - - - + + +
+
+ Skip to main content + +
+
+ +
+
+
+ + + + +
+
+
+
+ +
+
+ +
+
+
+ + +
+
+
- -
-
-
- -
-
-
-
+
+
+
+
+

Total price: $84.00

- -
+
+
+ +
-
-
-
-
-
-

Total price: $84.00

-
-
-
-
-
-
-
-

Stripe Out White Off-The-Shoulder Dress

-
-
$48.00
-
-
-
-
-
-
-
-
-
-
-

Answer To Your Layers Butterscotch Yellow Top

-
-
$36.00
-
-
-
- -
-
- -
+
+
+

Stripe Out White Off-The-Shoulder Dress

+
+
$48.00
+
+ + +
+
+
- -
- +
+
+ +
-
- - + - - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/images-logo-stacked.svg b/packages/snap-preact-demo/public/snap/images-logo-stacked.svg new file mode 100644 index 000000000..e753a7fc3 --- /dev/null +++ b/packages/snap-preact-demo/public/snap/images-logo-stacked.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/images-logo.svg b/packages/snap-preact-demo/public/snap/images-logo.svg new file mode 100644 index 000000000..8ef58ba7f --- /dev/null +++ b/packages/snap-preact-demo/public/snap/images-logo.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/index.html b/packages/snap-preact-demo/public/snap/index.html index da3e762c8..bd377e900 100644 --- a/packages/snap-preact-demo/public/snap/index.html +++ b/packages/snap-preact-demo/public/snap/index.html @@ -1,236 +1,237 @@ - - + - + + + + Search Results - - - - - - - - - - - - - + - - - - Skip to main content - -
-
-
-
+
+
+
+
+
+
    +
  • Home
  • +
  • + + + + + +
  • +
  • Search results
  • +
+
+
-
-
-
-
    -
  • Home
  • -
  • -
  • Search Results
  • -
+
+ + +
+
+

Content to be hidden!

+
+
+
+
+
-
- +
- -
-
-

Content to be hidden!

+ + -
-
- - - - - - - + +
+
+

Login

+ +
- -
- - - - - - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/order.html b/packages/snap-preact-demo/public/snap/order.html index 1f8cdf5c4..43111e812 100644 --- a/packages/snap-preact-demo/public/snap/order.html +++ b/packages/snap-preact-demo/public/snap/order.html @@ -1,233 +1,255 @@ - - + + - - Order Confirmation - - - - - - - - - - + - - -
-
- -
- - -
- -
-
-
-
-
-
-

Order Confirmation

-
    -
  • C-BP-G7-B1469, qty: 1, price: 22
  • -
  • C-VJ-P2-32007, qty: 1, price: 39
  • -
- Total price: $61.00 -
-
-
- -
-
-
- - - - + + + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/product.html b/packages/snap-preact-demo/public/snap/product.html index d7706a81b..a04716dc5 100644 --- a/packages/snap-preact-demo/public/snap/product.html +++ b/packages/snap-preact-demo/public/snap/product.html @@ -1,242 +1,295 @@ - - + + - + + + + Product Detail Page - - - - - - - - - - + - - -
-
- -
- - -
- -
-
-
- -
-
-
-
- -
- -
- - -
-
- - - - + + + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/recommendations.html b/packages/snap-preact-demo/public/snap/recommendations.html index db5681446..050d136a7 100644 --- a/packages/snap-preact-demo/public/snap/recommendations.html +++ b/packages/snap-preact-demo/public/snap/recommendations.html @@ -1,248 +1,299 @@ - - + + - + + + + Product Detail Page - - - - - - - - - - + + +
+
+ Skip to main content + +
+
+ +
+
+
+ + + + +
+
+
+
+ +
+
+ +
+
+
+ + +
+
+
- -
- - - -
- -
-
-
- -
-
-
-
- -
- -
stuff...
- - +
+
+
+
+
+
    +
  • Home
  • +
  • + + + + + +
  • +
  • Stripe Out White Off-The-Shoulder Dress
  • +
+
+
+ +
+

Stripe Out White Off-The-Shoulder Dress

+
+ +
+
+
+
+ +
+ Stripe Out White Off-The-Shoulder Dress +
+
+
+ +
+
+

+ Are you Stripe Out of ideas for what to wear this weekend on that trip you've got coming up with + your friends? Afraid you'll be the odd one out and everyone else will be all cute and trendy and + there you'll be ... not trendy and wearing the same old things you've been wearing on this + annual getaway for years? Lucky for you, here's the dress you've been searching for. Doesn't + matter what else you pack (it does, you'll want to continue to shop with us, we were just being + nice) this is the piece that will set you apart from everyone else (that is absolutely true, you + will be a Goddess among women). Take that, bad fashion moments of the past! Striped dress + features 3/4 sleeve bell sleeves with a partially elastic/open back. Model is wearing a small. • + 97% Cotton 3% Spandex • Machine Wash Cold... +

+
+
+
+
+ +
+
+
+

Stripe Out White Off-The-Shoulder Dress

+
+

+ $50.00 + $48.00 +

+ +
+
+
+
- +
+
stuff...
- -
-
+ - - - + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/website.css b/packages/snap-preact-demo/public/snap/website.css index 5921c38c9..b40bd018e 100644 --- a/packages/snap-preact-demo/public/snap/website.css +++ b/packages/snap-preact-demo/public/snap/website.css @@ -1,774 +1,1742 @@ -/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ +/* NORMALIZE +========================================================================== */ + +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document - ========================================================================== */ +========================================================================== */ /** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in iOS. - */ +* 1. Correct the line height in all browsers. +* 2. Prevent adjustments of font size after orientation changes in iOS. +*/ html { - line-height: 1.15; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ } + line-height: 1.15; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ +} /* Sections - ========================================================================== */ +========================================================================== */ /** - * Remove the margin in all browsers. - */ +* Remove the margin in all browsers. +*/ body { - margin: 0; } + margin: 0; +} + +/** +* Render the `main` element consistently in IE. +*/ +main { + display: block; +} /** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ +* Correct the font size and margin on `h1` elements within `section` and +* `article` contexts in Chrome, Firefox, and Safari. +*/ h1 { - font-size: 2em; - margin: 0.67em 0; } + font-size: 2em; + margin: 0.67em 0; +} /* Grouping content - ========================================================================== */ +========================================================================== */ /** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ +* 1. Add the correct box sizing in Firefox. +* 2. Show the overflow in Edge and IE. +*/ hr { - box-sizing: content-box; - /* 1 */ - height: 0; - /* 1 */ - overflow: visible; - /* 2 */ } + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ +} /** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ +* 1. Correct the inheritance and scaling of font size in all browsers. +* 2. Correct the odd `em` font sizing in all browsers. +*/ pre { - font-family: monospace, monospace; - /* 1 */ - font-size: 1em; - /* 2 */ } + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} /* Text-level semantics - ========================================================================== */ +========================================================================== */ /** - * Remove the gray background on active links in IE 10. - */ +* Remove the gray background on active links in IE 10. +*/ a { - background-color: transparent; } + background-color: transparent; +} /** - * 1. Remove the bottom border in Chrome 57- - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ +* 1. Remove the bottom border in Chrome 57- +* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. +*/ abbr[title] { - border-bottom: none; - /* 1 */ - text-decoration: underline; - /* 2 */ - text-decoration: underline dotted; - /* 2 */ } + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ +} /** - * Add the correct font weight in Chrome, Edge, and Safari. - */ -b, -strong { - font-weight: bolder; } +* Add the correct font weight in Chrome, Edge, and Safari. +*/ +b, strong { + font-weight: bolder; +} /** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ -code, -kbd, -samp { - font-family: monospace, monospace; - /* 1 */ - font-size: 1em; - /* 2 */ } +* 1. Correct the inheritance and scaling of font size in all browsers. +* 2. Correct the odd `em` font sizing in all browsers. +*/ +code, kbd, samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} /** - * Add the correct font size in all browsers. - */ +* Add the correct font size in all browsers. +*/ small { - font-size: 80%; } + font-size: 80%; +} /** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; } +* Prevent `sub` and `sup` elements from affecting the line height in +* all browsers. +*/ +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} sub { - bottom: -0.25em; } + bottom: -0.25em; +} sup { - top: -0.5em; } + top: -0.5em; +} /* Embedded content - ========================================================================== */ +========================================================================== */ /** - * Remove the border on images inside links in IE 10. - */ +* Remove the border on images inside links in IE 10. +*/ img { - border-style: none; } + border-style: none; +} /* Forms - ========================================================================== */ +========================================================================== */ /** - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - line-height: 1.15; - /* 1 */ - margin: 0; - /* 2 */ } +* 1. Change the font styles in all browsers. +* 2. Remove the margin in Firefox and Safari. +*/ +button, input, optgroup, select, textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} /** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ -button, -input { - /* 1 */ - overflow: visible; } +* Show the overflow in IE. +* 1. Show the overflow in Edge. +*/ +button, input { + overflow: visible; /* 1 */ +} /** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ -button, -select { - /* 1 */ - text-transform: none; } +* Remove the inheritance of text transform in Edge, Firefox, and IE. +* 1. Remove the inheritance of text transform in Firefox. +*/ +button, select { + text-transform: none; /* 1 */ +} /** - * Correct the inability to style clickable types in iOS and Safari. - */ -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; } +* Correct the inability to style clickable types in iOS and Safari. +*/ +button, [type=button], [type=reset], [type=submit] { + -webkit-appearance: button; +} /** - * Remove the inner border and padding in Firefox. - */ -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; } +* Remove the inner border and padding in Firefox. +*/ +button::-moz-focus-inner, [type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner { + border-style: none; + padding: 0; +} /** - * Restore the focus styles unset by the previous rule. - */ -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; } +* Restore the focus styles unset by the previous rule. +*/ +button:-moz-focusring, [type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring { + outline: 1px dotted ButtonText; +} /** - * Correct the padding in Firefox. - */ +* Correct the padding in Firefox. +*/ fieldset { - padding: 0.35em 0.75em 0.625em; } + padding: 0.35em 0.75em 0.625em; +} /** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ +* 1. Correct the text wrapping in Edge and IE. +* 2. Correct the color inheritance from `fieldset` elements in IE. +* 3. Remove the padding so developers are not caught out when they zero out +* `fieldset` elements in all browsers. +*/ legend { - /* 1 */ - color: inherit; - /* 2 */ - display: table; - /* 1 */ - max-width: 100%; - /* 1 */ - padding: 0; - /* 3 */ - white-space: normal; - /* 1 */ } + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} /** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ +* Add the correct vertical alignment in Chrome, Firefox, and Opera. +*/ progress { - vertical-align: baseline; } + vertical-align: baseline; +} /** - * Remove the default vertical scrollbar in IE 10+. - */ +* Remove the default vertical scrollbar in IE 10+. +*/ textarea { - overflow: auto; } + overflow: auto; +} /** - * 1. Add the correct box sizing in IE 10. - * 2. Remove the padding in IE 10. - */ -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; - /* 1 */ - padding: 0; - /* 2 */ } +* 1. Add the correct box sizing in IE 10. +* 2. Remove the padding in IE 10. +*/ +[type=checkbox], +[type=radio] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} /** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; } +* Correct the cursor style of increment and decrement buttons in Chrome. +*/ +[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button { + height: auto; +} /** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ -[type="search"] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ } +* 1. Correct the odd appearance in Chrome and Safari. +* 2. Correct the outline style in Safari. +*/ +[type=search] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} /** - * Remove the inner padding in Chrome and Safari on macOS. - */ -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } +* Remove the inner padding in Chrome and Safari on macOS. +*/ +[type=search]::-webkit-search-decoration { + -webkit-appearance: none; +} /** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ +* 1. Correct the inability to style clickable types in iOS and Safari. +* 2. Change font properties to `inherit` in Safari. +*/ ::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ } + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} /* Interactive - ========================================================================== */ +========================================================================== */ /* - * Add the correct display in Edge, IE 10+, and Firefox. - */ +* Add the correct display in Edge, IE 10+, and Firefox. +*/ details { - display: block; } + display: block; +} /* - * Add the correct display in all browsers. - */ +* Add the correct display in all browsers. +*/ summary { - display: list-item; } + display: list-item; +} /* Misc - ========================================================================== */ +========================================================================== */ /** - * Add the correct display in IE 10+. - */ +* Add the correct display in IE 10+. +*/ template { - display: none; } + display: none; +} /** - * Add the correct display in IE 10. - */ +* Add the correct display in IE 10. +*/ [hidden] { - display: none; } + display: none; +} -/* Base Styles -============================================== */ +/* DEMO - BASE STYLES +========================================================================== */ + +*, *:before, *:after { + box-sizing: border-box; +} html, body { - min-height: 100%; } + height: 100%; + min-height: 100%; +} html { - font-size: 16px; } + font-size: 16px; +} body { - height: 100%; - -webkit-print-color-adjust: exact; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - backface-visibility: hidden; - background-attachment: fixed; - font-family: 'Roboto', Helvetica, Arial; - font-size: 14px; - line-height: 1.5; - color: #3f3e40; } + height: 100%; + -webkit-print-color-adjust: exact; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + backface-visibility: hidden; + background-attachment: fixed; + font-size: 14px; + line-height: 1.5; +} img { - max-width: 100%; - width: auto; - height: auto; - display: block; } + max-width: 100%; + width: auto; + height: auto; + display: block; +} a { - color: #4c3ce2; - text-decoration: none; } - a:hover { - color: #3f3e40; } + text-decoration: none; +} ul { - list-style: none; - padding: 0; } + list-style: none; + padding: 0; +} h1, h2, h3, h4, h5, h6, p, ul { - margin: 0 0 20px 0; } - -h1, h2, h3, h4, h5, h6, .ss-lite-title { - font-weight: 700; - font-family: 'Roboto', Helvetica, Arial; } + margin: 0 0 20px 0; +} h1 { - font-size: 26px; } + font-size: 28px; +} h2 { - font-size: 24px; } + font-size: 26px; +} h3 { - font-size: 22px; } + font-size: 22px; +} h4 { - font-size: 20px; } + font-size: 20px; +} h5, h6 { - font-size: 18px; } + font-size: 18px; +} -hr { - border: 0; - border-top: 1px solid #ebebeb; } +.ss__demo { + height: 100%; +} + +.ss__demo .ss__demo__main { + min-height: 400px; +} + +.ss__demo .ss__demo__theme .ss__demo__pointer { + cursor: pointer; +} + +.ss__demo .ss__demo__theme .ss__demo__icon { + -webkit-flex-flow: column nowrap; + flex-flow: column nowrap; + display: -webkit-inline-flex; + display: -ms-inline-flex; + display: -moz-inline-flex; + display: inline-flex; + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; + -moz-flex: 0 0 auto; + flex: 0 0 auto; + width: 16px; + height: 16px; + line-height: 16px; +} + +.ss__demo .ss__demo__theme .ss__demo__icon .ss__icon { + margin: auto; + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; + line-height: 1; + fill: currentColor; +} + +/* DEMO - TYPOGRAPHY +========================================================================== */ + +.ss__pike { + font-family: "Roboto", Helvetica, Arial; +} + +.ss__pike .ss__demo .ss__demo__theme { + color: #515151; +} + +.ss__pike h1, .ss__pike h2, +.ss__pike h3, .ss__pike h4, +.ss__pike h5, .ss__pike h6 { + font-family: "Roboto", Helvetica, Arial; + font-weight: 700; +} + +.ss__pike .ss__demo .ss__demo__theme h1, .ss__pike .ss__demo .ss__demo__theme h2, +.ss__pike .ss__demo .ss__demo__theme h3, .ss__pike .ss__demo .ss__demo__theme h4, +.ss__pike .ss__demo .ss__demo__theme h5, .ss__pike .ss__demo .ss__demo__theme h6 { + color: #1d4990; +} + +.ss__everest { + font-family: "Source Sans 3", Helvetica, Arial; +} + +.ss__everest .ss__demo .ss__demo__theme a:hover { + color: #515151; +} + +.ss__everest h1, .ss__everest h2, +.ss__everest h3, .ss__everest h4, +.ss__everest h5, .ss__everest h6 { + font-family: "Montserrat", Helvetica, Arial; + font-weight: 600; + text-transform: uppercase; +} + +.ss__everest .ss__demo .ss__demo__theme h1, .ss__everest .ss__demo .ss__demo__theme h2, +.ss__everest .ss__demo .ss__demo__theme h3, .ss__everest .ss__demo .ss__demo__theme h4, +.ss__everest .ss__demo .ss__demo__theme h5, .ss__everest .ss__demo .ss__demo__theme h6 { + color: #94280b; +} + +.ss__matterhorn { + font-family: "Poppins", Helvetica, Arial; +} + +.ss__matterhorn .ss__demo .ss__demo__theme { + color: #555555; +} + +.ss__matterhorn h1, .ss__matterhorn h2, +.ss__matterhorn h3, .ss__matterhorn h4, +.ss__matterhorn h5, .ss__matterhorn h6 { + font-family: "Lora", "Times New Roman", serif; + font-weight: 300; + font-style: italic; +} + +.ss__matterhorn .ss__demo .ss__demo__theme h1, .ss__matterhorn .ss__demo .ss__demo__theme h2, +.ss__matterhorn .ss__demo .ss__demo__theme h3, .ss__matterhorn .ss__demo .ss__demo__theme h4, +.ss__matterhorn .ss__demo .ss__demo__theme h5, .ss__matterhorn .ss__demo .ss__demo__theme h6 { + color: #222222; +} + +/* DEMO - FORM FIELDS +========================================================================== */ + +input, button, select { + padding: 0; + margin: 0; + border: 0; +} + +input, .ss__demo__button, select { + height: 40px; + line-height: 40px; + padding: 0 20px; +} -/* Form fields -============================================== */ input::-webkit-input-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input:-moz-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input::-moz-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input:-ms-input-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input :focus::-webkit-input-placeholder { - color: #3f3e40; } - -input :focus:-moz-placeholder { - color: #3f3e40; } - -input :focus::-moz-placeholder { - color: #3f3e40; } - -input :focus:-ms-input-placeholder { - color: #3f3e40; } - -input[type='text'], button { - border: 0; - line-height: 1; } + -webkit-transition: color 0.3s ease-in-out; + -o-transition: color 0.3s ease-in-out; + -ms-transition: color 0.3s ease-in-out; + -moz-transition: color 0.3s ease-in-out; + transition: color 0.3s ease-in-out; +} + +input::-ms-input-placeholder { + -webkit-transition: color 0.3s ease-in-out; + -o-transition: color 0.3s ease-in-out; + -ms-transition: color 0.3s ease-in-out; + -moz-transition: color 0.3s ease-in-out; + transition: color 0.3s ease-in-out; +} + +input::placeholder { + -webkit-transition: color 0.3s ease-in-out; + -o-transition: color 0.3s ease-in-out; + -ms-transition: color 0.3s ease-in-out; + -moz-transition: color 0.3s ease-in-out; + transition: color 0.3s ease-in-out; +} button { - padding: 7px 20px; - color: #ffffff; - background: #3a23ad; - font-size: 18px; - border: none; - font-weight: bold; - cursor: pointer; } - button:hover { - color: white; - background: #4e37c1; } - -input[type='text'] { - color: #3f3e40; - padding: 10px; - box-sizing: border-box; - min-height: 40px; } - -/* Layout -============================================== */ -.ss-lite-wrapper { - margin: 0 auto; - padding: 0 20px; - max-width: 1200px; - width: auto; } - -.ss-lite-flex-wrap, .ss-lite-flex-wrap-center { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row wrap; - -ms-flex-flow: row wrap; - flex-flow: row wrap; } - -.ss-lite-flex-nowrap, .ss-lite-flex-nowrap-center { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row nowrap; - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; } - -.ss-lite-flex-wrap-center, .ss-lite-flex-nowrap-center { - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - -ms-grid-row-align: center; - align-items: center; } - -.ss-lite-row-5 { - margin: 0 -5px; } - .ss-lite-row-5 > .ss-lite-col { - padding: 0 5px; } - -.ss-lite-row-10 { - margin: 0 -10px; } - .ss-lite-row-10 > .ss-lite-col { - padding: 0 10px; } - -.ss-lite-row-20 { - margin: 0 -20px; } - .ss-lite-row-20 > .ss-lite-col { - padding: 0 20px; } - -.clear { - clear: both; } - -/* Faded background -============================================== */ -.ss-lite-header { - background-color: #f8f8f8; } - .ss-lite-header, .ss-lite-header .ss-lite-wrapper { - position: relative; } - .ss-lite-header .ss-lite-wrapper { - padding: 20px; } - -/* Header -============================================== */ -.ss-lite-header .ss-lite-subheader { - text-transform: uppercase; - color: #00cee1; } - -.ss-lite-header .ss-lite-icon { - font-size: 20px; - color: #4c3ce2; } - -.ss-lite-header .ss-lite-header-logo { - width: 250px; } - .ss-lite-header .ss-lite-header-logo .st0 { - fill: url(#SVGID_1_); } - .ss-lite-header .ss-lite-header-logo .st1 { - fill: url(#SVGID_2_); } - .ss-lite-header .ss-lite-header-logo .st2 { - fill: #515151; } - .ss-lite-header .ss-lite-header-logo a { - text-align: right; - display: block; - line-height: 0; } - .ss-lite-header .ss-lite-header-logo svg { - max-width: 100%; } - -.ss-lite-header .ss-lite-header-buttons { - width: 840px; - margin: 0 0 0 auto; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar { - -webkit-box-flex: 1; - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - position: relative; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar .ss-lite-input[type='text'] { - border: 1px solid #ebebeb; - width: 100%; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar .ss-lite-input[type='text']::placeholder { - color: #c9c9c9; - font-weight: 100; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar .ss-lite-button { - background-color: transparent; - padding: 0; - position: absolute; - top: 0; - bottom: 0; - right: 10px; - margin: auto; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons { - margin: 0 0 0 15px; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons a { - position: relative; - padding: 0 5px; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons .ss-lite-cart-count { - position: absolute; - top: 6px; - right: -6px; - color: #ffffff; - font-size: 12px; - font-weight: bold; - width: 20px; - height: 20px; - line-height: 20px; - text-align: center; - display: inline-block; - background: #00cee1; - border-radius: 100%; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons .ss-lite-cart-count:hover { - color: white; - background: #4e37c1; } - -/* Navigation -============================================== */ -.ss-lite-navigation { - background-color: #3a23ad; - border-top: 5px solid #4c3ce2; } - .ss-lite-navigation .ss-lite-list { - margin: 0 -20px -10px -20px; - text-align: center; } - .ss-lite-navigation .ss-lite-list li { - display: inline-block; - zoom: 1; - *display: inline; - vertical-align: middle; - padding: 0 20px 10px 20px; } - .ss-lite-navigation .ss-lite-list li a { - color: #ffffff; - font-size: 16px; - font-weight: bold; - text-transform: uppercase; } - .ss-lite-navigation .ss-lite-list li a.active { - border-bottom: 2px solid #00cee1; } - .ss-lite-navigation .ss-lite-list li a:hover { - color: #00cee1; } - -/* Main -============================================== */ - -.ss-lite-main { - flex: 1; - min-height: 500px; - padding: 40px 0; } - -.ss-lite-breadcrumbs .ss-lite-list { - margin: 0 -5px 40px -5px; } - .ss-lite-breadcrumbs .ss-lite-list li { - padding: 0 5px; - display: inline-block; - zoom: 1; - *display: inline; - vertical-align: middle; } - -.ss-lite-main-layout { - min-height: 600px; } - .ss-lite-main-layout .ss-lite-sidebar { - -webkit-box-flex: 0; - -webkit-flex: 0 0 250px; - -ms-flex: 0 0 250px; - flex: 0 0 250px; - max-width: 250px; - margin: 0 40px 0 0; } - .ss-lite-main-layout .ss-lite-content { - width: 100%; - min-width: 0; - } - -/* Footer -============================================== */ -.ss-lite-footer { - padding: 20px 0; - background-color: #3a23ad; - border-top: 5px solid #4c3ce2; } - .ss-lite-footer, .ss-lite-footer a, .ss-lite-footer p, .ss-lite-footer .ss-lite-title { - color: #ffffff; } - .ss-lite-footer a:hover { - color: #00cee1; } - .ss-lite-footer .ss-lite-col { - -webkit-box-flex: 1; - -webkit-flex: 1 1 0%; - -ms-flex: 1 1 0%; - flex: 1 1 0%; } - .ss-lite-footer .ss-lite-col .ss-lite-title { - text-transform: uppercase; - font-size: 16px; - margin: 0 0 10px 0; - padding: 0 0 10px 0; - border-bottom: 1px solid #4c3ce2; } - .ss-lite-footer .ss-lite-col .ss-lite-title .ss-lite-icon { - margin: 0 10px 0 0; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit .ss-lite-list li { - display: inline-block; - margin-right: 10px; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit a { - display: inline-block; - zoom: 1; - *display: inline; - vertical-align: middle; - width: 30px; - height: 30px; - background: #4c3ce2; - text-align: center; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - -ms-border-radius: 100%; - -o-border-radius: 100%; - border-radius: 100%; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit a:hover { - color: #ffffff; - background-color: #00cee1; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit a i { - line-height: 30px; - font-size: 16px; } - -/* Footer Copyright -============================================== */ -.ss-lite-footer-copyright { - padding: 30px 0 0; - text-align: center; } - .ss-lite-footer-copyright p { - margin: 0; } - .ss-lite-footer-copyright p:first-child { - margin: 0 0 2.5px 0; } - -/* Responsive -============================================== */ -@media only screen and (max-width: 991px) { - .ss-lite-footer .ss-lite-col, .ss-lite-footer .ss-lite-footer-information { - -webkit-box-flex: 1; - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - width: 50%; } - .ss-lite-header > .ss-lite-wrapper > .ss-lite-flex-wrap-center { - display: block; } - .ss-lite-header .ss-lite-header-logo, .ss-lite-header .ss-lite-header-buttons { - width: auto; } - .ss-lite-header .ss-lite-header-logo { - max-width: 250px; - margin: 0 auto 20px auto; } - .ss-lite-main .ss-lite-flex-nowrap { - display: block; } - .ss-lite-main .ss-lite-flex-nowrap .ss-lite-sidebar { - display: none; } } - -@media only screen and (max-width: 767px) { - .ss-lite-navigation .ss-lite-list { - margin: 0 -10px -10px -10px; } - .ss-lite-navigation .ss-lite-list li { - padding: 0 10px 10px 10px; } - .ss-lite-navigation .ss-lite-list li a { - font-size: 14px; } } - -@media only screen and (max-width: 540px) { - .ss-lite-footer .ss-lite-flex-wrap { - display: block; } - .ss-lite-footer .ss-lite-col, .ss-lite-footer .ss-lite-footer-information { - width: auto; } } - -.ss-results-title .ss-oq { - font-size: 14px; - color: #3b23ad; - font-weight: normal; -} - -.ss-results-title .ss-oq em { - font-weight: bold; -} - -.ss-toolbar-row { - margin-bottom: 20px; + cursor: pointer; } -.ss-toolbar-col { - display: inline-block; - margin: 10px 20px 10px 0; +select { + font-size: 16px; +} + +fieldset { + border: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__button { + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.ss__demo .ss__demo__theme .ss__demo__input { + -webkit-flex-flow: row nowrap; + flex-flow: row nowrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; +} + +.ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__label, .ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__input { + min-width: 1px; +} + +.ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__label { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 125px; + margin: 0 10px 0 0; +} + +.ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__input { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; +} + +@media only screen and (min-width: 768px) { + select { + font-size: 14px; + } +} + +.ss__pike .ss__demo .ss__demo__theme input, .ss__pike .ss__demo .ss__demo__theme select, .ss__pike .ss__demo .ss__demo__theme .ss__demo__button { + -moz-border-radius: 0; + border-radius: 0; +} + +.ss__pike .ss__demo .ss__demo__theme input, .ss__pike .ss__demo .ss__demo__theme select { + color: #515151; + border: 2px solid #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme input::-webkit-input-placeholder, .ss__pike .ss__demo .ss__demo__theme input :focus::-webkit-input-placeholder { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme input::-ms-input-placeholder, .ss__pike .ss__demo .ss__demo__theme input :focus::-ms-input-placeholder { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme input::placeholder, .ss__pike .ss__demo .ss__demo__theme input :focus::placeholder { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__button { + background-color: #00aeef; + color: #ffffff; + font-family: "Roboto", Helvetica, Arial; + font-weight: 700; +} + +.ss__everest .ss__demo .ss__demo__theme input, .ss__everest .ss__demo .ss__demo__theme select, .ss__everest .ss__demo .ss__demo__theme .ss__demo__button { + -moz-border-radius: 3px; + border-radius: 3px; +} + +.ss__everest .ss__demo .ss__demo__theme input, .ss__everest .ss__demo .ss__demo__theme select { + color: #515151; + border: 2px solid #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme input::-webkit-input-placeholder, .ss__everest .ss__demo .ss__demo__theme input :focus::-webkit-input-placeholder { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme input::-ms-input-placeholder, .ss__everest .ss__demo .ss__demo__theme input :focus::-ms-input-placeholder { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme input::placeholder, .ss__everest .ss__demo .ss__demo__theme input :focus::placeholder { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__button { + background-color: #d15120; + color: #ffffff; + font-family: "Montserrat", Helvetica, Arial; + font-weight: 600; + text-transform: uppercase; + position: relative; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__button:after { + content: ""; + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + border-bottom: 2px solid #94280b; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input, .ss__matterhorn .ss__demo .ss__demo__theme select, .ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__button { + -moz-border-radius: 0; + border-radius: 0; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input, .ss__matterhorn .ss__demo .ss__demo__theme select { + color: #555555; + border: 1px solid #111111; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input::-webkit-input-placeholder, .ss__matterhorn .ss__demo .ss__demo__theme input :focus::-webkit-input-placeholder { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input::-ms-input-placeholder, .ss__matterhorn .ss__demo .ss__demo__theme input :focus::-ms-input-placeholder { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input::placeholder, .ss__matterhorn .ss__demo .ss__demo__theme input :focus::placeholder { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__button { + background-color: #222222; + color: #ffffff; + font-family: "Lora", "Times New Roman", serif; + font-weight: 300; + font-style: italic; +} + +/* DEMO - BACKGROUND +========================================================================== */ + +.ss__demo .ss__demo__background { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} + +.ss__demo .ss__demo__background .ss__demo__svg { + width: 100%; + height: 100%; +} + +.ss__pike .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__background { + fill: #1d4990; +} + +.ss__pike .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__top_triangle { + stroke: #00aeef; +} + +.ss__pike .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__bottom_triangle { + stroke: #ffffff; +} + +.ss__everest .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__background { + fill: #94280b; } -.ss-toolbar-col.pagination, -.ss-toolbar.ss-toolbar-bottom { - margin-top: 20px; - float: right; +.ss__everest .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__top_triangle { + stroke: #d15120; } -.ss-toolbar-col.pagination, -.ss-toolbar.ss-toolbar-bottom-infinite { - display: flex; - justify-content: center; +.ss__everest .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__bottom_triangle { + stroke: #ffffff; } -.ss-slideout__button { - width: 100%; - border: 1px solid #333; - text-align: center; - padding: 10px 0; - margin: 10px 0; - font-size: 1.2em; - cursor: pointer; +.ss__matterhorn .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__background { + fill: #222222; } -.ss-slider button { - color: inherit; +.ss__matterhorn .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__top_triangle { + stroke: #111111; } -#login-modal { - background: white; - border-radius: 5px; - padding: 20px; - border: 1px solid #ccc; - width: 450px; - position: absolute; - z-index: 99999999; - top: 10%; - left: calc(50% - 225px); - box-shadow: 0px 0px 20px 0px rgb(0 0 0 / 20%); + +.ss__matterhorn .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__bottom_triangle { + stroke: #ffffff; } -#login-modal input { - width: 80%; - border: 1px solid #ccc; + +/* DEMO - SLIDEOUT BUTTON +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__slideout__default .ss__demo__slideout__button { + -webkit-flex-flow: row nowrap; + flex-flow: row nowrap; + display: -webkit-inline-flex; + display: -ms-inline-flex; + display: -moz-inline-flex; + display: inline-flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 5px; + gap: 5px; + height: auto; + line-height: 1; + font-size: 16px; + background-color: transparent; + padding: 0; } -#login-modal button { - display: block; - margin: 20px auto; + +/* DEMO - LAYOUT +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__layout { + -ms-gap: 30px; + gap: 30px; +} + +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__sidebar, +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__content { + min-width: 1px; +} + +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__sidebar { + display: none; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 250px; +} + +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__content { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; +} + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__sidebar { + display: block; + } +} + +.ss__demo .ss__demo__wrapper { + margin: 0 auto; + padding: 0 20px; + max-width: 1200px; + width: auto; +} + +.ss__demo .ss__demo__theme .ss__demo__flex__wrap, .ss__demo .ss__demo__theme .ss__demo__flex__wrap--center { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; +} + +.ss__demo .ss__demo__theme .ss__demo__flex__nowrap, .ss__demo .ss__demo__theme .ss__demo__flex__nowrap--center { + -webkit-flex-flow: nowrap; + flex-flow: nowrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; +} + +.ss__demo .ss__demo__theme .ss__demo__flex__wrap--center, .ss__demo .ss__demo__theme .ss__demo__flex__nowrap--center { + -webkit-align-items: center; + align-items: center; +} + +.ss__demo .ss__demo__theme .ss__demo__row--5 { + -ms-gap: 5px; + gap: 5px; +} + +.ss__demo .ss__demo__theme .ss__demo__row--10 { + -ms-gap: 10px; + gap: 10px; +} + +.ss__demo .ss__demo__theme .ss__demo__row--20 { + -ms-gap: 20px; + gap: 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__row--30 { + -ms-gap: 30px; + gap: 30px; +} + +.ss__demo .ss__demo__theme .ss__demo__column { + min-width: 1px; +} + +/* DEMO - HEADER +========================================================================== */ + +.ss__demo .ss__demo__header { + padding: 40px 0; + margin: 0 0 40px 0; + position: relative; +} + +.ss__demo .ss__demo__header .ss__demo__background { + z-index: -1; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo { + -webkit-flex: 0 0 200px; + -ms-flex: 0 0 200px; + -moz-flex: 0 0 200px; + flex: 0 0 200px; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo a { + display: block; + width: 100%; + line-height: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo img { + max-width: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search { + order: 3; + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form { + position: relative; + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + -moz-flex: 1 0 auto; + flex: 1 0 auto; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__input { + width: 100%; + padding-right: 60px; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button { + background-color: transparent; + position: absolute; + top: 2px; + bottom: 2px; + right: 20px; + margin: auto; + padding: 0; + line-height: 1; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + line-height: 1; + margin-left: auto; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__icon { + width: 20px; + height: 20px; + line-height: 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__icon .ss__icon { + fill: #ffffff; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button { + position: relative; + overflow: visible; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + position: absolute; + top: 12px; + right: -6px; + z-index: 1; + color: #ffffff; + font-size: 10px; + font-weight: 700; + width: 16px; + height: 16px; + line-height: 14px; + text-align: center; + border-radius: 50%; +} + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__flex__wrap--center { + -webkit-justify-content: flex-end; + justify-content: flex-end; + } + + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo { + -webkit-flex: 0 0 300px; + -ms-flex: 0 0 300px; + -moz-flex: 0 0 300px; + flex: 0 0 300px; + margin-right: auto; + } + + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search { + order: 0; + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + max-width: 500px; + } + + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons { + margin-left: 0; + } +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button .ss__demo__icon { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + background-color: #00aeef; + border: 1px solid #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button:hover .ss__demo__cart__count { + color: #00aeef; + background-color: #ffffff; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button .ss__demo__icon { + color: #515151; } -.ss__autocomplete { - width: 100%; +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__button:after { + display: none; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + background-color: #d15120; + border: 1px solid #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button:hover .ss__demo__cart__count { + color: #d15120; + background-color: #ffffff; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button .ss__demo__icon { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + background-color: #848484; + border: 1px solid #848484; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button:hover .ss__demo__cart__count { + color: #848484; + background-color: #ffffff; +} + +/* DEMO - NAVIGATION +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__navigation { + margin: 40px 0 0 0; + display: none; +} + +.ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 10px 20px; + gap: 10px 20px; + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-size: 16px; +} + + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__navigation { + display: block; + } +} + +@media only screen and (min-width: 992px) { + .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list { + -ms-gap: 10px 30px; + gap: 10px 30px; + } +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-family: "Roboto", Helvetica, Arial; + font-weight: 700; + color: #ffffff; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a:hover { + color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-family: "Source Sans 3", Helvetica, Arial; + font-weight: 600; + text-transform: uppercase; + color: #ffffff; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a:hover { + color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-family: "Lora", "Times New Roman", serif; + font-weight: 300; + font-style: italic; + color: #ffffff; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a:hover { + color: #555555; +} + +/* DEMO - BREADCRUMBS +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs { + margin: 0 0 30px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 10px; + gap: 10px; + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul li { + line-height: 1; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul li a { + color: #515151; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul li .ss__icon { + width: 12px; + height: 12px; + line-height: 12px; +} + +/* DEMO - HEADER TITLE +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__header__title { + margin: 0 0 30px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__header__title .ss__title { + margin: 0; +} + +/* DEMO - FOOTER +========================================================================== */ + +.ss__demo .ss__demo__footer { + padding: 40px 0; + margin: 40px 0 0 0; + position: relative; + overflow: hidden; +} + +.ss__demo .ss__demo__theme .ss__demo__footer a, .ss__demo .ss__demo__theme .ss__demo__footer p, .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + color: #ffffff; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__wrapper { + position: relative; + z-index: 2; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + font-size: 16px; + margin: 0 0 10px 0; + padding: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title .ss__demo__icon { + margin: 0 10px 0 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__list { + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__list li { + margin: 0 0 2.5px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__list li:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__column { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information p { + text-align: justify; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social { + text-align: right; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -webkit-justify-content: flex-end; + justify-content: flex-end; + -ms-gap: 10px; + gap: 10px; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + width: 30px; + height: 30px; + line-height: 30px; + -moz-border-radius: 50%; + border-radius: 50%; + text-align: center; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a:hover .ss__demo__icon .ss__icon { + fill: #ffffff; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a .ss__demo__icon { + height: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a .ss__demo__icon .ss__icon { + max-height: 16px; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright { + text-align: right; + margin: 20px 0 0 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright p { + margin: 0; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -webkit-justify-content: flex-end; + justify-content: flex-end; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright p a, .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright p span { + margin: 0 2.5px; +} + +@media only screen and (min-width: 541px) { + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__row--20 { + -ms-gap: 20px 40px; + gap: 20px 40px; + } + + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__column { + width: calc(50% - 20px); + } +} + +@media only screen and (min-width: 992px) { + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__column { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + width: auto; + } + + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information { + -webkit-flex: 0 0 400px; + -ms-flex: 0 0 400px; + -moz-flex: 0 0 400px; + flex: 0 0 400px; + } +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer { + background-color: #1d4990; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer a:hover { + color: #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + border-bottom: 2px solid #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + background-color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer { + background-color: #94280b; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer a:hover { + color: #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + border-bottom: 2px solid #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + background-color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__footer { + background-color: #222222; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__footer a:hover { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + background-color: #111111; +} + +/* DEMO - SKIP TO BUTTON +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__skip-to__button { + position: absolute; + top: -99999px; + left: -99999px; + background-color: #1d4990; + color: #ffffff; + font-size: 16px; + font-weight: 700; + text-transform: uppercase; + padding: 5px 10px; +} + +.ss__demo .ss__demo__theme .ss__skip-to__button:focus { + position: absolute; + top:0; + left: 0; + z-index: 1; +} + +/* DEMO - LOGIN MODAL +========================================================================== */ + +.ss__demo .ss__demo__theme #ss__demo__login__modal { + display: none; + background: #ffffff; + padding: 20px; + margin: 0 auto; + border: 1px solid #ebebeb; + border-radius: 15px; + box-shadow: 2px 2px 20px 0 rgba(80, 80, 100, 0.12); + width: 450px; + position: absolute; + left: 0; + right: 0; + top: 25%; + z-index: 99999999; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal.ss__demo__login__modal--active { + display: block; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header { + -webkit-flex-flow: row nowrap; + flex-flow: row nowrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 10px; + gap: 10px; + margin: 0 0 20px 0; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header .ss__demo__title { + line-height: 1; + margin: 0; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header .ss__demo__close { + background-color: rgba(0, 0, 0, 0); + border: 0; + padding: 0; + margin: 0; + margin-left: auto; + order: 10; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header .ss__demo__close .ss__icon { + fill: #515151; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__input .ss__demo__input__label { + width: auto; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__button { + display: block; + width: 100%; + margin: 20px auto 0 auto; +} + +/* DEMO - RESULT +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__result { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: flex-start; + align-items: flex-start; + -ms-gap: 30px; + gap: 30px; + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result > * { + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; + min-width: 1px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner { + position: relative; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: flex-start; + align-items: flex-start; + -ms-gap: 10px; + gap: 10px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner > * { + min-width: 1px; + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image { + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image .ss__image__link { + display: block; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image .ss__image { + position: relative; + line-height: 0; + height: 0; + padding-bottom: 150%; + overflow: hidden; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image .ss__image img { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + max-width: 100%; + max-height: 100%; + -o-object-position: center center; + object-position: center center; + -o-object-fit: contain; + object-fit: contain; + width: 100%; + height: 100%; + border: 0; + display: block; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details { + text-align: left; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > p, +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > div { + margin: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > p:last-child, +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > div:last-child, +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details .ss__result__description > *:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__demo__header__title { + display: none; + margin: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__demo__header__title .ss__title { + font-size: 22px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + font-size: 16px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span ~ span { + padding-left: 5px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + text-decoration: line-through; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-size: 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__add-to-cart { + width: 100%; + height: 46px; + line-height: 46px; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + color: #737373; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-weight: 700; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price--on-sale { + color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + color: #737373; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-weight: 600; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price--on-sale { + color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + color: #848484; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-weight: 600; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price--on-sale { + color: #222222; +} + +@media only screen and (min-width: 768px) { + #ss__product__demo .ss__demo .ss__demo__theme .ss__demo__header__title { + display: none; + } + + .ss__demo .ss__demo__theme .ss__demo__result .ss__result { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + } + + .ss__demo .ss__demo__theme .ss__result .ss__result__inner { + -ms-gap: 20px; + gap: 20px; + } + + .ss__demo .ss__demo__theme .ss__result .ss__result__inner .ss__result__image { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 200px; + } + + .ss__demo .ss__demo__theme .ss__result .ss__result__inner .ss__result__details { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + } + + .ss__demo .ss__demo__theme .ss__result__side { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 300px; + } + + #ss__product__demo .ss__demo .ss__demo__theme .ss__result__side > .ss__result__details .ss__demo__header__title { + display: block; + } +} + +@media only screen and (min-width: 992px) { + .ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image { + width: 350px; + } + + .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side { + width: 350px; + } +} + +/* DEMO - CART +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product { + margin: 0 0 20px 0; + -ms-gap: 10px 20px; + gap: 10px 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image, +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details { + min-width: 1px; + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image img { + width: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details > div { + margin: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details > div:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__name { + margin-bottom: 5px; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__name h3 { + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-size: 18px; + font-weight: 700; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__actions { + -ms-gap: 10px; + gap: 10px; + max-width: 400px; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__actions .ss__demo__button { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + height: 46px; + line-height: 46px; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-weight: 700; + color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-weight: 600; + color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-weight: 600; + color: #222222; +} + +@media only screen and (min-width: 541px) { + .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image { + -webkit-flex: 0 0 150px; + -ms-flex: 0 0 150px; + -moz-flex: 0 0 150px; + flex: 0 0 150px; + } + + .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + } +} + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image { + -webkit-flex: 0 0 200px; + -ms-flex: 0 0 200px; + -moz-flex: 0 0 200px; + flex: 0 0 200px; + } +} + + + +.ss-toolbar-col { + display: inline-block; + margin: 10px 20px 10px 0; } \ No newline at end of file diff --git a/packages/snap-preact-demo/public/snap/website.js b/packages/snap-preact-demo/public/snap/website.js new file mode 100644 index 000000000..3f6244609 --- /dev/null +++ b/packages/snap-preact-demo/public/snap/website.js @@ -0,0 +1,30 @@ +var activeClass = 'ss__demo__login__modal--active'; +var modalSelector = 'ss__demo__login__modal'; +var modalInputSelector = '#ss__demo__login__modal #ss__demo__input__shopper-id'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function toggleModal() { + var modal = document.getElementById(modalSelector); + var modalInput = document.querySelector(modalInputSelector); + + if (modal.classList.contains(activeClass)) { + modal.classList.remove(activeClass); + } else { + modal.classList.add(activeClass); + modalInput.focus(); + } +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function setShopperID() { + var modal = document.getElementById(modalSelector); + var modalInput = document.querySelector(modalInputSelector); + var id = modalInput.value; + + if (id) { + window.searchspring.tracker.track.shopper.login({ + id: id, + }); + modal.classList.remove(activeClass); + } +} diff --git a/packages/snap-preact-demo/public/templates/bundle.html b/packages/snap-preact-demo/public/templates/bundle.html index f149b82e9..08aa6e866 100644 --- a/packages/snap-preact-demo/public/templates/bundle.html +++ b/packages/snap-preact-demo/public/templates/bundle.html @@ -1,242 +1,294 @@ - - + + - + + + + Product Detail Page - - - - - - - - - - + - - -
- - - -
- -
-
-
- -
-
-
-
- -
- - -
stuff...
- - -
-
- - - - +
+ + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/images-logo-stacked.svg b/packages/snap-preact-demo/public/templates/images-logo-stacked.svg new file mode 100644 index 000000000..e753a7fc3 --- /dev/null +++ b/packages/snap-preact-demo/public/templates/images-logo-stacked.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/images-logo.svg b/packages/snap-preact-demo/public/templates/images-logo.svg new file mode 100644 index 000000000..8ef58ba7f --- /dev/null +++ b/packages/snap-preact-demo/public/templates/images-logo.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/index.html b/packages/snap-preact-demo/public/templates/index.html index 6f5a7c16b..e1ac30cd2 100644 --- a/packages/snap-preact-demo/public/templates/index.html +++ b/packages/snap-preact-demo/public/templates/index.html @@ -1,18 +1,17 @@ - - + - + + + + Search Results - - - - - - - - - + - - - - - - - Skip to main content - -
-
-
-
- -
-
-
-
    -
  • Home
  • -
  • -
  • Search Results
  • -
-
-
- +
+
+
+
+
+
    +
  • Home
  • +
  • + + + + + +
  • +
  • Search results
  • +
+
+
+
Content to be hidden!
- - + +
-
-
+ - - - - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/product.html b/packages/snap-preact-demo/public/templates/product.html index dc4fe694f..de3403e5d 100644 --- a/packages/snap-preact-demo/public/templates/product.html +++ b/packages/snap-preact-demo/public/templates/product.html @@ -1,233 +1,285 @@ - - + + - + + + + Product Detail Page - - - - - - - - - - + - - -
-
-
- -
-
-
-
- - - + + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/recommendations.html b/packages/snap-preact-demo/public/templates/recommendations.html index db5681446..0043367cd 100644 --- a/packages/snap-preact-demo/public/templates/recommendations.html +++ b/packages/snap-preact-demo/public/templates/recommendations.html @@ -1,248 +1,299 @@ - - + + - + + + + Product Detail Page - - - - - - - - - - + + +
+
+ Skip to main content + +
+
+ +
+
+
+ + + + +
+
+
+
+ +
+
+ +
+
+
+ + +
+
+
- -
- - - -
- -
-
-
- -
-
-
-
- -
- -
stuff...
- - +
+
+
+
+
+
    +
  • Home
  • +
  • + + + + + +
  • +
  • Stripe Out White Off-The-Shoulder Dress
  • +
+
+
+ +
+

Stripe Out White Off-The-Shoulder Dress

+
+ +
+
+
+
+ +
+ Stripe Out White Off-The-Shoulder Dress +
+
+
+ +
+
+

+ Are you Stripe Out of ideas for what to wear this weekend on that trip you've got coming up with + your friends? Afraid you'll be the odd one out and everyone else will be all cute and trendy and + there you'll be ... not trendy and wearing the same old things you've been wearing on this + annual getaway for years? Lucky for you, here's the dress you've been searching for. Doesn't + matter what else you pack (it does, you'll want to continue to shop with us, we were just being + nice) this is the piece that will set you apart from everyone else (that is absolutely true, you + will be a Goddess among women). Take that, bad fashion moments of the past! Striped dress + features 3/4 sleeve bell sleeves with a partially elastic/open back. Model is wearing a small. • + 97% Cotton 3% Spandex • Machine Wash Cold... +

+
+
+
+
+ +
+
+
+

Stripe Out White Off-The-Shoulder Dress

+
+

+ $50.00 + $48.00 +

+ +
+
+
+
- +
+
stuff...
- -
-
+ - - - +
+ + - \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/website.css b/packages/snap-preact-demo/public/templates/website.css index 470f9a69e..2ff55a54a 100644 --- a/packages/snap-preact-demo/public/templates/website.css +++ b/packages/snap-preact-demo/public/templates/website.css @@ -1,767 +1,1735 @@ -/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ +/* NORMALIZE +========================================================================== */ + +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document - ========================================================================== */ +========================================================================== */ /** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in iOS. - */ +* 1. Correct the line height in all browsers. +* 2. Prevent adjustments of font size after orientation changes in iOS. +*/ html { - line-height: 1.15; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ } + line-height: 1.15; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ +} /* Sections - ========================================================================== */ +========================================================================== */ /** - * Remove the margin in all browsers. - */ +* Remove the margin in all browsers. +*/ body { - margin: 0; } + margin: 0; +} + +/** +* Render the `main` element consistently in IE. +*/ +main { + display: block; +} /** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ +* Correct the font size and margin on `h1` elements within `section` and +* `article` contexts in Chrome, Firefox, and Safari. +*/ h1 { - font-size: 2em; - margin: 0.67em 0; } + font-size: 2em; + margin: 0.67em 0; +} /* Grouping content - ========================================================================== */ +========================================================================== */ /** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ +* 1. Add the correct box sizing in Firefox. +* 2. Show the overflow in Edge and IE. +*/ hr { - box-sizing: content-box; - /* 1 */ - height: 0; - /* 1 */ - overflow: visible; - /* 2 */ } + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ +} /** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ +* 1. Correct the inheritance and scaling of font size in all browsers. +* 2. Correct the odd `em` font sizing in all browsers. +*/ pre { - font-family: monospace, monospace; - /* 1 */ - font-size: 1em; - /* 2 */ } + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} /* Text-level semantics - ========================================================================== */ +========================================================================== */ /** - * Remove the gray background on active links in IE 10. - */ +* Remove the gray background on active links in IE 10. +*/ a { - background-color: transparent; } + background-color: transparent; +} /** - * 1. Remove the bottom border in Chrome 57- - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ +* 1. Remove the bottom border in Chrome 57- +* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. +*/ abbr[title] { - border-bottom: none; - /* 1 */ - text-decoration: underline; - /* 2 */ - text-decoration: underline dotted; - /* 2 */ } + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ +} /** - * Add the correct font weight in Chrome, Edge, and Safari. - */ -b, -strong { - font-weight: bolder; } +* Add the correct font weight in Chrome, Edge, and Safari. +*/ +b, strong { + font-weight: bolder; +} /** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ -code, -kbd, -samp { - font-family: monospace, monospace; - /* 1 */ - font-size: 1em; - /* 2 */ } +* 1. Correct the inheritance and scaling of font size in all browsers. +* 2. Correct the odd `em` font sizing in all browsers. +*/ +code, kbd, samp { + font-family: monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} /** - * Add the correct font size in all browsers. - */ +* Add the correct font size in all browsers. +*/ small { - font-size: 80%; } + font-size: 80%; +} /** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; } +* Prevent `sub` and `sup` elements from affecting the line height in +* all browsers. +*/ +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} sub { - bottom: -0.25em; } + bottom: -0.25em; +} sup { - top: -0.5em; } + top: -0.5em; +} /* Embedded content - ========================================================================== */ +========================================================================== */ /** - * Remove the border on images inside links in IE 10. - */ +* Remove the border on images inside links in IE 10. +*/ img { - border-style: none; } + border-style: none; +} /* Forms - ========================================================================== */ +========================================================================== */ /** - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - line-height: 1.15; - /* 1 */ - margin: 0; - /* 2 */ } +* 1. Change the font styles in all browsers. +* 2. Remove the margin in Firefox and Safari. +*/ +button, input, optgroup, select, textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} /** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ -button, -input { - /* 1 */ - overflow: visible; } +* Show the overflow in IE. +* 1. Show the overflow in Edge. +*/ +button, input { + overflow: visible; /* 1 */ +} /** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ -button, -select { - /* 1 */ - text-transform: none; } +* Remove the inheritance of text transform in Edge, Firefox, and IE. +* 1. Remove the inheritance of text transform in Firefox. +*/ +button, select { + text-transform: none; /* 1 */ +} /** - * Correct the inability to style clickable types in iOS and Safari. - */ -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; } +* Correct the inability to style clickable types in iOS and Safari. +*/ +button, [type=button], [type=reset], [type=submit] { + -webkit-appearance: button; +} /** - * Remove the inner border and padding in Firefox. - */ -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; } +* Remove the inner border and padding in Firefox. +*/ +button::-moz-focus-inner, [type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner { + border-style: none; + padding: 0; +} /** - * Restore the focus styles unset by the previous rule. - */ -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; } +* Restore the focus styles unset by the previous rule. +*/ +button:-moz-focusring, [type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring { + outline: 1px dotted ButtonText; +} /** - * Correct the padding in Firefox. - */ +* Correct the padding in Firefox. +*/ fieldset { - padding: 0.35em 0.75em 0.625em; } + padding: 0.35em 0.75em 0.625em; +} /** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ +* 1. Correct the text wrapping in Edge and IE. +* 2. Correct the color inheritance from `fieldset` elements in IE. +* 3. Remove the padding so developers are not caught out when they zero out +* `fieldset` elements in all browsers. +*/ legend { - /* 1 */ - color: inherit; - /* 2 */ - display: table; - /* 1 */ - max-width: 100%; - /* 1 */ - padding: 0; - /* 3 */ - white-space: normal; - /* 1 */ } + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} /** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ +* Add the correct vertical alignment in Chrome, Firefox, and Opera. +*/ progress { - vertical-align: baseline; } + vertical-align: baseline; +} /** - * Remove the default vertical scrollbar in IE 10+. - */ +* Remove the default vertical scrollbar in IE 10+. +*/ textarea { - overflow: auto; } + overflow: auto; +} /** - * 1. Add the correct box sizing in IE 10. - * 2. Remove the padding in IE 10. - */ -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; - /* 1 */ - padding: 0; - /* 2 */ } +* 1. Add the correct box sizing in IE 10. +* 2. Remove the padding in IE 10. +*/ +[type=checkbox], +[type=radio] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} /** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; } +* Correct the cursor style of increment and decrement buttons in Chrome. +*/ +[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button { + height: auto; +} /** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ -[type="search"] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ } +* 1. Correct the odd appearance in Chrome and Safari. +* 2. Correct the outline style in Safari. +*/ +[type=search] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} /** - * Remove the inner padding in Chrome and Safari on macOS. - */ -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } +* Remove the inner padding in Chrome and Safari on macOS. +*/ +[type=search]::-webkit-search-decoration { + -webkit-appearance: none; +} /** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ +* 1. Correct the inability to style clickable types in iOS and Safari. +* 2. Change font properties to `inherit` in Safari. +*/ ::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ } + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} /* Interactive - ========================================================================== */ +========================================================================== */ /* - * Add the correct display in Edge, IE 10+, and Firefox. - */ +* Add the correct display in Edge, IE 10+, and Firefox. +*/ details { - display: block; } + display: block; +} /* - * Add the correct display in all browsers. - */ +* Add the correct display in all browsers. +*/ summary { - display: list-item; } + display: list-item; +} /* Misc - ========================================================================== */ +========================================================================== */ /** - * Add the correct display in IE 10+. - */ +* Add the correct display in IE 10+. +*/ template { - display: none; } + display: none; +} /** - * Add the correct display in IE 10. - */ +* Add the correct display in IE 10. +*/ [hidden] { - display: none; } + display: none; +} + +/* DEMO - BASE STYLES +========================================================================== */ -/* Base Styles -============================================== */ +*, *:before, *:after { + box-sizing: border-box; +} html, body { - min-height: 100%; } + height: 100%; + min-height: 100%; +} html { - font-size: 16px; } + font-size: 16px; +} body { - height: 100%; - -webkit-print-color-adjust: exact; - -webkit-tap-highlight-color: rgba(255, 255, 255, 0); - backface-visibility: hidden; - background-attachment: fixed; - font-family: 'Roboto', Helvetica, Arial; - font-size: 14px; - line-height: 1.5; - color: #3f3e40; } + height: 100%; + -webkit-print-color-adjust: exact; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + backface-visibility: hidden; + background-attachment: fixed; + font-size: 14px; + line-height: 1.5; +} img { - max-width: 100%; - width: auto; - height: auto; - display: block; } + max-width: 100%; + width: auto; + height: auto; + display: block; +} a { - color: #4c3ce2; - text-decoration: none; } - a:hover { - color: #3f3e40; } + text-decoration: none; +} ul { - list-style: none; - padding: 0; } + list-style: none; + padding: 0; +} h1, h2, h3, h4, h5, h6, p, ul { - margin: 0 0 20px 0; } - -h1, h2, h3, h4, h5, h6, .ss-lite-title { - font-weight: 700; - font-family: 'Roboto', Helvetica, Arial; } + margin: 0 0 20px 0; +} h1 { - font-size: 26px; } + font-size: 28px; +} h2 { - font-size: 24px; } + font-size: 26px; +} h3 { - font-size: 22px; } + font-size: 22px; +} h4 { - font-size: 20px; } + font-size: 20px; +} h5, h6 { - font-size: 18px; } + font-size: 18px; +} -hr { - border: 0; - border-top: 1px solid #ebebeb; } +.ss__demo { + height: 100%; +} + +.ss__demo .ss__demo__main { + min-height: 400px; +} + +.ss__demo .ss__demo__theme .ss__demo__pointer { + cursor: pointer; +} + +.ss__demo .ss__demo__theme .ss__demo__icon { + -webkit-flex-flow: column nowrap; + flex-flow: column nowrap; + display: -webkit-inline-flex; + display: -ms-inline-flex; + display: -moz-inline-flex; + display: inline-flex; + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; + -moz-flex: 0 0 auto; + flex: 0 0 auto; + width: 16px; + height: 16px; + line-height: 16px; +} + +.ss__demo .ss__demo__theme .ss__demo__icon .ss__icon { + margin: auto; + width: auto; + height: auto; + max-width: 100%; + max-height: 100%; + line-height: 1; + fill: currentColor; +} + +/* DEMO - TYPOGRAPHY +========================================================================== */ + +.ss__pike { + font-family: "Roboto", Helvetica, Arial; +} + +.ss__pike .ss__demo .ss__demo__theme { + color: #515151; +} + +.ss__pike h1, .ss__pike h2, +.ss__pike h3, .ss__pike h4, +.ss__pike h5, .ss__pike h6 { + font-family: "Roboto", Helvetica, Arial; + font-weight: 700; +} + +.ss__pike .ss__demo .ss__demo__theme h1, .ss__pike .ss__demo .ss__demo__theme h2, +.ss__pike .ss__demo .ss__demo__theme h3, .ss__pike .ss__demo .ss__demo__theme h4, +.ss__pike .ss__demo .ss__demo__theme h5, .ss__pike .ss__demo .ss__demo__theme h6 { + color: #1d4990; +} + +.ss__everest { + font-family: "Source Sans 3", Helvetica, Arial; +} + +.ss__everest .ss__demo .ss__demo__theme a:hover { + color: #515151; +} + +.ss__everest h1, .ss__everest h2, +.ss__everest h3, .ss__everest h4, +.ss__everest h5, .ss__everest h6 { + font-family: "Montserrat", Helvetica, Arial; + font-weight: 600; + text-transform: uppercase; +} + +.ss__everest .ss__demo .ss__demo__theme h1, .ss__everest .ss__demo .ss__demo__theme h2, +.ss__everest .ss__demo .ss__demo__theme h3, .ss__everest .ss__demo .ss__demo__theme h4, +.ss__everest .ss__demo .ss__demo__theme h5, .ss__everest .ss__demo .ss__demo__theme h6 { + color: #94280b; +} + +.ss__matterhorn { + font-family: "Poppins", Helvetica, Arial; +} + +.ss__matterhorn .ss__demo .ss__demo__theme { + color: #555555; +} + +.ss__matterhorn h1, .ss__matterhorn h2, +.ss__matterhorn h3, .ss__matterhorn h4, +.ss__matterhorn h5, .ss__matterhorn h6 { + font-family: "Lora", "Times New Roman", serif; + font-weight: 300; + font-style: italic; +} + +.ss__matterhorn .ss__demo .ss__demo__theme h1, .ss__matterhorn .ss__demo .ss__demo__theme h2, +.ss__matterhorn .ss__demo .ss__demo__theme h3, .ss__matterhorn .ss__demo .ss__demo__theme h4, +.ss__matterhorn .ss__demo .ss__demo__theme h5, .ss__matterhorn .ss__demo .ss__demo__theme h6 { + color: #222222; +} + +/* DEMO - FORM FIELDS +========================================================================== */ + +input, button, select { + padding: 0; + margin: 0; + border: 0; +} + +input, .ss__demo__button, select { + height: 40px; + line-height: 40px; + padding: 0 20px; +} -/* Form fields -============================================== */ input::-webkit-input-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input:-moz-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input::-moz-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input:-ms-input-placeholder { - color: #3f3e40; - -webkit-transition: color 0.3s ease-in-out; - -moz-transition: color 0.3s ease-in-out; - -ms-transition: color 0.3s ease-in-out; - -o-transition: color 0.3s ease-in-out; - transition: color 0.3s ease-in-out; } - -input :focus::-webkit-input-placeholder { - color: #3f3e40; } - -input :focus:-moz-placeholder { - color: #3f3e40; } - -input :focus::-moz-placeholder { - color: #3f3e40; } - -input :focus:-ms-input-placeholder { - color: #3f3e40; } - -input[type='text'], button { - border: 0; - line-height: 1; } + -webkit-transition: color 0.3s ease-in-out; + -o-transition: color 0.3s ease-in-out; + -ms-transition: color 0.3s ease-in-out; + -moz-transition: color 0.3s ease-in-out; + transition: color 0.3s ease-in-out; +} + +input::-ms-input-placeholder { + -webkit-transition: color 0.3s ease-in-out; + -o-transition: color 0.3s ease-in-out; + -ms-transition: color 0.3s ease-in-out; + -moz-transition: color 0.3s ease-in-out; + transition: color 0.3s ease-in-out; +} + +input::placeholder { + -webkit-transition: color 0.3s ease-in-out; + -o-transition: color 0.3s ease-in-out; + -ms-transition: color 0.3s ease-in-out; + -moz-transition: color 0.3s ease-in-out; + transition: color 0.3s ease-in-out; +} button { - padding: 7px 20px; - color: #ffffff; - background: #3a23ad; - font-size: 18px; - border: none; - font-weight: bold; - cursor: pointer; } - button:hover { - color: white; - background: #4e37c1; } - -input[type='text'] { - color: #3f3e40; - padding: 10px; - box-sizing: border-box; - min-height: 40px; } - -/* Layout -============================================== */ -.ss-lite-wrapper { - margin: 0 auto; - padding: 0 20px; - max-width: 1200px; - width: auto; } - -.ss-lite-flex-wrap, .ss-lite-flex-wrap-center { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row wrap; - -ms-flex-flow: row wrap; - flex-flow: row wrap; } - -.ss-lite-flex-nowrap, .ss-lite-flex-nowrap-center { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row nowrap; - -ms-flex-flow: row nowrap; - flex-flow: row nowrap; } - -.ss-lite-flex-wrap-center, .ss-lite-flex-nowrap-center { - -webkit-box-align: center; - -webkit-align-items: center; - -ms-flex-align: center; - -ms-grid-row-align: center; - align-items: center; } - -.ss-lite-row-5 { - margin: 0 -5px; } - .ss-lite-row-5 > .ss-lite-col { - padding: 0 5px; } - -.ss-lite-row-10 { - margin: 0 -10px; } - .ss-lite-row-10 > .ss-lite-col { - padding: 0 10px; } - -.ss-lite-row-20 { - margin: 0 -20px; } - .ss-lite-row-20 > .ss-lite-col { - padding: 0 20px; } - -.clear { - clear: both; } - -/* Faded background -============================================== */ -.ss-lite-header { - background-color: #f8f8f8; } - .ss-lite-header, .ss-lite-header .ss-lite-wrapper { - position: relative; } - .ss-lite-header .ss-lite-wrapper { - padding: 20px; } - -/* Header -============================================== */ -.ss-lite-header .ss-lite-subheader { - text-transform: uppercase; - color: #00cee1; } - -.ss-lite-header .ss-lite-icon { - font-size: 20px; - color: #4c3ce2; } - -.ss-lite-header .ss-lite-header-logo { - width: 250px; } - .ss-lite-header .ss-lite-header-logo .st0 { - fill: url(#SVGID_1_); } - .ss-lite-header .ss-lite-header-logo .st1 { - fill: url(#SVGID_2_); } - .ss-lite-header .ss-lite-header-logo .st2 { - fill: #515151; } - .ss-lite-header .ss-lite-header-logo a { - text-align: right; - display: block; - line-height: 0; } - .ss-lite-header .ss-lite-header-logo svg { - max-width: 100%; } - -.ss-lite-header .ss-lite-header-buttons { - width: 840px; - margin: 0 0 0 auto; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar { - -webkit-box-flex: 1; - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - position: relative; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar .ss-lite-input[type='text'] { - border: 1px solid #ebebeb; - width: 100%; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar .ss-lite-input[type='text']::placeholder { - color: #c9c9c9; - font-weight: 100; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-search-bar .ss-lite-button { - background-color: transparent; - padding: 0; - position: absolute; - top: 0; - bottom: 0; - right: 10px; - margin: auto; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons { - margin: 0 0 0 15px; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons a { - position: relative; - padding: 0 5px; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons .ss-lite-cart-count { - position: absolute; - top: 6px; - right: -6px; - color: #ffffff; - font-size: 12px; - font-weight: bold; - width: 20px; - height: 20px; - line-height: 20px; - text-align: center; - display: inline-block; - background: #00cee1; - border-radius: 100%; } - .ss-lite-header .ss-lite-header-buttons .ss-lite-store-icons .ss-lite-cart-count:hover { - color: white; - background: #4e37c1; } - -/* Navigation -============================================== */ -.ss-lite-navigation { - background-color: #3a23ad; - border-top: 5px solid #4c3ce2; } - .ss-lite-navigation .ss-lite-list { - margin: 0 -20px -10px -20px; - text-align: center; } - .ss-lite-navigation .ss-lite-list li { - display: inline-block; - zoom: 1; - *display: inline; - vertical-align: middle; - padding: 0 20px 10px 20px; } - .ss-lite-navigation .ss-lite-list li a { - color: #ffffff; - font-size: 16px; - font-weight: bold; - text-transform: uppercase; } - .ss-lite-navigation .ss-lite-list li a.active { - border-bottom: 2px solid #00cee1; } - .ss-lite-navigation .ss-lite-list li a:hover { - color: #00cee1; } - -/* Main -============================================== */ - -.ss-lite-main { - flex: 1; - padding: 40px 0; } - -.ss-lite-breadcrumbs .ss-lite-list { - margin: 0 -5px 40px -5px; } - .ss-lite-breadcrumbs .ss-lite-list li { - padding: 0 5px; - display: inline-block; - zoom: 1; - *display: inline; - vertical-align: middle; } - - .ss-lite-main-layout .ss-lite-sidebar { - -webkit-box-flex: 0; - -webkit-flex: 0 0 250px; - -ms-flex: 0 0 250px; - flex: 0 0 250px; - max-width: 250px; - margin: 0 40px 0 0; } - .ss-lite-main-layout .ss-lite-content { - width: 100%; - min-width: 0; - } - -/* Footer -============================================== */ -.ss-lite-footer { - padding: 20px 0; - background-color: #3a23ad; - border-top: 5px solid #4c3ce2; } - .ss-lite-footer, .ss-lite-footer a, .ss-lite-footer p, .ss-lite-footer .ss-lite-title { - color: #ffffff; } - .ss-lite-footer a:hover { - color: #00cee1; } - .ss-lite-footer .ss-lite-col { - -webkit-box-flex: 1; - -webkit-flex: 1 1 0%; - -ms-flex: 1 1 0%; - flex: 1 1 0%; } - .ss-lite-footer .ss-lite-col .ss-lite-title { - text-transform: uppercase; - font-size: 16px; - margin: 0 0 10px 0; - padding: 0 0 10px 0; - border-bottom: 1px solid #4c3ce2; } - .ss-lite-footer .ss-lite-col .ss-lite-title .ss-lite-icon { - margin: 0 10px 0 0; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit .ss-lite-list li { - display: inline-block; - margin-right: 10px; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit a { - display: inline-block; - zoom: 1; - *display: inline; - vertical-align: middle; - width: 30px; - height: 30px; - background: #4c3ce2; - text-align: center; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - -ms-border-radius: 100%; - -o-border-radius: 100%; - border-radius: 100%; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit a:hover { - color: #ffffff; - background-color: #00cee1; } - .ss-lite-footer .ss-lite-col.ss-lite-footer-visit a i { - line-height: 30px; - font-size: 16px; } - -/* Footer Copyright -============================================== */ -.ss-lite-footer-copyright { - padding: 30px 0 0; - text-align: center; } - .ss-lite-footer-copyright p { - margin: 0; } - .ss-lite-footer-copyright p:first-child { - margin: 0 0 2.5px 0; } - -/* Responsive -============================================== */ -@media only screen and (max-width: 991px) { - .ss-lite-footer .ss-lite-col, .ss-lite-footer .ss-lite-footer-information { - -webkit-box-flex: 1; - -webkit-flex: 1 0 auto; - -ms-flex: 1 0 auto; - flex: 1 0 auto; - width: 50%; } - .ss-lite-header > .ss-lite-wrapper > .ss-lite-flex-wrap-center { - display: block; } - .ss-lite-header .ss-lite-header-logo, .ss-lite-header .ss-lite-header-buttons { - width: auto; } - .ss-lite-header .ss-lite-header-logo { - max-width: 250px; - margin: 0 auto 20px auto; } - .ss-lite-main .ss-lite-flex-nowrap { - display: block; } - .ss-lite-main .ss-lite-flex-nowrap .ss-lite-sidebar { - display: none; } } - -@media only screen and (max-width: 767px) { - .ss-lite-navigation .ss-lite-list { - margin: 0 -10px -10px -10px; } - .ss-lite-navigation .ss-lite-list li { - padding: 0 10px 10px 10px; } - .ss-lite-navigation .ss-lite-list li a { - font-size: 14px; } } - -@media only screen and (max-width: 540px) { - .ss-lite-footer .ss-lite-flex-wrap { - display: block; } - .ss-lite-footer .ss-lite-col, .ss-lite-footer .ss-lite-footer-information { - width: auto; } } - -.ss-results-title .ss-oq { - font-size: 14px; - color: #3b23ad; - font-weight: normal; -} - -.ss-results-title .ss-oq em { - font-weight: bold; -} - -.ss-toolbar-row { - margin-bottom: 20px; -} - -.ss-toolbar-col { - display: inline-block; - margin: 10px 20px 10px 0; -} - -.ss-toolbar-col.pagination, -.ss-toolbar.ss-toolbar-bottom { - margin-top: 20px; - float: right; -} - -.ss-toolbar-col.pagination, -.ss-toolbar.ss-toolbar-bottom-infinite { - display: flex; - justify-content: center; -} - -.ss-slideout__button { - width: 100%; - border: 1px solid #333; - text-align: center; - padding: 10px 0; - margin: 10px 0; - font-size: 1.2em; - cursor: pointer; -} - -.ss-slider button { - color: inherit; -} -#login-modal { - background: white; - border-radius: 5px; - padding: 20px; - border: 1px solid #ccc; - width: 450px; - position: absolute; - z-index: 99999999; - top: 10%; - left: calc(50% - 225px); - box-shadow: 0px 0px 20px 0px rgb(0 0 0 / 20%); -} -#login-modal input { - width: 80%; - border: 1px solid #ccc; -} -#login-modal button { - display: block; - margin: 20px auto; + cursor: pointer; +} + +select { + font-size: 16px; +} + +fieldset { + border: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__button { + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.ss__demo .ss__demo__theme .ss__demo__input { + -webkit-flex-flow: row nowrap; + flex-flow: row nowrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; +} + +.ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__label, .ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__input { + min-width: 1px; +} + +.ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__label { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 125px; + margin: 0 10px 0 0; +} + +.ss__demo .ss__demo__theme .ss__demo__input .ss__demo__input__input { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; +} + +@media only screen and (min-width: 768px) { + select { + font-size: 14px; + } +} + +.ss__pike .ss__demo .ss__demo__theme input, .ss__pike .ss__demo .ss__demo__theme select, .ss__pike .ss__demo .ss__demo__theme .ss__demo__button { + -moz-border-radius: 0; + border-radius: 0; +} + +.ss__pike .ss__demo .ss__demo__theme input, .ss__pike .ss__demo .ss__demo__theme select { + color: #515151; + border: 2px solid #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme input::-webkit-input-placeholder, .ss__pike .ss__demo .ss__demo__theme input :focus::-webkit-input-placeholder { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme input::-ms-input-placeholder, .ss__pike .ss__demo .ss__demo__theme input :focus::-ms-input-placeholder { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme input::placeholder, .ss__pike .ss__demo .ss__demo__theme input :focus::placeholder { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__button { + background-color: #00aeef; + color: #ffffff; + font-family: "Roboto", Helvetica, Arial; + font-weight: 700; +} + +.ss__everest .ss__demo .ss__demo__theme input, .ss__everest .ss__demo .ss__demo__theme select, .ss__everest .ss__demo .ss__demo__theme .ss__demo__button { + -moz-border-radius: 3px; + border-radius: 3px; +} + +.ss__everest .ss__demo .ss__demo__theme input, .ss__everest .ss__demo .ss__demo__theme select { + color: #515151; + border: 2px solid #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme input::-webkit-input-placeholder, .ss__everest .ss__demo .ss__demo__theme input :focus::-webkit-input-placeholder { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme input::-ms-input-placeholder, .ss__everest .ss__demo .ss__demo__theme input :focus::-ms-input-placeholder { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme input::placeholder, .ss__everest .ss__demo .ss__demo__theme input :focus::placeholder { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__button { + background-color: #d15120; + color: #ffffff; + font-family: "Montserrat", Helvetica, Arial; + font-weight: 600; + text-transform: uppercase; + position: relative; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__button:after { + content: ""; + display: block; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + border-bottom: 2px solid #94280b; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input, .ss__matterhorn .ss__demo .ss__demo__theme select, .ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__button { + -moz-border-radius: 0; + border-radius: 0; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input, .ss__matterhorn .ss__demo .ss__demo__theme select { + color: #555555; + border: 1px solid #111111; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input::-webkit-input-placeholder, .ss__matterhorn .ss__demo .ss__demo__theme input :focus::-webkit-input-placeholder { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input::-ms-input-placeholder, .ss__matterhorn .ss__demo .ss__demo__theme input :focus::-ms-input-placeholder { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme input::placeholder, .ss__matterhorn .ss__demo .ss__demo__theme input :focus::placeholder { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__button { + background-color: #222222; + color: #ffffff; + font-family: "Lora", "Times New Roman", serif; + font-weight: 300; + font-style: italic; +} + +/* DEMO - BACKGROUND +========================================================================== */ + +.ss__demo .ss__demo__background { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; +} + +.ss__demo .ss__demo__background .ss__demo__svg { + width: 100%; + height: 100%; +} + +.ss__pike .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__background { + fill: #1d4990; +} + +.ss__pike .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__top_triangle { + stroke: #00aeef; +} + +.ss__pike .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__bottom_triangle { + stroke: #ffffff; +} + +.ss__everest .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__background { + fill: #94280b; +} + +.ss__everest .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__top_triangle { + stroke: #d15120; +} + +.ss__everest .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__bottom_triangle { + stroke: #ffffff; +} + +.ss__matterhorn .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__background { + fill: #222222; +} + +.ss__matterhorn .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__top_triangle { + stroke: #111111; +} + +.ss__matterhorn .ss__demo .ss__demo__background .ss__demo__svg .ss__demo__svg__bottom_triangle { + stroke: #ffffff; +} + +/* DEMO - SLIDEOUT BUTTON +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__slideout__default .ss__demo__slideout__button { + -webkit-flex-flow: row nowrap; + flex-flow: row nowrap; + display: -webkit-inline-flex; + display: -ms-inline-flex; + display: -moz-inline-flex; + display: inline-flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 5px; + gap: 5px; + height: auto; + line-height: 1; + font-size: 16px; + background-color: transparent; + padding: 0; +} + +/* DEMO - LAYOUT +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__layout { + -ms-gap: 30px; + gap: 30px; +} + +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__sidebar, +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__content { + min-width: 1px; +} + +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__sidebar { + display: none; + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 250px; +} + +.ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__content { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; +} + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__layout .ss__demo__layout__sidebar { + display: block; + } +} + +.ss__demo .ss__demo__wrapper { + margin: 0 auto; + padding: 0 20px; + max-width: 1200px; + width: auto; +} + +.ss__demo .ss__demo__theme .ss__demo__flex__wrap, .ss__demo .ss__demo__theme .ss__demo__flex__wrap--center { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; +} + +.ss__demo .ss__demo__theme .ss__demo__flex__nowrap, .ss__demo .ss__demo__theme .ss__demo__flex__nowrap--center { + -webkit-flex-flow: nowrap; + flex-flow: nowrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; +} + +.ss__demo .ss__demo__theme .ss__demo__flex__wrap--center, .ss__demo .ss__demo__theme .ss__demo__flex__nowrap--center { + -webkit-align-items: center; + align-items: center; +} + +.ss__demo .ss__demo__theme .ss__demo__row--5 { + -ms-gap: 5px; + gap: 5px; +} + +.ss__demo .ss__demo__theme .ss__demo__row--10 { + -ms-gap: 10px; + gap: 10px; +} + +.ss__demo .ss__demo__theme .ss__demo__row--20 { + -ms-gap: 20px; + gap: 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__row--30 { + -ms-gap: 30px; + gap: 30px; +} + +.ss__demo .ss__demo__theme .ss__demo__column { + min-width: 1px; +} + +/* DEMO - HEADER +========================================================================== */ + +.ss__demo .ss__demo__header { + padding: 40px 0; + margin: 0 0 40px 0; + position: relative; +} + +.ss__demo .ss__demo__header .ss__demo__background { + z-index: -1; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo { + -webkit-flex: 0 0 200px; + -ms-flex: 0 0 200px; + -moz-flex: 0 0 200px; + flex: 0 0 200px; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo a { + display: block; + width: 100%; + line-height: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo img { + max-width: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search { + order: 3; + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form { + position: relative; + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + -moz-flex: 1 0 auto; + flex: 1 0 auto; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__input { + width: 100%; + padding-right: 60px; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button { + background-color: transparent; + position: absolute; + top: 2px; + bottom: 2px; + right: 20px; + margin: auto; + padding: 0; + line-height: 1; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + line-height: 1; + margin-left: auto; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__icon { + width: 20px; + height: 20px; + line-height: 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__icon .ss__icon { + fill: #ffffff; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button { + position: relative; + overflow: visible; +} + +.ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + position: absolute; + top: 12px; + right: -6px; + z-index: 1; + color: #ffffff; + font-size: 10px; + font-weight: 700; + width: 16px; + height: 16px; + line-height: 14px; + text-align: center; + border-radius: 50%; +} + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__flex__wrap--center { + -webkit-justify-content: flex-end; + justify-content: flex-end; + } + + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__logo { + -webkit-flex: 0 0 300px; + -ms-flex: 0 0 300px; + -moz-flex: 0 0 300px; + flex: 0 0 300px; + margin-right: auto; + } + + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search { + order: 0; + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + max-width: 500px; + } + + .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons { + margin-left: 0; + } +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button .ss__demo__icon { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + background-color: #00aeef; + border: 1px solid #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button:hover .ss__demo__cart__count { + color: #00aeef; + background-color: #ffffff; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button .ss__demo__icon { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__button:after { + display: none; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + background-color: #d15120; + border: 1px solid #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button:hover .ss__demo__cart__count { + color: #d15120; + background-color: #ffffff; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__search .ss__demo__search__form .ss__demo__search__button .ss__demo__icon { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button .ss__demo__cart__count { + background-color: #848484; + border: 1px solid #848484; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__header .ss__demo__store-icons .ss__demo__column--cart .ss__demo__slideout__button:hover .ss__demo__cart__count { + color: #848484; + background-color: #ffffff; +} + +/* DEMO - NAVIGATION +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__navigation { + margin: 40px 0 0 0; + display: none; +} + +.ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 10px 20px; + gap: 10px 20px; + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-size: 16px; +} + + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__navigation { + display: block; + } +} + +@media only screen and (min-width: 992px) { + .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list { + -ms-gap: 10px 30px; + gap: 10px 30px; + } +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-family: "Roboto", Helvetica, Arial; + font-weight: 700; + color: #ffffff; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a:hover { + color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-family: "Source Sans 3", Helvetica, Arial; + font-weight: 600; + text-transform: uppercase; + color: #ffffff; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a:hover { + color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a { + font-family: "Lora", "Times New Roman", serif; + font-weight: 300; + font-style: italic; + color: #ffffff; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__navigation .ss__demo__list li a:hover { + color: #555555; +} + +/* DEMO - BREADCRUMBS +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs { + margin: 0 0 30px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 10px; + gap: 10px; + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul li { + line-height: 1; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul li a { + color: #515151; +} + +.ss__demo .ss__demo__theme .ss__demo__breadcrumbs ul li .ss__icon { + width: 12px; + height: 12px; + line-height: 12px; +} + +/* DEMO - HEADER TITLE +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__header__title { + margin: 0 0 30px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__header__title .ss__title { + margin: 0; +} + +/* DEMO - FOOTER +========================================================================== */ + +.ss__demo .ss__demo__footer { + padding: 40px 0; + margin: 40px 0 0 0; + position: relative; + overflow: hidden; +} + +.ss__demo .ss__demo__theme .ss__demo__footer a, .ss__demo .ss__demo__theme .ss__demo__footer p, .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + color: #ffffff; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__wrapper { + position: relative; + z-index: 2; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + font-size: 16px; + margin: 0 0 10px 0; + padding: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title .ss__demo__icon { + margin: 0 10px 0 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__list { + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__list li { + margin: 0 0 2.5px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__list li:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__column { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information p { + text-align: justify; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social { + text-align: right; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -webkit-justify-content: flex-end; + justify-content: flex-end; + -ms-gap: 10px; + gap: 10px; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + width: 30px; + height: 30px; + line-height: 30px; + -moz-border-radius: 50%; + border-radius: 50%; + text-align: center; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a:hover .ss__demo__icon .ss__icon { + fill: #ffffff; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a .ss__demo__icon { + height: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a .ss__demo__icon .ss__icon { + max-height: 16px; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright { + text-align: right; + margin: 20px 0 0 0; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright p { + margin: 0; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -webkit-justify-content: flex-end; + justify-content: flex-end; +} + +.ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright p a, .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__copyright p span { + margin: 0 2.5px; +} + +@media only screen and (min-width: 541px) { + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__row--20 { + -ms-gap: 20px 40px; + gap: 20px 40px; + } + + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__column { + width: calc(50% - 20px); + } +} + +@media only screen and (min-width: 992px) { + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__column { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + width: auto; + } + + .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information { + -webkit-flex: 0 0 400px; + -ms-flex: 0 0 400px; + -moz-flex: 0 0 400px; + flex: 0 0 400px; + } +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer { + background-color: #1d4990; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer a:hover { + color: #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + border-bottom: 2px solid #00aeef; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + background-color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer { + background-color: #94280b; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer a:hover { + color: #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__title { + border-bottom: 2px solid #d15120; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + background-color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__footer { + background-color: #222222; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__footer a:hover { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__footer .ss__demo__information .ss__demo__social a { + background-color: #111111; +} + +/* DEMO - SKIP TO BUTTON +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__skip-to__button { + position: absolute; + top: -99999px; + left: -99999px; + background-color: #1d4990; + color: #ffffff; + font-size: 16px; + font-weight: 700; + text-transform: uppercase; + padding: 5px 10px; +} + +.ss__demo .ss__demo__theme .ss__skip-to__button:focus { + position: absolute; + top:0; + left: 0; + z-index: 1; +} + +/* DEMO - LOGIN MODAL +========================================================================== */ + +.ss__demo .ss__demo__theme #ss__demo__login__modal { + display: none; + background: #ffffff; + padding: 20px; + margin: 0 auto; + border: 1px solid #ebebeb; + border-radius: 15px; + box-shadow: 2px 2px 20px 0 rgba(80, 80, 100, 0.12); + width: 450px; + position: absolute; + left: 0; + right: 0; + top: 25%; + z-index: 99999999; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal.ss__demo__login__modal--active { + display: block; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header { + -webkit-flex-flow: row nowrap; + flex-flow: row nowrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -ms-gap: 10px; + gap: 10px; + margin: 0 0 20px 0; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header .ss__demo__title { + line-height: 1; + margin: 0; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header .ss__demo__close { + background-color: rgba(0, 0, 0, 0); + border: 0; + padding: 0; + margin: 0; + margin-left: auto; + order: 10; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__login__header .ss__demo__close .ss__icon { + fill: #515151; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__input .ss__demo__input__label { + width: auto; +} + +.ss__demo .ss__demo__theme #ss__demo__login__modal .ss__demo__button { + display: block; + width: 100%; + margin: 20px auto 0 auto; +} + +/* DEMO - RESULT +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__result { + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: flex-start; + align-items: flex-start; + -ms-gap: 30px; + gap: 30px; + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result > * { + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; + min-width: 1px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner { + position: relative; + -webkit-flex-flow: row wrap; + flex-flow: row wrap; + display: -webkit-flex; + display: -ms-flex; + display: -moz-flex; + display: flex; + -webkit-align-items: flex-start; + align-items: flex-start; + -ms-gap: 10px; + gap: 10px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner > * { + min-width: 1px; + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image { + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image .ss__image__link { + display: block; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image .ss__image { + position: relative; + line-height: 0; + height: 0; + padding-bottom: 150%; + overflow: hidden; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image .ss__image img { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + margin: auto; + max-width: 100%; + max-height: 100%; + -o-object-position: center center; + object-position: center center; + -o-object-fit: contain; + object-fit: contain; + width: 100%; + height: 100%; + border: 0; + display: block; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details { + text-align: left; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > p, +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > div { + margin: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > p:last-child, +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details > div:last-child, +.ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__details .ss__result__description > *:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__demo__header__title { + display: none; + margin: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__demo__header__title .ss__title { + font-size: 22px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + font-size: 16px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span ~ span { + padding-left: 5px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + text-decoration: line-through; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-size: 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__add-to-cart { + width: 100%; + height: 46px; + line-height: 46px; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + color: #515151; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + color: #737373; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-weight: 700; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price--on-sale { + color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + color: #515151; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + color: #737373; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-weight: 600; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price--on-sale { + color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing span { + color: #555555; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__msrp { + color: #848484; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price { + font-weight: 600; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side > .ss__result__details .ss__result__pricing .ss__result__price--on-sale { + color: #222222; +} + +@media only screen and (min-width: 768px) { + #ss__product__demo .ss__demo .ss__demo__theme .ss__demo__header__title { + display: none; + } + + .ss__demo .ss__demo__theme .ss__demo__result .ss__result { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + } + + .ss__demo .ss__demo__theme .ss__result .ss__result__inner { + -ms-gap: 20px; + gap: 20px; + } + + .ss__demo .ss__demo__theme .ss__result .ss__result__inner .ss__result__image { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 200px; + } + + .ss__demo .ss__demo__theme .ss__result .ss__result__inner .ss__result__details { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + } + + .ss__demo .ss__demo__theme .ss__result__side { + -webkit-flex: 0 1 auto; + -ms-flex: 0 1 auto; + -moz-flex: 0 1 auto; + flex: 0 1 auto; + width: 300px; + } + + #ss__product__demo .ss__demo .ss__demo__theme .ss__result__side > .ss__result__details .ss__demo__header__title { + display: block; + } +} + +@media only screen and (min-width: 992px) { + .ss__demo .ss__demo__theme .ss__demo__result .ss__result .ss__result__inner .ss__result__image { + width: 350px; + } + + .ss__demo .ss__demo__theme .ss__demo__result .ss__result__side { + width: 350px; + } +} + +/* DEMO - CART +========================================================================== */ + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product { + margin: 0 0 20px 0; + -ms-gap: 10px 20px; + gap: 10px 20px; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image, +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details { + min-width: 1px; + -webkit-flex: 1 1 100%; + -ms-flex: 1 1 100%; + -moz-flex: 1 1 100%; + flex: 1 1 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image img { + width: 100%; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details > div { + margin: 0 0 10px 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details > div:last-child { + margin-bottom: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__name { + margin-bottom: 5px; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__name h3 { + margin: 0; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-size: 18px; + font-weight: 700; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__actions { + -ms-gap: 10px; + gap: 10px; + max-width: 400px; +} + +.ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__actions .ss__demo__button { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + height: 46px; + line-height: 46px; +} + +.ss__pike .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-weight: 700; + color: #00aeef; +} + +.ss__everest .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-weight: 600; + color: #d15120; +} + +.ss__matterhorn .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details .ss__demo__cart__product__pricing { + font-weight: 600; + color: #222222; +} + +@media only screen and (min-width: 541px) { + .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image { + -webkit-flex: 0 0 150px; + -ms-flex: 0 0 150px; + -moz-flex: 0 0 150px; + flex: 0 0 150px; + } + + .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__details { + -webkit-flex: 1 1 0%; + -ms-flex: 1 1 0%; + -moz-flex: 1 1 0%; + flex: 1 1 0%; + } +} + +@media only screen and (min-width: 768px) { + .ss__demo .ss__demo__theme .ss__demo__cart__products .ss__demo__cart__product .ss__demo__cart__product__image { + -webkit-flex: 0 0 200px; + -ms-flex: 0 0 200px; + -moz-flex: 0 0 200px; + flex: 0 0 200px; + } } \ No newline at end of file diff --git a/packages/snap-preact-demo/public/templates/website.js b/packages/snap-preact-demo/public/templates/website.js new file mode 100644 index 000000000..3f6244609 --- /dev/null +++ b/packages/snap-preact-demo/public/templates/website.js @@ -0,0 +1,30 @@ +var activeClass = 'ss__demo__login__modal--active'; +var modalSelector = 'ss__demo__login__modal'; +var modalInputSelector = '#ss__demo__login__modal #ss__demo__input__shopper-id'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function toggleModal() { + var modal = document.getElementById(modalSelector); + var modalInput = document.querySelector(modalInputSelector); + + if (modal.classList.contains(activeClass)) { + modal.classList.remove(activeClass); + } else { + modal.classList.add(activeClass); + modalInput.focus(); + } +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function setShopperID() { + var modal = document.getElementById(modalSelector); + var modalInput = document.querySelector(modalInputSelector); + var id = modalInput.value; + + if (id) { + window.searchspring.tracker.track.shopper.login({ + id: id, + }); + modal.classList.remove(activeClass); + } +} diff --git a/packages/snap-preact-demo/snap/src/index.ts b/packages/snap-preact-demo/snap/src/index.ts index 0531909ad..9c03b589c 100644 --- a/packages/snap-preact-demo/snap/src/index.ts +++ b/packages/snap-preact-demo/snap/src/index.ts @@ -230,7 +230,7 @@ let config: SnapConfig = { url: '/snap/', fields: [ { - field: 'collection_handle', + field: 'collection_name', label: 'Collection', }, { @@ -242,7 +242,7 @@ let config: SnapConfig = { targeters: [ { name: 'finder', - selector: '#searchspring-finder', + selector: '#athos-finder', component: async () => { return (await import('./components/Finder/Finder')).Finder; }, @@ -262,7 +262,7 @@ let config: SnapConfig = { targeters: [ { name: 'finder_hierarchy', - selector: '#searchspring-finder-hierarchy', + selector: '#athos-finder-hierarchy', component: async () => { return (await import('./components/Finder/Finder')).Finder; }, diff --git a/packages/snap-preact-demo/templates/src/components/Result.tsx b/packages/snap-preact-demo/templates/src/components/Result.tsx index 8bb22cc2a..dbc36aea1 100644 --- a/packages/snap-preact-demo/templates/src/components/Result.tsx +++ b/packages/snap-preact-demo/templates/src/components/Result.tsx @@ -1,11 +1,85 @@ import { h, Fragment } from 'preact'; -import { Price, Image, OverlayBadge, CalloutBadge } from '@athoscommerce/snap-preact/components'; +import { Price, Image, OverlayBadge, CalloutBadge, Rating } from '@athoscommerce/snap-preact/components'; import { Product } from '@athoscommerce/snap-store-mobx'; import type { SearchController } from '@athoscommerce/snap-controller'; export const CustomResult = (props: { result: Product; controller: SearchController }) => { const { result, controller } = props; const core = result.mappings.core; + // const variants = result.variants; + + // const breadcrumbs = [ + // { url: '/', label: 'Home' }, + // { url: '/', label: 'Collections' }, + // { url: '/', label: 'Appliances' }, + // { label: 'Fridge' } + // ] + + // const errorObject = { + // code: 429, + // type: ErrorType.ERROR, + // message: 'Too many requests try again later', + // } + + // const slides = [ + // "https://picsum.photos/400/300?random=1", + // "https://picsum.photos/400/300?random=2", + // "https://picsum.photos/400/300?random=3", + // "https://picsum.photos/400/300?random=4", + // "https://picsum.photos/400/300?random=5", + // "https://picsum.photos/400/300?random=6", + // "https://picsum.photos/400/300?random=7", + // "https://picsum.photos/400/300?random=8" + // ]; + + // const gridOptions = [ + // { + // value: 'one one one', + // disabled: true, + // }, + // { + // value: 'two two two two', + // }, + // { + // value: 'three three three three', + // }, + // { + // value: 'four four four', + // background: 'red', + // disabled: true, + // }, + // { + // value: 'five', + // background: 'yellow', + // }, + // { + // value: 'six six six', + // background: 'blue', + // }, + // { + // value: 'seven seven', + // disabled: true, + // backgroundImageUrl: + // 'https://cdn.shopify.com/s/files/1/0916/6477/7582/files/Women_s_Apparel_Studio_Legging_-_Charcoal_86731d52-9ef2-4663-802a-8935249c5a7c.png?v=1747685734', + // }, + // { + // value: 'eight eight eight', + // backgroundImageUrl: + // 'https://cdn.shopify.com/s/files/1/0916/6477/7582/files/Women_s_Apparel_Align_Crewneck_-_Olive_519ac0c5-e067-4ab7-9fe5-5421f364c52a.png?v=1747685123', + // }, + // { + // value: 'nine nine', + // backgroundImageUrl: 'https://cdn.shopify.com/s/files/1/0916/6477/7582/files/red-buffalo-plaid-flannel.png?v=1765405015', + // }, + // { + // value: 'ten a big fat hen', + // background: 'url(https://searchspring-demo-content.s3.amazonaws.com/demo/fashion/product_images_large/rdb_studio_2_3312_large.jpg)', + // }, + // { + // value: 'grey', + // background: 'grey', + // }, + // ]; return (
@@ -16,6 +90,7 @@ export const CustomResult = (props: { result: Product; controller: SearchControl +
+
+
+ + {/* + + */} + + {/* {variants?.selections + ? variants.selections.map((selection) => { + return ; + }) + : null} */} + + {/* */} + + {/* */} + + {/*
+
*/} +
{core.price < core.msrp ? ( @@ -37,6 +132,8 @@ export const CustomResult = (props: { result: Product; controller: SearchControl )}
+ +
diff --git a/packages/snap-preact-demo/templates/src/index.ts b/packages/snap-preact-demo/templates/src/index.ts index 702e3b612..e82278a77 100644 --- a/packages/snap-preact-demo/templates/src/index.ts +++ b/packages/snap-preact-demo/templates/src/index.ts @@ -23,7 +23,7 @@ const siteId = 'atkzs2'; // }; let config: SnapTemplatesConfig = { config: { - siteId, + siteId: siteId, language: 'en', currency: 'usd', platform: 'other', @@ -42,13 +42,14 @@ let config: SnapTemplatesConfig = { }, }, theme: { - extends: 'base', + extends: 'pike', + //resultComponent: 'CustomResult', variables: { - breakpoints: { - mobile: 768, - tablet: 1024, - desktop: 1280, - }, + // breakpoints: { + // mobile: 767, + // tablet: 1024, + // desktop: 1280, + // }, // colors: { // primary: '#6d7175', // secondary: '#202223', @@ -64,6 +65,7 @@ let config: SnapTemplatesConfig = { email: { Email: { component: 'RecommendationEmail', + //resultComponent: 'EmailResult', }, }, default: { @@ -84,6 +86,14 @@ let config: SnapTemplatesConfig = { component: 'Search', }, ], + settings: { + variants: { + showDisabledSelectionValues: true, + }, + // infinite: { + // backfill: 5, + // }, + }, }, autocomplete: { targets: [ @@ -92,6 +102,16 @@ let config: SnapTemplatesConfig = { component: 'AutocompleteFixed', }, ], + settings: { + history: { + limit: 6, + showResults: true, + }, + trending: { + limit: 6, + showResults: true, + }, + }, }, }; diff --git a/packages/snap-preact-demo/tests/cypress/e2e/templates/email/email.cy.js b/packages/snap-preact-demo/tests/cypress/e2e/templates/email/email.cy.js index 579b13829..d1a5c2bb6 100644 --- a/packages/snap-preact-demo/tests/cypress/e2e/templates/email/email.cy.js +++ b/packages/snap-preact-demo/tests/cypress/e2e/templates/email/email.cy.js @@ -27,7 +27,7 @@ describe('Email Recs', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', overrides: { default: { image: { diff --git a/packages/snap-preact-demo/tests/cypress/e2e/templates/recommendation/recommendation.cy.js b/packages/snap-preact-demo/tests/cypress/e2e/templates/recommendation/recommendation.cy.js index a747644fa..776f151a2 100644 --- a/packages/snap-preact-demo/tests/cypress/e2e/templates/recommendation/recommendation.cy.js +++ b/packages/snap-preact-demo/tests/cypress/e2e/templates/recommendation/recommendation.cy.js @@ -59,7 +59,7 @@ describe('Recommendations', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', overrides: { default: { recommendation: { @@ -202,7 +202,7 @@ describe('Recommendations', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', overrides: { default: { recommendation: { diff --git a/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/stylescripts.cy.js b/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/stylescripts.cy.js index 284951a64..274483a3e 100644 --- a/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/stylescripts.cy.js +++ b/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/stylescripts.cy.js @@ -23,7 +23,7 @@ describe('Theme styling works', () => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', style: obj.customStyles, variables: { breakpoints: { mobile: 767, tablet: 991, desktop: 1299 }, @@ -85,7 +85,7 @@ describe('Theme styling works', () => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', style: obj.customStyles, variables: { breakpoints: { mobile: 540, tablet: 767, desktop: 1200 }, diff --git a/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/variables.cy.js b/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/variables.cy.js index 32a4fa2b0..b1374a95d 100644 --- a/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/variables.cy.js +++ b/packages/snap-preact-demo/tests/cypress/e2e/templates/theming/variables.cy.js @@ -10,7 +10,7 @@ describe('Theme variables work', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', variables: { breakpoints: { mobile: 767, @@ -86,7 +86,7 @@ describe('Theme variables work', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', variables: { breakpoints: { mobile: 540, @@ -164,7 +164,7 @@ describe('Theme variables work', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'pike', // variables: { // colors: { // text: '#222222', @@ -201,15 +201,15 @@ describe('Theme variables work', () => { cy.snapController().then(({ store }) => { //accent - cy.get('.ss__select .ss__dropdown .ss__icon').should('have.css', 'fill', 'rgb(58, 35, 173)'); + cy.get('.ss__select .ss__dropdown .ss__icon').should('have.css', 'fill', 'rgb(81, 81, 81)'); // cypress converts all css colors to rgb... //secondary - cy.get('.ss__select .ss__select__select .ss__select__select__option').should('have.css', 'color', 'rgb(109, 113, 117)'); + cy.get('.ss__select .ss__select__select .ss__select__select__option').should('have.css', 'color', 'rgb(0, 174, 239)'); //primary - cy.get('.ss__button').should('have.css', 'color', 'rgb(32, 34, 35)'); + cy.get('.ss__button').should('have.css', 'color', 'rgb(81, 81, 81)'); //text - cy.get('.ss__facet-grid-options a').should('have.css', 'color', 'rgb(34, 34, 34)'); + cy.get('.ss__facet-grid-options a').should('have.css', 'color', 'rgb(81, 81, 81)'); }); }); @@ -219,7 +219,7 @@ describe('Theme variables work', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', variables: { colors: { text: 'rgb(22, 22, 255)', @@ -250,16 +250,19 @@ describe('Theme variables work', () => { cy.visit('https://localhost:2222/templates/'); cy.snapController().then(({ store }) => { - //accent - cy.get('.ss__select .ss__dropdown .ss__icon').should('have.css', 'fill', 'rgb(55, 55, 255)'); + //primary + cy.get('.ss__select .ss__dropdown .ss__icon').should('have.css', 'fill', 'rgb(33, 33, 255)'); // cypress converts all css colors to rgb... + + //base theme currently doesnt use any other colors.. + //secondary - cy.get('.ss__select .ss__select__select .ss__select__select__option').should('have.css', 'color', 'rgb(44, 44, 255)'); + // cy.get('.ss__select .ss__select__select .ss__select__select__option').should('have.css', 'color', 'rgb(44, 44, 255)'); //primary - cy.get('.ss__button').should('have.css', 'color', 'rgb(33, 33, 255)'); - //text - cy.get('.ss__facet-grid-options a').should('have.css', 'color', 'rgb(22, 22, 255)'); + // cy.get('.ss__button').should('have.css', 'color', 'rgb(33, 33, 255)'); + // //text + // cy.get('.ss__facet-grid-options a').should('have.css', 'color', 'rgb(22, 22, 255)'); }); }); @@ -273,7 +276,7 @@ describe('Theme variables work', () => { cy.on('window:before:load', (win) => { win.mergeSnapConfig = { theme: { - extends: 'bocachica', + extends: 'base', variables: { custom: { text: 'custom stuff', diff --git a/packages/snap-preact/components/.storybook/ColorPickerTool.tsx b/packages/snap-preact/components/.storybook/ColorPickerTool.tsx new file mode 100644 index 000000000..72513a073 --- /dev/null +++ b/packages/snap-preact/components/.storybook/ColorPickerTool.tsx @@ -0,0 +1,313 @@ +// .storybook/ColorPickerTool.tsx +// Toolbar color picker addon component for theme color overrides. + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { useGlobals } from '@storybook/manager-api'; + +export const COLOR_KEYS = ['primary', 'secondary', 'accent', 'text'] as const; +export type ColorKey = typeof COLOR_KEYS[number]; +export const GLOBAL_COLOR_PREFIX = 'themeColor_'; +export const DEFAULT_COLOR_PREFIX = 'themeDefaultColor_'; + +const DEBOUNCE_MS = 150; + +export const ColorPickerTool: React.FC = () => { + const [globals, updateGlobals] = useGlobals(); + const [open, setOpen] = React.useState(false); + const [hovered, setHovered] = React.useState(false); + const buttonRef = React.useRef(null); + const [panelPos, setPanelPos] = React.useState({ top: 0, left: 0 }); + + // Local state for instant picker feedback. + const [localColors, setLocalColors] = React.useState>(() => { + const init = {} as Record; + COLOR_KEYS.forEach((k) => { + init[k] = (globals[`${GLOBAL_COLOR_PREFIX}${k}`] as string) || ''; + }); + return init; + }); + + const timers = React.useRef>>>({}); + + const openDropdown = () => { + if (buttonRef.current) { + const rect = buttonRef.current.getBoundingClientRect(); + setPanelPos({ top: rect.bottom + 14, left: rect.left }); + } + setOpen(true); + }; + + // Close on outside click — covers both the manager document and the story iframe. + React.useEffect(() => { + if (!open) return; + const onMouseDown = (e: MouseEvent) => { + const panel = document.getElementById('ss-color-picker-panel'); + if (buttonRef.current?.contains(e.target as Node)) return; + if (panel?.contains(e.target as Node)) return; + setOpen(false); + }; + // Manager frame + document.addEventListener('mousedown', onMouseDown); + // Story iframe + const iframe = document.querySelector('#storybook-preview-iframe'); + iframe?.contentDocument?.addEventListener('mousedown', onMouseDown); + return () => { + document.removeEventListener('mousedown', onMouseDown); + iframe?.contentDocument?.removeEventListener('mousedown', onMouseDown); + }; + }, [open]); + + // Sync local state when globals change externally. + React.useEffect( + () => { + COLOR_KEYS.forEach((k) => { + const globalVal = (globals[`${GLOBAL_COLOR_PREFIX}${k}`] as string) || ''; + setLocalColors((prev) => (prev[k] === globalVal ? prev : { ...prev, [k]: globalVal })); + }); + }, + COLOR_KEYS.map((k) => globals[`${GLOBAL_COLOR_PREFIX}${k}`]) + ); + + const handleChange = (key: ColorKey, value: string) => { + setLocalColors((prev) => ({ ...prev, [key]: value })); + clearTimeout(timers.current[key]); + timers.current[key] = setTimeout(() => { + updateGlobals({ [`${GLOBAL_COLOR_PREFIX}${key}`]: value }); + }, DEBOUNCE_MS); + }; + + const handleReset = (key: ColorKey) => { + clearTimeout(timers.current[key]); + setLocalColors((prev) => ({ ...prev, [key]: '' })); + updateGlobals({ [`${GLOBAL_COLOR_PREFIX}${key}`]: '' }); + }; + + const anyOverridden = COLOR_KEYS.some((k) => localColors[k]); + + const swatches = COLOR_KEYS.map((k) => { + const override = localColors[k]; + const defaultColor = globals[`${DEFAULT_COLOR_PREFIX}${k}`] as string | undefined; + return override || defaultColor || '#cccccc'; + }); + + const panel = open + ? ReactDOM.createPortal( + React.createElement( + 'div', + { + id: 'ss-color-picker-panel', + style: { + position: 'fixed', + top: `${panelPos.top}px`, + left: `${panelPos.left}px`, + zIndex: 99999, + background: '#fff', + borderRadius: '6px', + boxShadow: '0 4px 16px rgba(0,0,0,0.14)', + padding: '10px 14px', + minWidth: '160px', + }, + }, + React.createElement('div', { style: { fontSize: '11px', fontWeight: 600, color: '#666', marginBottom: '8px' } }, 'Theme Color Overrides'), + ...COLOR_KEYS.map((key) => { + const override = localColors[key]; + const defaultColor = globals[`${DEFAULT_COLOR_PREFIX}${key}`] as string | undefined; + const effectiveColor = override || defaultColor || '#000000'; + const isOverridden = Boolean(override); + + return React.createElement( + 'div', + { + key, + style: { + display: 'flex', + alignItems: 'center', + gap: '8px', + padding: '5px 0', + }, + }, + // Swatch / color picker — far left + React.createElement( + 'div', + { + style: { + position: 'relative', + width: '32px', + height: '24px', + borderRadius: '3px', + border: `2px solid ${isOverridden ? '#1D4990' : 'transparent'}`, + background: effectiveColor, + flexShrink: 0, + overflow: 'hidden', + cursor: 'pointer', + }, + }, + React.createElement('input', { + type: 'color', + value: effectiveColor, + onChange: (e: React.ChangeEvent) => handleChange(key, e.target.value), + style: { + position: 'absolute', + inset: 0, + width: '200%', + height: '200%', + padding: 0, + margin: '-25%', + opacity: 0, + cursor: 'pointer', + border: 'none', + }, + }) + ), + // Color name label + hex underneath + React.createElement( + 'div', + { style: { display: 'flex', flexDirection: 'column', flex: 1, gap: '1px' } }, + React.createElement( + 'label', + { + style: { + fontSize: '12px', + color: isOverridden ? '#1D4990' : '#444', + textTransform: 'capitalize', + fontWeight: isOverridden ? '600' : '400', + lineHeight: '1.2', + }, + }, + key + ), + React.createElement( + 'span', + { + style: { + fontSize: '9px', + color: '#aaa', + fontFamily: 'monospace', + lineHeight: '1.2', + }, + }, + effectiveColor + ) + ), + // Reset button / spacer + isOverridden + ? React.createElement( + 'button', + { + onClick: () => handleReset(key), + title: 'Reset to theme default', + style: { + width: '22px', + height: '22px', + padding: '0', + fontSize: '13px', + lineHeight: '1', + cursor: 'pointer', + border: '1px solid #ccc', + borderRadius: '3px', + background: '#fff', + color: '#666', + flexShrink: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + }, + '×' + ) + : React.createElement('div', { style: { width: '22px', flexShrink: 0 } }) + ); + }), + anyOverridden + ? React.createElement( + 'button', + { + onClick: () => COLOR_KEYS.forEach((k) => handleReset(k)), + style: { + marginTop: '8px', + width: '100%', + padding: '4px', + fontSize: '11px', + cursor: 'pointer', + border: '1px solid #ccc', + borderRadius: '3px', + background: '#f8f8f8', + color: '#666', + }, + }, + 'Reset all' + ) + : null + ), + document.body + ) + : null; + + return React.createElement( + React.Fragment, + null, + React.createElement( + 'button', + { + ref: buttonRef, + onClick: () => (open ? setOpen(false) : openDropdown()), + onMouseEnter: () => setHovered(true), + onMouseLeave: () => setHovered(false), + title: 'Theme color overrides', + style: { + display: 'inline-flex', + alignItems: 'center', + alignSelf: 'center', + gap: '6px', + height: '28px', + padding: '0 10px', + cursor: 'pointer', + border: 'none', + borderRadius: '4px', + background: open || hovered ? 'rgba(0,0,0,0.12)' : 'rgba(0,0,0,0.06)', + color: anyOverridden ? '#1D4990' : '#444', + fontSize: '13px', + fontWeight: 700, + whiteSpace: 'nowrap', + outline: 'none', + transition: 'background 0.1s', + lineHeight: '28px', + verticalAlign: 'middle', + }, + }, + React.createElement( + 'div', + { style: { display: 'flex', gap: '2px', alignItems: 'center' } }, + ...swatches.map((color, i) => + React.createElement('div', { + key: i, + style: { + width: '9px', + height: '9px', + borderRadius: '50%', + background: color, + border: '1px solid rgba(0,0,0,0.18)', + flexShrink: 0, + }, + }) + ) + ), + React.createElement('span', { style: { letterSpacing: '0.01em' } }, 'Colors'), + anyOverridden + ? React.createElement('span', { + title: 'Colors overridden', + style: { + width: '6px', + height: '6px', + borderRadius: '50%', + background: '#1D4990', + flexShrink: 0, + marginLeft: '1px', + }, + }) + : null + ), + panel + ); +}; diff --git a/packages/snap-preact/components/.storybook/manager.ts b/packages/snap-preact/components/.storybook/manager.ts index 889e107a6..3dd24c7f0 100644 --- a/packages/snap-preact/components/.storybook/manager.ts +++ b/packages/snap-preact/components/.storybook/manager.ts @@ -1,9 +1,17 @@ -// .storybook/manager.js -// used to style up the UI - using Athos Custom Theme +// .storybook/manager.ts +// Storybook manager-side config: UI theme + toolbar addon registration. -import { addons } from '@storybook/addons'; +import React from 'react'; +import { addons, types } from '@storybook/manager-api'; import athosTheme from './AthosTheme'; +import { ColorPickerTool } from './ColorPickerTool'; -addons.setConfig({ - theme: athosTheme, +addons.setConfig({ theme: athosTheme }); + +addons.register('snap-theme-color-picker', () => { + addons.add('snap-theme-color-picker/tool', { + type: types.TOOL, + title: 'Theme Colors', + render: () => React.createElement(ColorPickerTool), + }); }); diff --git a/packages/snap-preact/components/.storybook/preview.tsx b/packages/snap-preact/components/.storybook/preview.tsx index d9602cc8c..cd1a97ea4 100644 --- a/packages/snap-preact/components/.storybook/preview.tsx +++ b/packages/snap-preact/components/.storybook/preview.tsx @@ -1,14 +1,15 @@ -import { ComponentChildren, Fragment, h } from 'preact'; +import { ComponentChildren, h } from 'preact'; import { withThemeFromJSXProvider } from '@storybook/addon-themes'; +import { useGlobals, useEffect } from '@storybook/preview-api'; import { observer } from 'mobx-react-lite'; import { SnapTemplates, TemplatesStore } from '../../src'; import { ThemeComplete, ThemeProvider } from '../src/providers/theme'; -import { base, bocachica, snappy, snapnco } from '../src/themes'; +import { base, bocachica, everest, matterhorn, pike, snappy, snapnco } from '../src/themes'; // custom styles for storybook import './styles.scss'; -import { SnapProvider, Theme } from '../src'; +import { SnapProvider, Theme, TreePathProvider } from '../src'; // snap instance for theming and templates functionality const snapTemplates = new SnapTemplates({ @@ -22,50 +23,129 @@ const snapTemplates = new SnapTemplates({ }); // need to add each theme synchronously -addTheme(snapTemplates, 'snappy', snappy); +addTheme(snapTemplates, 'base', base); addTheme(snapTemplates, 'bocachica', bocachica); +addTheme(snapTemplates, 'everest', everest); +addTheme(snapTemplates, 'matterhorn', matterhorn); +addTheme(snapTemplates, 'pike', pike); addTheme(snapTemplates, 'snapnco', snapnco); -addTheme(snapTemplates, 'base', base); +addTheme(snapTemplates, 'snappy', snappy); + +// color keys that map to theme variables.colors +const COLOR_KEYS = ['primary', 'secondary', 'accent', 'text'] as const; +type ColorKey = typeof COLOR_KEYS[number]; +const GLOBAL_COLOR_PREFIX = 'themeColor_'; +const DEFAULT_COLOR_PREFIX = 'themeDefaultColor_'; + +// register globals so Storybook persists color overrides and theme defaults across story navigation +export const globalTypes = { + themeColor_primary: { defaultValue: '' }, + themeColor_secondary: { defaultValue: '' }, + themeColor_accent: { defaultValue: '' }, + themeColor_text: { defaultValue: '' }, + themeDefaultColor_primary: { defaultValue: '' }, + themeDefaultColor_secondary: { defaultValue: '' }, + themeDefaultColor_accent: { defaultValue: '' }, + themeDefaultColor_text: { defaultValue: '' }, +}; const Providers = observer( - ({ templateStore, children, themeName }: { templateStore: TemplatesStore; themeName: string; children: ComponentChildren }) => { + ({ + templateStore, + children, + themeName, + colorOverrides, + }: { + templateStore: TemplatesStore; + themeName: string; + colorOverrides: Partial>; + children: ComponentChildren; + }) => { const themeLocation = templateStore.themes.library[themeName]; - const mergedTheme = themeLocation?.theme || {}; + const baseTheme = themeLocation?.theme || {}; + + const hasOverrides = COLOR_KEYS.some((k) => colorOverrides[k]); + const mergedTheme = hasOverrides + ? { + ...baseTheme, + variables: { + ...baseTheme.variables, + colors: { + ...baseTheme.variables?.colors, + ...Object.fromEntries(COLOR_KEYS.filter((k) => colorOverrides[k]).map((k) => [k, colorOverrides[k]])), + }, + }, + } + : baseTheme; return ( - {children} + + {children} + ); } ); -const CustomThemeProvider = ({ theme, children }: { theme: Theme; children: ComponentChildren }) => { - return ( - - {children} - - ); -}; +const CustomThemeProvider = ({ + theme, + children, + colorOverrides, +}: { + theme: Theme; + children: ComponentChildren; + colorOverrides: Partial>; +}) => ( + + {children} + +); export const decorators = [ (Story: any, context: any) => { - // if the component is a template we should utilize the themeStore theme - // otherwise we should use the base theme (stripped of all props except styleScripts) + // useGlobals must be called here in the decorator (valid Storybook hook context) + const [globals, updateGlobals] = useGlobals(); + + // Sync the active theme's default colors into globals so the toolbar can display them + const activeThemeName: string = context.globals.theme || 'base'; + useEffect(() => { + const themeStore = snapTemplates.templates.themes.library[activeThemeName]; + const defaultColors = themeStore?.theme?.variables?.colors as Record | undefined; + if (defaultColors) { + const defaults: Record = {}; + COLOR_KEYS.forEach((k) => { + defaults[`${DEFAULT_COLOR_PREFIX}${k}`] = defaultColors[k] || ''; + }); + updateGlobals(defaults); + } + }, [activeThemeName]); + + const colorOverrides: Partial> = {}; + COLOR_KEYS.forEach((k) => { + const v = globals[`${GLOBAL_COLOR_PREFIX}${k}`]; + if (v) colorOverrides[k] = v; + }); - const templateStory = context.kind.match(/^Template/); + // Bind colorOverrides into the provider + const BoundProvider = ({ theme, children }: { theme: Theme; children: ComponentChildren }) => ( + + {children} + + ); const themeDecoratorFn = withThemeFromJSXProvider({ themes: { - snapnco: templateStory ? snapTemplates.templates.themes.library.snapnco.theme : snapTemplates.templates.themes.local.snapncoSimple.theme, - snappy: templateStory ? snapTemplates.templates.themes.library.snappy.theme : snapTemplates.templates.themes.local.snappySimple.theme, - bocachica: templateStory - ? snapTemplates.templates.themes.library.bocachica.theme - : snapTemplates.templates.themes.local.bocachicaSimple.theme, - base: templateStory ? snapTemplates.templates.themes.library.base.theme : snapTemplates.templates.themes.local.baseSimple.theme, + snapnco: snapTemplates.templates.themes.library.snapnco.theme, + snappy: snapTemplates.templates.themes.library.snappy.theme, + bocachica: snapTemplates.templates.themes.library.bocachica.theme, + base: snapTemplates.templates.themes.library.base.theme, + everest: snapTemplates.templates.themes.library.everest.theme, + matterhorn: snapTemplates.templates.themes.library.matterhorn.theme, + pike: snapTemplates.templates.themes.library.pike.theme, }, defaultTheme: 'base', - Provider: templateStory ? CustomThemeProvider : ThemeProvider, + Provider: BoundProvider, }); return themeDecoratorFn(Story, context); @@ -101,36 +181,4 @@ function addTheme(snapTemplates: SnapTemplates, themeName: string, theme: ThemeC currency: {}, innerWidth: window.innerWidth, }); - snapTemplates.templates.addTheme({ - name: `${themeName}Simple`, - type: 'local', - base: generateSimpleTheme(theme), - language: {}, - languageOverrides: {}, - currency: {}, - innerWidth: window.innerWidth, - }); -} - -function generateSimpleTheme(theme: ThemeComplete): ThemeComplete { - // strip off everything except for stylescripts and variables - - const simpleTheme: ThemeComplete = { - name: theme.name, - variables: theme.variables, - components: {}, - responsive: {}, - }; - - for (const componentName in theme.components) { - const componentProps = theme.components[componentName as keyof typeof theme.components]; - simpleTheme.components![componentName as keyof typeof simpleTheme.components] = { - // @ts-ignore - type was removed for overrides - styleScript: componentProps?.styleScript, - // @ts-ignore - type was removed for overrides - themeStyleScript: componentProps?.themeStyleScript, - }; - } - // return theme; - return simpleTheme; } diff --git a/packages/snap-preact/components/src/components/Atoms/Breadcrumbs/Breadcrumbs.stories.tsx b/packages/snap-preact/components/src/components/Atoms/Breadcrumbs/Breadcrumbs.stories.tsx index 5e11f4fdc..f944ff6c9 100644 --- a/packages/snap-preact/components/src/components/Atoms/Breadcrumbs/Breadcrumbs.stories.tsx +++ b/packages/snap-preact/components/src/components/Atoms/Breadcrumbs/Breadcrumbs.stories.tsx @@ -84,7 +84,6 @@ categoryPage.args = { label: 'Fridge', }, ], - separator: '/', }; export const SearchPage = (args: BreadcrumbsProps) => ; diff --git a/packages/snap-preact/components/src/components/Atoms/Button/Button.tsx b/packages/snap-preact/components/src/components/Atoms/Button/Button.tsx index 192f1da1d..879737a0a 100644 --- a/packages/snap-preact/components/src/components/Atoms/Button/Button.tsx +++ b/packages/snap-preact/components/src/components/Atoms/Button/Button.tsx @@ -14,7 +14,7 @@ import deepmerge from 'deepmerge'; import Color from 'color'; const defaultStyles: StyleScript = ({ native, color, backgroundColor, borderColor, theme }) => { - const lightenedPrimaryColorObj = new Color(backgroundColor || color || theme?.variables?.colors?.primary).lightness(95); + const lightenedPrimaryColorObj = new Color(backgroundColor || color || theme?.variables?.colors?.primary || undefined).lightness(95); // no styling on native if (native) { diff --git a/packages/snap-preact/components/src/components/Atoms/Icon/Icon.stories.tsx b/packages/snap-preact/components/src/components/Atoms/Icon/Icon.stories.tsx index f4494928c..5567d8cb9 100644 --- a/packages/snap-preact/components/src/components/Atoms/Icon/Icon.stories.tsx +++ b/packages/snap-preact/components/src/components/Atoms/Icon/Icon.stories.tsx @@ -181,7 +181,7 @@ export const Gallery = (): JSX.Element => { .map((icon) => { return (
- +
{icon}
); diff --git a/packages/snap-preact/components/src/components/Atoms/Icon/Icon.test.tsx b/packages/snap-preact/components/src/components/Atoms/Icon/Icon.test.tsx index f84905710..8e35efec4 100644 --- a/packages/snap-preact/components/src/components/Atoms/Icon/Icon.test.tsx +++ b/packages/snap-preact/components/src/components/Atoms/Icon/Icon.test.tsx @@ -92,7 +92,6 @@ describe('Icon Component', () => { const styles = getComputedStyle(svg); expect(styles.width).toBe(defaultProps.size); expect(styles.height).toBe(defaultProps.size); - expect(styles.fill).toBe(defaultProps.color); const path = svg.querySelector('path'); expect(path).toHaveAttribute('d', iconPaths[icon]); @@ -193,7 +192,6 @@ describe('Icon Component', () => { const styles = getComputedStyle(svg); expect(styles.width).toBe(defaultProps.size); expect(styles.height).toBe(defaultProps.size); - expect(styles.fill).toBe(defaultProps.color); const path = svg.querySelector('path'); expect(path).toHaveAttribute('d', svgPath); diff --git a/packages/snap-preact/components/src/components/Atoms/SearchHeader/SearchHeader.stories.tsx b/packages/snap-preact/components/src/components/Atoms/SearchHeader/SearchHeader.stories.tsx index f2420fdd8..f2c382770 100644 --- a/packages/snap-preact/components/src/components/Atoms/SearchHeader/SearchHeader.stories.tsx +++ b/packages/snap-preact/components/src/components/Atoms/SearchHeader/SearchHeader.stories.tsx @@ -93,8 +93,7 @@ export default { summary: 'string', }, defaultValue: { - summary: - 'Showing 1-30 of 8,474 results for "*"', + summary: 'Search results', }, }, control: { type: 'text' }, @@ -114,7 +113,10 @@ export default { type: { summary: 'string', }, - defaultValue: { summary: '
No results found for "*", showing results for "hat" instead.
' }, + defaultValue: { + summary: + 'No results found for "${search?.originalQuery?.string}", showing results for "${search?.query?.string}" instead.', + }, }, control: { type: 'text' }, }, diff --git a/packages/snap-preact/components/src/components/Molecules/Carousel/Carousel.stories.tsx b/packages/snap-preact/components/src/components/Molecules/Carousel/Carousel.stories.tsx index 890ce9f89..f967ee352 100644 --- a/packages/snap-preact/components/src/components/Molecules/Carousel/Carousel.stories.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Carousel/Carousel.stories.tsx @@ -190,7 +190,7 @@ export const Colors = (props: CarouselProps) => { return ( {colors.map((number, index) => ( -
+
))}
); diff --git a/packages/snap-preact/components/src/components/Molecules/FacetGridOptions/FacetGridOptions.tsx b/packages/snap-preact/components/src/components/Molecules/FacetGridOptions/FacetGridOptions.tsx index c3bd61759..625091d01 100644 --- a/packages/snap-preact/components/src/components/Molecules/FacetGridOptions/FacetGridOptions.tsx +++ b/packages/snap-preact/components/src/components/Molecules/FacetGridOptions/FacetGridOptions.tsx @@ -15,7 +15,7 @@ import Color from 'color'; const defaultStyles: StyleScript = ({ columns, gapSize, gridSize, theme }) => { const variables = theme?.variables; - const backgroundColor = new Color(variables?.colors.primary); + const backgroundColor = new Color(variables?.colors.primary || undefined); const color = backgroundColor.isDark() ? '#fff' : '#000'; return css({ diff --git a/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.stories.tsx b/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.stories.tsx index 8997f2b67..c8036dcb8 100644 --- a/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.stories.tsx +++ b/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.stories.tsx @@ -31,13 +31,7 @@ export default { ), }, }, - decorators: [ - (Story: any) => ( -
- -
- ), - ], + decorators: [(Story: any) => ], argTypes: { values: { description: 'Facet.values store reference', @@ -209,7 +203,11 @@ const ObservableFacetPaletteOptions = observer(({ args, controller }: { args: Fa }); export const Default = (args: FacetPaletteOptionsProps, { loaded: { controller } }: { loaded: { controller: SearchController } }) => { - return ; + return ( +
+ +
+ ); }; Default.loaders = [ diff --git a/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.tsx b/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.tsx index bc99654cd..f4b74ab63 100644 --- a/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.tsx +++ b/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/FacetPaletteOptions.tsx @@ -16,6 +16,7 @@ import { Checkbox, CheckboxProps } from '../Checkbox'; import { Lang, useLang } from '../../../hooks'; import deepmerge from 'deepmerge'; import Color from 'color'; +import { Image, ImageProps } from '../../Atoms/Image'; const defaultStyles: StyleScript = ({ columns, gridSize, gapSize, horizontal, theme }) => { return css({ @@ -63,6 +64,11 @@ const defaultStyles: StyleScript = ({ columns, gridSiz strokeLinejoin: 'round', opacity: 0, }, + + '&.ss__facet-palette-options__option__palette--image': { + paddingTop: '0', + height: 'auto', + }, }, '.ss__facet-palette-options__option__value': { display: 'block', @@ -206,6 +212,17 @@ export const FacetPaletteOptions = observer((properties: FacetPaletteOptionsProp theme: props?.theme, treePath, }, + image: { + // default props + internalClassName: 'ss__facet-palette-options__image', + // inherited props + ...defined({ + disableStyles, + }), + // component theme overrides + theme: props?.theme, + treePath, + }, checkbox: { // default props internalClassName: 'ss__facet-palette-options__checkbox', @@ -262,6 +279,13 @@ export const FacetPaletteOptions = observer((properties: FacetPaletteOptionsProp ? lowerCaseColorMapping[value.label.toLowerCase()].background : value.value; + const backgroundImageUrl = + lowerCaseColorMapping && + lowerCaseColorMapping[value.label.toLowerCase()] && + lowerCaseColorMapping[value.label.toLowerCase()].backgroundImageUrl + ? lowerCaseColorMapping[value.label.toLowerCase()].backgroundImageUrl + : undefined; + let isDark = false; if (background) { try { @@ -297,12 +321,18 @@ export const FacetPaletteOptions = observer((properties: FacetPaletteOptionsProp
+ {backgroundImageUrl ? ( + {value.label + ) : ( + + )} {!hideIcon && value.filtered && layout?.toLowerCase() == 'grid' && }
@@ -341,6 +371,7 @@ export interface FacetPaletteOptionsProps extends ComponentProps { [name: string]: { label?: string; background?: string; + backgroundImageUrl?: string; }; }; lang?: Partial; @@ -354,6 +385,7 @@ export interface FacetPaletteOptionsLang { } interface FacetPaletteOptionsSubProps { - icon: IconProps; - checkbox: CheckboxProps; + icon: Partial; + checkbox: Partial; + image: Partial; } diff --git a/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/readme.md b/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/readme.md index b478b856b..d1b73f211 100644 --- a/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/readme.md +++ b/packages/snap-preact/components/src/components/Molecules/FacetPaletteOptions/readme.md @@ -132,7 +132,10 @@ The `onClick` prop allows for a custom callback function for when a facet value #### colorMapping -The colorMapping prop allows for custom color mapping overrides. The object used is keyed by a color label, and can take background and label properties. The color label can be any accepted CSS background property value. So a color, string, hash, RGB, gradiant, or an image URL could be used. The label takes a string value and replaces the color's original label for display. +The colorMapping prop allows for custom color mapping overrides. The object used is keyed by a color label, and can take background, backgroundImageUrl and label properties. +The color label can be any accepted CSS background property value. So a color, string, hash, RGB, gradiant, or an image URL could be used. +The label takes a string value and replaces the color's original label for display. +The backgroundImageUrl will render an actual HTML Image element rather than css background url. ```jsx const colorMapping = { @@ -140,6 +143,10 @@ const colorMapping = { background: 'brown', label: 'Army' }, + 'Red': { + backgroundImageUrl: 'https://s3-figma-hubfile-images-production.figma.com/hub/file/carousel/img/bfbec80cfd07b650c2f02b5f8a8c29b3c726e9da', + label: 'Red' + }, 'Striped': { background: "url(https://mysite.com/cdn/shop/files/candy-stripe-square_small.jpg)", label: "stripy" diff --git a/packages/snap-preact/components/src/components/Molecules/Filter/Filter.tsx b/packages/snap-preact/components/src/components/Molecules/Filter/Filter.tsx index 7b059c55f..16c1463cc 100644 --- a/packages/snap-preact/components/src/components/Molecules/Filter/Filter.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Filter/Filter.tsx @@ -26,6 +26,7 @@ const defaultStyles: StyleScript = ({}) => { }, '& .ss__filter__label': { marginRight: '5px', + marginLeft: '5px', fontWeight: 'bold', }, }); diff --git a/packages/snap-preact/components/src/components/Molecules/Grid/Grid.stories.tsx b/packages/snap-preact/components/src/components/Molecules/Grid/Grid.stories.tsx index 85b7a3b9f..81f609e00 100644 --- a/packages/snap-preact/components/src/components/Molecules/Grid/Grid.stories.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Grid/Grid.stories.tsx @@ -237,8 +237,8 @@ DisabledOption.args = { ], } as GridProps; -export const backgroundImages = (args: GridProps) => ; -backgroundImages.args = { +export const Images = (args: GridProps) => ; +Images.args = { options: [ { value: 'Faded Khaki', diff --git a/packages/snap-preact/components/src/components/Molecules/Grid/Grid.tsx b/packages/snap-preact/components/src/components/Molecules/Grid/Grid.tsx index f4f0c0b0f..a6c963920 100644 --- a/packages/snap-preact/components/src/components/Molecules/Grid/Grid.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Grid/Grid.tsx @@ -307,7 +307,6 @@ export function Grid(properties: GridProps): JSX.Element { 'ss__grid__option--unavailable': option?.available === false, 'ss__grid__option--dark': isDark, })} - style={{ background: option.background ? option.background : option.backgroundImageUrl ? undefined : option.value }} onClick={(e) => !disabled && !option?.disabled && makeSelection(e as any, option)} ref={(e) => useA11y(e)} title={option.label || option.value.toString()} @@ -315,7 +314,10 @@ export function Grid(properties: GridProps): JSX.Element { aria-selected={selected} aria-disabled={option.disabled} > -
+
{!option.background && option.backgroundImageUrl ? ( {option.label ) : ( diff --git a/packages/snap-preact/components/src/components/Molecules/LoadMore/LoadMore.tsx b/packages/snap-preact/components/src/components/Molecules/LoadMore/LoadMore.tsx index fb94c2750..683e4ac34 100644 --- a/packages/snap-preact/components/src/components/Molecules/LoadMore/LoadMore.tsx +++ b/packages/snap-preact/components/src/components/Molecules/LoadMore/LoadMore.tsx @@ -21,11 +21,8 @@ const defaultStyles: StyleScript = ({ pagination, progressIndicat flexDirection: 'column', alignItems: 'center', gap: '20px', - '& .ss__load-more__button--disabled': { opacity: 0.7, - borderColor: 'rgba(51,51,51,0.7)', - backgroundColor: 'initial', pointerEvents: 'none', '&:hover': { cursor: 'default', diff --git a/packages/snap-preact/components/src/components/Molecules/Rating/Rating.tsx b/packages/snap-preact/components/src/components/Molecules/Rating/Rating.tsx index 30c4b020d..7a54d6c1c 100644 --- a/packages/snap-preact/components/src/components/Molecules/Rating/Rating.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Rating/Rating.tsx @@ -12,6 +12,7 @@ const defaultStyles: StyleScript = () => { return css({ display: 'flex', alignItems: 'center', + justifyContent: 'center', '& .ss__rating__icons': { position: 'relative', diff --git a/packages/snap-preact/components/src/components/Molecules/Result/Result.stories.tsx b/packages/snap-preact/components/src/components/Molecules/Result/Result.stories.tsx index 6e29a04c2..c8cae794b 100644 --- a/packages/snap-preact/components/src/components/Molecules/Result/Result.stories.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Result/Result.stories.tsx @@ -230,7 +230,7 @@ export default { const snapInstance = Snapify.search({ id: 'Result', globals: { siteId: 'atkzs2' } }); export const Default = (args: ResultProps, { loaded: { controller } }: { loaded: { controller: SearchController } }) => ( - + ); Default.loaders = [ @@ -243,7 +243,7 @@ Default.loaders = [ ]; export const hideSections = (args: ResultProps, { loaded: { controller } }: { loaded: { controller: SearchController } }) => ( - + ); hideSections.loaders = [ @@ -261,7 +261,7 @@ hideSections.args = { }; export const truncateTitle = (args: ResultProps, { loaded: { controller } }: { loaded: { controller: SearchController } }) => ( - + ); truncateTitle.loaders = [ diff --git a/packages/snap-preact/components/src/components/Molecules/Result/Result.tsx b/packages/snap-preact/components/src/components/Molecules/Result/Result.tsx index 8a03c002d..4b7e6640f 100644 --- a/packages/snap-preact/components/src/components/Molecules/Result/Result.tsx +++ b/packages/snap-preact/components/src/components/Molecules/Result/Result.tsx @@ -53,11 +53,6 @@ const defaultStyles: StyleScript = () => { }, }, - '& .ss__result__details__rating-wrapper': { - display: 'flex', - justifyContent: 'center', - }, - '& .ss__result__details': { padding: '10px', textAlign: 'center', @@ -292,13 +287,9 @@ export const Result = observer((properties: ResultProps): JSX.Element => { />
)} - {!hideRating && ( -
- -
- )} + {!hideRating && } - {!hidePricing && ( + {!hidePricing && core.price && core.price > 0 ? (
{isOnSale ? ( <> @@ -310,11 +301,11 @@ export const Result = observer((properties: ResultProps): JSX.Element => { )}
- )} + ) : null} {cloneWithProps(detailSlot, { result, treePath })} - {!hideVariantSelections && ( + {!hideVariantSelections && result.variants?.selections.length && (
{result.variants?.selections.map((selection) => { return ; diff --git a/packages/snap-preact/components/src/components/Molecules/SearchInput/SearchInput.tsx b/packages/snap-preact/components/src/components/Molecules/SearchInput/SearchInput.tsx index 05557a601..64d6c0768 100644 --- a/packages/snap-preact/components/src/components/Molecules/SearchInput/SearchInput.tsx +++ b/packages/snap-preact/components/src/components/Molecules/SearchInput/SearchInput.tsx @@ -136,8 +136,7 @@ export const SearchInput = observer((properties: SearchInputProps): JSX.Element ...clearSearchButton, internalClassName: 'ss__search-input__button--clear-search-button', name: 'clear-search', - - onClick: () => { + onClick: (e) => { if (inputRef?.current) { //reset the input value (inputRef?.current as HTMLInputElement).value = ''; @@ -148,8 +147,7 @@ export const SearchInput = observer((properties: SearchInputProps): JSX.Element setInputValue && setInputValue(''); - // @ts-ignore - this is a button, so it should have an onClick prop? - clearSearchButton?.onClick && clearSearchButton.onClick(); + clearSearchButton?.onClick && clearSearchButton.onClick(e); }, // inherited props ...defined({ @@ -230,7 +228,6 @@ export const SearchInput = observer((properties: SearchInputProps): JSX.Element }} disabled={disabled} /> -
{clearSearchButton && inputValue?.length ?
)} @@ -796,7 +800,10 @@ export const Autocomplete = observer((properties: AutocompleteProps): JSX.Elemen {...mergedLang.seeMoreButton.attributes} > - + ))} + />
) : null @@ -867,6 +874,7 @@ export interface AutocompleteProps extends ComponentProps { contentTitle?: string; viewportMaxHeight?: boolean; seeMoreButtonText?: string | ((controller: AutocompleteController) => string); + seeMoreButtonIcon?: IconType | Partial | boolean; termsSlot?: JSX.Element | JSX.Element[]; facetsSlot?: JSX.Element | JSX.Element[]; contentSlot?: JSX.Element | JSX.Element[]; diff --git a/packages/snap-preact/components/src/components/Organisms/Autocomplete/readme.md b/packages/snap-preact/components/src/components/Organisms/Autocomplete/readme.md index 756346af0..ce0ce8ad1 100644 --- a/packages/snap-preact/components/src/components/Organisms/Autocomplete/readme.md +++ b/packages/snap-preact/components/src/components/Organisms/Autocomplete/readme.md @@ -89,6 +89,17 @@ The `contentTitle` prop will display the given text above the autocomplete conte ``` +### seeMoreButtonIcon +The `seeMoreButtonIcon` prop will display the given icon in the see more button. + +```jsx + +``` + +The `seeMoreButtonText` prop can also take a function returning a string. The function is pased the Autocomplete controller. + +```jsx + ### seeMoreButtonText The `seeMoreButtonText` prop will display the given text in the see more button. diff --git a/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.stories.tsx b/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.stories.tsx index 600493152..18341e8c5 100644 --- a/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.stories.tsx +++ b/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.stories.tsx @@ -80,7 +80,7 @@ export default { table: { type: { summary: - "['c1' | 'c2' | 'c3' | 'c4' | 'termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']", + "['c1' | 'c2' | 'c3' | 'c4' | 'termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | 'no-results' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']", }, defaultValue: { summary: "[['c1','c2', 'c3']]" }, }, @@ -91,7 +91,7 @@ export default { table: { type: { summary: - "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", + "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | 'no-results' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", }, defaultValue: { summary: `{ @@ -107,7 +107,7 @@ export default { table: { type: { summary: - "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", + "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | 'no-results' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", }, defaultValue: { summary: `{ @@ -123,7 +123,7 @@ export default { table: { type: { summary: - "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", + "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | 'no-results' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", }, defaultValue: { summary: `{ @@ -139,7 +139,7 @@ export default { table: { type: { summary: - "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", + "{width: '150px', layout: ['termsList' | 'terms.history' | 'terms.trending'| 'terms.suggestions'| 'facets' | 'facetsHorizontal' | 'button.see-more' | 'content' | 'no-results' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header']}", }, }, control: 'array', diff --git a/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.tsx b/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.tsx index f4706e1f0..dee738369 100644 --- a/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.tsx +++ b/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/AutocompleteLayout.tsx @@ -227,6 +227,14 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) let props = mergeProps('autocompleteLayout', globalTheme, defaultProps, properties); delete props.treePath; + if (props.layout == 'terms') { + props.templates = { + recommendation: { + enabled: false, + }, + }; + } + const valueProps = createHoverProps(); const facetClickEvent = () => { @@ -261,6 +269,9 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) limit: 6, disableOverflow: true, disableCollapse: true, + searchable: false, + showClearAllText: false, + showSelectedCount: false, }, facetGridOptions: { columns: 3, @@ -307,7 +318,6 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) const { facetsTitle, contentTitle, - layout, column1, column2, column3, @@ -321,6 +331,8 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) internalClassName, controller, } = props; + let layout = props.layout; + const subProps: AutocompleteSubProps = { button: { internalClassName: 'ss__autocomplete__button--see-more', @@ -339,6 +351,7 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) }, termsList: { internalClassName: 'ss__autocomplete__terms-list', + verticalOptions: props.layout == 'terms' || props.layout == 'mini' ? false : true, // default props controller: controller, // inherited props @@ -350,6 +363,7 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) }, terms: { internalClassName: 'ss__autocomplete__terms', + vertical: props.layout == 'terms' || props.layout == 'mini' ? false : true, // default props controller: controller, // inherited props @@ -682,6 +696,31 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) ); } + if (module == 'no-results' && showResults) { + return ( +
+ {results.length == 0 && !loading ? ( +
+
+ {RecommendationTemplateComponent && recsController?.store?.loaded ? ( +
+ +
+ ) : null} +
+ ) : ( + <> + )} +
+ ); + } + if (module == '_') { return
; } @@ -709,12 +748,31 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) } }; + if (typeof props.layout === 'string') { + if (props.layout === 'terms') { + layout = [['termsList'], ['no-results'], ['_', 'button.see-more']]; + } + if (props.layout === 'mini') { + layout = [['termsList'], ['content'], ['_', 'button.see-more']]; + } + + if (props.layout === 'standard') { + layout = [['c1', 'c2', 'c3']]; + } + } + /***************************************/ return visible && layout?.length ? (
e.stopPropagation()} ref={(e) => useA11y(e, 0, false, reset)} > @@ -727,7 +785,7 @@ export const AutocompleteLayout = observer((properties: AutocompleteLayoutProps) {...mergedLang.closeButton?.all} > - {layout?.map((module) => { + {(layout as ModuleNamesWithColumns[])?.map((module) => { return findModule(module as ModuleNames); })}
@@ -758,12 +816,14 @@ export type ModuleNames = | 'facetsHorizontal' | 'button.see-more' | 'content' + | 'no-results' | '_' | 'banner.left' | 'banner.banner' | 'banner.footer' | 'banner.header'; type ColumnsNames = 'c1' | 'c2' | 'c3' | 'c4'; +type PrebuiltLayouts = 'terms' | 'mini' | 'standard'; type ModuleNamesWithColumns = ModuleNames | ColumnsNames | ModuleNames[] | ColumnsNames[]; type Column = { @@ -775,7 +835,7 @@ type Column = { export interface AutocompleteLayoutProps extends ComponentProps { input: Element | string; controller: AutocompleteController; - layout?: ModuleNamesWithColumns[]; + layout?: ModuleNamesWithColumns[] | PrebuiltLayouts; column1?: Column; column2?: Column; diff --git a/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/readme.md b/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/readme.md index 44dcd472e..ff264fe35 100644 --- a/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/readme.md +++ b/packages/snap-preact/components/src/components/Organisms/AutocompleteLayout/readme.md @@ -45,7 +45,7 @@ The `_` module is used a seperator module to center|left|right justify the other available modules to use in the layout are -`c1`, `c2`, `c3`, `c4`, `termsList`, `terms.history`, `terms.trending`, `terms.suggestions`, `facets`, `facetsHorizontal`, `button.see-more`, `content`, `_`, `banner.left`, `banner.banner`, `banner.footer`, `banner.header` +`c1`, `c2`, `c3`, `c4`, `termsList`, `terms.history`, `terms.trending`, `terms.suggestions`, `facets`, `facetsHorizontal`, `button.see-more`, `content`, `no-results`, `_`, `banner.left`, `banner.banner`, `banner.footer`, `banner.header` ```jsx diff --git a/packages/snap-preact/components/src/components/Organisms/Facet/Facet.stories.tsx b/packages/snap-preact/components/src/components/Organisms/Facet/Facet.stories.tsx index 0d458c8d1..baf88678d 100644 --- a/packages/snap-preact/components/src/components/Organisms/Facet/Facet.stories.tsx +++ b/packages/snap-preact/components/src/components/Organisms/Facet/Facet.stories.tsx @@ -379,6 +379,18 @@ export default { type: 'object', }, }, + display: { + defaultValue: {}, + description: 'Change props per facet display type', + table: { + type: { + summary: 'object', + }, + }, + control: { + type: 'object', + }, + }, ...componentArgs, }, }; diff --git a/packages/snap-preact/components/src/components/Organisms/Facet/Facet.tsx b/packages/snap-preact/components/src/components/Organisms/Facet/Facet.tsx index 93ee0fdcb..486c16c24 100644 --- a/packages/snap-preact/components/src/components/Organisms/Facet/Facet.tsx +++ b/packages/snap-preact/components/src/components/Organisms/Facet/Facet.tsx @@ -167,6 +167,7 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { iconCollapse, iconExpand, limit, + statefulOverflow, disableOverflow, iconColor, color, @@ -202,7 +203,7 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { // default props internalClassName: 'ss__facet__dropdown__icon', size: '12px', - color: iconColor || color, + fill: iconColor || color, // inherited props ...defined({ disableStyles, @@ -224,7 +225,7 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { // default props internalClassName: 'ss__facet__show-more-less__icon', size: '10px', - color: iconColor || color, + fill: iconColor || color, // inherited props ...defined({ disableStyles, @@ -325,9 +326,89 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { }; let limitedValues: Array; + + function escapeRegExp(string: string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string + } + + const [overflowState, setOverflowState] = useState(); + + useEffect(() => { + if (statefulOverflow) { + const interalOverflow: { + enabled: boolean; + limited: boolean; + limit: number; + remaining: number | undefined; + setLimit: (limit: number) => void; + toggle: (val?: boolean) => void; + calculate: () => void; + } = { + enabled: false, + limited: true, + limit: 0, + remaining: undefined, + setLimit: function (limit: number) { + if (limit != this.limit) { + this.enabled = true; + this.limit = limit; + this.calculate(); + } + }, + toggle: function (val?: boolean) { + if (typeof val != 'undefined') { + this.limited = val; + } else { + this.limited = !this.limited; + } + + this.calculate(); + }, + calculate: function () { + if (this.limit > 0) { + const remaining = (facet as ValueFacet)?.values?.length - this.limit; + + if (remaining > 0 && !(facet as ValueFacet)?.search?.input) { + this.enabled = true; + + if (this.limited) { + this.remaining = remaining; + } else { + this.remaining = 0; + } + } else { + this.enabled = false; + } + } + + setOverflowState({ ...this }); + }, + }; + + setOverflowState(interalOverflow); + } + }, []); + if ((facet as ValueFacet)?.overflow && limit && Number.isInteger(limit) && !disableOverflow) { - (facet as ValueFacet).overflow?.setLimit(limit); - limitedValues = (facet as ValueFacet)?.refinedValues; + if (statefulOverflow) { + let values = (facet as ValueFacet)?.values || []; + + if ((facet as ValueFacet)?.search?.input) { + const search = new RegExp(escapeRegExp((facet as ValueFacet)?.search?.input), 'i'); + values = (facet as ValueFacet)?.values.filter((value) => String(value?.label || '').match(search)); + } + + if (overflowState?.enabled && overflowState?.limited) { + values = values.slice(0, overflowState?.limit); + } + if (overflowState?.limit !== limit) { + overflowState?.setLimit(limit); + } + limitedValues = values; + } else { + (facet as ValueFacet).overflow?.setLimit(limit); + limitedValues = (facet as ValueFacet)?.refinedValues; + } } else if ((facet as ValueFacet)?.overflow && Number.isInteger(limit)) { limitedValues = (facet as ValueFacet)?.values.slice(0, limit); } else { @@ -338,7 +419,7 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { // Search within facet const searchableFacet = { - allowableTypes: ['list', 'grid', 'palette'], + allowableTypes: properties.treePath?.includes('autocomplete') ? [] : ['list', 'grid', 'palette'], searchFilter: (e: React.ChangeEvent) => { if ((facet as ValueFacet)?.search) { (facet as ValueFacet).search.input = e.target.value; @@ -353,6 +434,7 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { const facetContentProps = { limitedValues, + overflowState, searchableFacet, subProps, className, @@ -389,7 +471,10 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { facet, }); - const selectedCount = (facet as ValueFacet)?.values?.filter((value) => value?.filtered).length; + const selectedCount = + (facet as ValueFacet)?.values?.filter((value) => value?.filtered).length || + (facet as RangeFacet)?.active?.high !== (facet as RangeFacet)?.range?.high || + (facet as RangeFacet)?.active?.low !== (facet as RangeFacet)?.range?.low; return facet && renderFacet ? ( @@ -402,7 +487,9 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { className, internalClassName, `${facet.display ? `ss__facet--${facet.display}` : ''}`, - ((facet as ValueFacet)?.overflow?.remaining || 0) > 0 || facet?.display == 'slider' ? '' : 'ss__facet--showing-all' + (statefulOverflow ? overflowState?.remaining || 0 > 0 : ((facet as ValueFacet)?.overflow?.remaining || 0) > 0) || facet?.display == 'slider' + ? '' + : 'ss__facet--showing-all' )} > {justContent ? ( @@ -423,7 +510,7 @@ export const Facet = observer((properties: FacetProps): JSX.Element => { >
{facet?.label} - {showSelectedCount && selectedCount ? ( + {showSelectedCount && selectedCount && facet.type !== 'range' ? ( {hideSelectedCountParenthesis ? selectedCount : `(${selectedCount})`} ) : null} {(mergedLang.clearAllText.value || clearAllIcon) && selectedCount ? ( @@ -475,6 +562,7 @@ const FacetContent = ( }; subProps: FacetSubProps; mergedLang: LangAttributesObj; + overflowState?: overflowStateType; } ) => { const { @@ -484,6 +572,7 @@ const FacetContent = ( internalClassName, limitedValues, facet, + statefulOverflow, limit, overflowSlot, optionsSlot, @@ -535,6 +624,13 @@ const FacetContent = ( const submitButtonRef: MutableRef = useRef(); + let overflowState: overflowStateType | undefined; + if (!statefulOverflow) { + overflowState = (facet as ValueFacet).overflow; + } else { + overflowState = props.overflowState; + } + return ( {searchable && searchableFacet.allowableTypes.includes(facet.display) && ( @@ -670,13 +766,8 @@ const FacetContent = (
)} - {!disableOverflow && (facet as ValueFacet)?.overflow?.enabled && ( -
(facet as ValueFacet).overflow?.toggle()} - ref={(e) => useA11y(e)} - > + {!disableOverflow && overflowState?.enabled && ( +
overflowState?.toggle()} ref={(e) => useA11y(e)}> {overflowSlot ? ( cloneWithProps(overflowSlot, { facet, treePath }) ) : ( @@ -684,14 +775,12 @@ const FacetContent = ( 0 + {...((overflowState?.remaining || 0) > 0 ? { ...(typeof iconOverflowMore == 'string' ? { icon: iconOverflowMore } : (iconOverflowMore as Partial)) } : { ...(typeof iconOverflowLess == 'string' ? { icon: iconOverflowLess } : (iconOverflowLess as Partial)) })} /> {!hideShowMoreLessText && ( - 0 ? mergedLang!.showMoreText?.all : mergedLang!.showLessText?.all)} - > + 0 ? mergedLang!.showMoreText?.all : mergedLang!.showLessText?.all)}> )} )} @@ -726,6 +815,7 @@ interface OptionalFacetProps extends ComponentProps { iconColor?: string; iconExpand?: IconType | Partial; limit?: number; + statefulOverflow?: boolean; overflowSlot?: JSX.Element | JSX.Element[]; optionsSlot?: JSX.Element | JSX.Element[]; disableOverflow?: boolean; @@ -775,3 +865,13 @@ export interface FacetLang { type FieldProps = { [variable: string]: Omit; }; + +type overflowStateType = { + enabled: boolean; + limited: boolean; + limit: number; + remaining: number | undefined; + setLimit: (limit: number) => void; + toggle: (val?: boolean) => void; + calculate: () => void; +}; diff --git a/packages/snap-preact/components/src/components/Organisms/Facet/readme.md b/packages/snap-preact/components/src/components/Organisms/Facet/readme.md index d77043d35..9010245e2 100644 --- a/packages/snap-preact/components/src/components/Organisms/Facet/readme.md +++ b/packages/snap-preact/components/src/components/Organisms/Facet/readme.md @@ -111,16 +111,15 @@ The `hideShowMoreLessText` prop hides the show more / show less text. ``` - ### showSelectedCount -The `showSelectedCount` prop shows the number of selected options within the facet in the facet header. +The `showSelectedCount` prop shows the number of selected options within the facet in the facet header. NOTE: this prop will not work if `justContent` prop enabled. ```jsx ``` ### hideSelectedCountParenthesis -The `hideSelectedCountParenthesis` prop specifies if the parenthesis should render around the selected count in the facet header. +The `hideSelectedCountParenthesis` prop specifies if the parenthesis should render around the selected count in the facet header. NOTE: this prop will not work if `justContent` prop enabled. ```jsx @@ -236,6 +235,32 @@ const fieldsProp = { ``` +### display +The `display` prop allows you to manually change prop values on a per-facet display type level + +```typescript +const displayProp = { + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 3 + }, + grid: { + limit: 10 + }, + palette: { + limit: 20 + } + } +}, +``` + +```jsx + +``` + ### optionsSlot The `optionsSlot` prop is a JSX element used to manually set the options component used, regardless of the facet.display type. Returns the facet,valueProps, limit, & previewOnFocus prop values. diff --git a/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.stories.tsx b/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.stories.tsx index 6454a2d18..613dd3b78 100644 --- a/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.stories.tsx +++ b/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.stories.tsx @@ -93,6 +93,59 @@ export default { }, control: { type: 'boolean' }, }, + showSelectedCount: { + description: 'shows the number of selected options within the facet headers', + table: { + type: { + summary: 'boolean', + }, + defaultValue: { summary: false }, + }, + control: { type: 'boolean' }, + }, + hideSelectedCountParenthesis: { + description: 'specifies if the parenthesis should render around the selected count', + table: { + type: { + summary: 'boolean', + }, + defaultValue: { summary: false }, + }, + control: { type: 'boolean' }, + }, + showClearAllText: { + description: 'specifies if the clear all text should render', + table: { + type: { + summary: 'boolean', + }, + defaultValue: { summary: false }, + }, + control: { type: 'boolean' }, + }, + clearAllText: { + description: 'text to show in the clear all link', + table: { + type: { + summary: 'string', + }, + defaultValue: { summary: 'Clear All' }, + }, + control: { type: 'text' }, + }, + clearAllIcon: { + description: 'Icon to show in the clear all link', + table: { + type: { + summary: 'string', + }, + defaultValue: { summary: '' }, + }, + options: [...Object.keys(iconPaths)], + control: { + type: 'select', + }, + }, iconExpand: { defaultValue: 'angle-down', description: 'Icon for when facet is collapsed', diff --git a/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.tsx b/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.tsx index ad6a17d2f..a3f626980 100644 --- a/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.tsx +++ b/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/FacetsHorizontal.tsx @@ -10,15 +10,16 @@ import { Theme, useTheme, CacheProvider, useTreePath } from '../../../providers' import { defined, mergeProps, mergeStyles } from '../../../utilities'; import { ComponentProps, StyleScript } from '../../../types'; import type { SearchController, AutocompleteController } from '@athoscommerce/snap-controller'; -import type { ValueFacet } from '@athoscommerce/snap-store-mobx'; +import type { RangeFacet, ValueFacet } from '@athoscommerce/snap-store-mobx'; import type { IndividualFacetType } from '../Facets/Facets'; import { MobileSidebar, MobileSidebarProps } from '../MobileSidebar'; import { Lang, useA11y, useClickOutside, useLang } from '../../../hooks'; import { Dropdown, DropdownProps } from '../../Atoms/Dropdown'; import { Icon, IconProps, IconType } from '../../Atoms/Icon'; import { useEffect } from 'react'; +import { Button, ButtonProps } from '../../Atoms/Button'; -const defaultStyles: StyleScript = ({}) => { +const defaultStyles: StyleScript = ({ theme }) => { return css({ margin: '10px 0px', @@ -31,6 +32,32 @@ const defaultStyles: StyleScript = ({}) => { margin: '0 10px', }, + '& .ss__facet__header__inner': { + display: 'flex', + }, + + '& .ss__facet__header__selected-count': { + margin: '0px 5px', + }, + + '& .ss__facet__header__clear-all': { + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + marginLeft: '10px', + border: 'none', + padding: '0', + color: theme?.variables?.colors?.primary, + '&:hover': { + cursor: 'pointer', + textDecoration: 'underline', + background: 'none', + }, + '& .ss__icon': { + marginLeft: '5px', + }, + }, + '& .ss__facets-horizontal__header__dropdown': { margin: '0 0 10px 0', '.ss__dropdown__button': { @@ -88,6 +115,7 @@ export const FacetsHorizontal = observer((properties: FacetsHorizontalProps): JS overlay: true, iconCollapse: 'angle-up', iconExpand: 'angle-down', + clearAllText: 'Clear All', facets: properties.controller?.store?.facets, treePath: globalTreePath, }; @@ -101,7 +129,12 @@ export const FacetsHorizontal = observer((properties: FacetsHorizontalProps): JS alwaysShowFiltersButton, hideFiltersButton, onFacetOptionClick, + showSelectedCount, + hideSelectedCountParenthesis, + clearAllIcon, + showClearAllText, iconExpand, + clearAllText, iconCollapse, disableStyles, className, @@ -166,6 +199,15 @@ export const FacetsHorizontal = observer((properties: FacetsHorizontalProps): JS theme: props?.theme, treePath, }, + button: { + // inherited props + ...defined({ + disableStyles, + }), + // component theme overrides + theme: props?.theme, + treePath, + }, icon: { // default props internalClassName: 'ss__dropdown__button__heading__icon', @@ -181,6 +223,8 @@ export const FacetsHorizontal = observer((properties: FacetsHorizontalProps): JS // default props internalClassName: `ss__facets-horizontal__content__facet`, justContent: true, + // this should be turned on if there is ever a filters button rendering. + statefulOverflow: !hideFiltersButton && (isOverflowing || alwaysShowFiltersButton) ? true : undefined, // horizontal: true, // inherited props ...defined({ @@ -227,15 +271,23 @@ export const FacetsHorizontal = observer((properties: FacetsHorizontalProps): JS >
{facetsToShow?.map((facet: IndividualFacetType) => { + const selectedCount = + (facet as ValueFacet)?.values?.filter((value) => value?.filtered).length || + (facet as RangeFacet)?.active?.high !== (facet as RangeFacet)?.range?.high || + (facet as RangeFacet)?.active?.low !== (facet as RangeFacet)?.range?.low; + //initialize lang const defaultLang = { dropdownButton: { attributes: { - 'aria-label': `currently ${selectedFacet?.field === facet.field ? 'open' : 'collapsed'} ${facet.field} facet dropdown ${ + 'aria-label': `currently ${selectedFacet?.field === facet.field ? 'open' : 'collapsed'} ${facet.label} facet dropdown ${ (facet as ValueFacet).values?.length ? (facet as ValueFacet).values?.length + ' options' : '' }`, }, }, + clearAllText: { + value: clearAllText, + }, }; //deep merge with props.lang @@ -264,7 +316,32 @@ export const FacetsHorizontal = observer((properties: FacetsHorizontalProps): JS }} button={
- {facet?.label} +
+ {facet?.label} + + {showSelectedCount && selectedCount && facet.type !== 'range' ? ( + + {hideSelectedCountParenthesis ? selectedCount : `(${selectedCount})`} + + ) : null} + {(mergedLang.clearAllText.value || clearAllIcon) && selectedCount ? ( + + ) : ( + <> + )} +
+ ; facet: Partial; MobileSidebar: Partial; + button: Partial; } export interface FacetsHorizontalProps extends ComponentProps { facets?: IndividualFacetType[]; + showSelectedCount?: boolean; + hideSelectedCountParenthesis?: boolean; + clearAllText?: string; + showClearAllText?: boolean; + clearAllIcon?: IconType | Partial; limit?: number; overlay?: boolean; alwaysShowFiltersButton?: boolean; diff --git a/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/readme.md b/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/readme.md index 222b3d71f..6311d15a4 100644 --- a/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/readme.md +++ b/packages/snap-preact/components/src/components/Organisms/FacetsHorizontal/readme.md @@ -44,6 +44,20 @@ The `limit` prop will limit the maximum number of facets to display before displ ``` +### showSelectedCount +The `showSelectedCount` prop shows the number of selected options within the facet header. + +```jsx + +``` + +### hideSelectedCountParenthesis +The `hideSelectedCountParenthesis` prop specifies if the parenthesis should render around the selected count in the facet header. + +```jsx + +``` + ### alwaysShowFiltersButton The `alwaysShowFiltersButton` prop will always render the button and MobileSidebar, not just when facets are overflowing. @@ -51,6 +65,29 @@ The `alwaysShowFiltersButton` prop will always render the button and MobileSideb ``` +### showClearAllText +The `showClearAllText` prop specifies if the clear all text should render. + +```jsx + +``` + + +### clearAllText +The `clearAllText` prop specifies the text displayed in the facet header when options are selected. Clicking it clears all currently selected options. Defaults to 'Clear All' + +```jsx + +``` + + +### clearAllIcon +The `clearAllIcon` prop specifies the icon displayed in the facet header when options are selected. Clicking it clears all currently selected options. + +```jsx + +``` + ### hideFiltersButton The `hideFiltersButton` specifies wether the filters button should be rendered or not. If true, the button will render when there are more filters to show than the limit prop allows (unless the alwaysShowFiltersButton prop is passed, which will ignore the limit). diff --git a/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.stories.tsx b/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.stories.tsx index 247fdd13a..873bc7e67 100644 --- a/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.stories.tsx +++ b/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.stories.tsx @@ -152,6 +152,20 @@ export default { control: { type: 'none' }, action: 'onClick', }, + type: { + defaultValue: 'inline', + description: 'display type', + table: { + type: { + summary: 'string', + }, + defaultValue: { summary: 'inline' }, + }, + options: ['inline', 'list'], + control: { + type: 'select', + }, + }, onClearAllClick: { description: 'Filter clear click event handler', table: { diff --git a/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.test.tsx b/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.test.tsx index 80138c04c..997fdae30 100644 --- a/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.test.tsx +++ b/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.test.tsx @@ -165,7 +165,7 @@ describe('FilterSummary Component', () => { const rendered = render(); const facetsElement = rendered.container.querySelector('.ss__filter-summary'); - expect(facetsElement?.classList).toHaveLength(1); + expect(facetsElement?.classList).toHaveLength(2); }); }); diff --git a/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.tsx b/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.tsx index 8d7c59d23..7229f0d0a 100644 --- a/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.tsx +++ b/packages/snap-preact/components/src/components/Organisms/FilterSummary/FilterSummary.tsx @@ -14,7 +14,8 @@ import { IconProps, IconType } from '../../Atoms/Icon'; import { Lang, useLang } from '../../../hooks'; import deepmerge from 'deepmerge'; -const defaultStyles: StyleScript = () => { +const defaultStyles: StyleScript = (props) => { + const variables = props.theme?.variables; return css({ '.ss__filter-summary__title': { fontSize: '1.2em', @@ -26,6 +27,45 @@ const defaultStyles: StyleScript = () => { gap: '10px', flexWrap: 'wrap', }, + + '&.ss__filter-summary--list': { + '& .ss__filter-summary__clear-all .ss__filter__value': { + marginLeft: '5px', + }, + + '&, .ss__filter-summary__filters': { + display: 'block', + }, + + '.ss__filter-summary__filters': { + '.ss__filter': { + display: 'block', + margin: `0 5px 5px 5px`, + '.ss__filter__button': { + padding: `0 0 0 0`, + border: 0, + '&, &:hover, &:not(.ss__button--disabled):hover, &.ss__button--disabled': { + backgroundColor: 'transparent', + }, + '.ss__button__content': { + display: 'flex', + alignItems: 'center', + + '.ss__icon': { + padding: '4px', + backgroundColor: '#f8f8f8', + border: `1px solid black`, + width: `8px`, + height: `8px`, + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + marginRight: '0px', + }, + }, + }, + }, + }, + }, }); }; @@ -35,6 +75,7 @@ export const FilterSummary = observer((properties: FilterSummaryProps): JSX.Elem const defaultProps: Partial = { title: 'Current Filters', + type: 'inline', clearAllLabel: 'Clear All', clearAllIcon: 'close-thin', filterIcon: 'close-thin', @@ -49,6 +90,7 @@ export const FilterSummary = observer((properties: FilterSummaryProps): JSX.Elem const { filters, title, + type, filterIcon, clearAllIcon, separator, @@ -102,7 +144,16 @@ export const FilterSummary = observer((properties: FilterSummaryProps): JSX.Elem return filters?.length ? ( -
+
{!hideTitle &&
}
@@ -134,6 +185,7 @@ export const FilterSummary = observer((properties: FilterSummaryProps): JSX.Elem export interface FilterSummaryProps extends ComponentProps { filters?: FilterType[]; + type?: 'inline' | 'list'; title?: string; hideTitle?: boolean; filterIcon?: IconType | Partial; diff --git a/packages/snap-preact/components/src/components/Organisms/FilterSummary/readme.md b/packages/snap-preact/components/src/components/Organisms/FilterSummary/readme.md index e658ac242..05c389840 100644 --- a/packages/snap-preact/components/src/components/Organisms/FilterSummary/readme.md +++ b/packages/snap-preact/components/src/components/Organisms/FilterSummary/readme.md @@ -78,6 +78,13 @@ The `hideClearAll` prop prevents the 'clear all' button from rendering. ``` +### type +The `type` prop determines what layout the filters should be rendered as. Options are `list` or `inline`. `inline` is default. + +```jsx + +``` + ### Events #### onClick diff --git a/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.stories.tsx b/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.stories.tsx index 4bacec30a..6f00411aa 100644 --- a/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.stories.tsx +++ b/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.stories.tsx @@ -9,6 +9,7 @@ import { AutocompleteController } from '@athoscommerce/snap-controller'; import { Snapify } from '../../../utilities/snapify'; import type { AutocompleteTermStore } from '@athoscommerce/snap-store-mobx'; import type { UrlManager } from '@athoscommerce/snap-url-manager'; +import { useState } from 'preact/hooks'; export default { title: 'Organisms/TermsList', @@ -50,6 +51,7 @@ export default { padding: '10px', boxSizing: 'border-box', border: '1px solid #3a23ad', + marginBottom: '20px', }} /> @@ -83,17 +85,27 @@ export default { type: { summary: 'string', }, - defaultValue: { summary: 'History' }, + defaultValue: { summary: 'Recent Searches' }, }, control: { type: 'text' }, }, + verticalOptions: { + description: 'boolean to specify if the terms should be displayed vertically', + table: { + type: { + summary: 'boolean', + }, + defaultValue: { summary: undefined }, + }, + control: { type: 'boolean' }, + }, suggestionTitle: { description: 'suggested terms title', table: { type: { summary: 'string', }, - defaultValue: { summary: 'Suggestions' }, + defaultValue: { summary: 'Search Suggestions' }, }, control: { type: 'text' }, }, @@ -103,7 +115,7 @@ export default { type: { summary: 'string', }, - defaultValue: { summary: 'Trending' }, + defaultValue: { summary: 'Popular Searches' }, }, control: { type: 'text' }, }, @@ -145,50 +157,52 @@ const snapInstance = Snapify.autocomplete({ }); export const Default = (args: TermsListProps, { loaded: { controller } }: { loaded: { controller: AutocompleteController } }) => { + const [termState, setTermState] = useState(false); + const mockTerms: AutocompleteTermStore = [ { - active: false, - preview: () => console.log(''), + active: termState === 'dress', + preview: () => setTermState('dress'), value: 'dress', url: { href: 'www.dress.com', } as UrlManager, }, { - active: false, - preview: () => console.log(''), + active: termState === 'drss', + preview: () => setTermState('drss'), value: 'drss', url: { href: 'www.drss.com', } as UrlManager, }, { - active: false, - preview: () => console.log(''), + active: termState === 'dreees', + preview: () => setTermState('dreees'), value: 'dreees', url: { href: 'www.dreees.com', } as UrlManager, }, { - active: false, - preview: () => console.log(''), + active: termState === 'dres', + preview: () => setTermState('dres'), value: 'dres', url: { href: 'www.dres.com', } as UrlManager, }, { - active: false, - preview: () => console.log(''), + active: termState === 'dss', + preview: () => setTermState('dss'), value: 'dss', url: { href: 'www.dss.com', } as UrlManager, }, { - active: false, - preview: () => console.log(''), + active: termState === 'ress', + preview: () => setTermState('ress'), value: 'ress', url: { href: 'www.ress.com', diff --git a/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.tsx b/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.tsx index 9fcf30d1c..8becf7384 100644 --- a/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.tsx +++ b/packages/snap-preact/components/src/components/Organisms/TermsList/TermsList.tsx @@ -1,15 +1,13 @@ import { Fragment, h } from 'preact'; - import { observer } from 'mobx-react-lite'; import { jsx, css } from '@emotion/react'; import classnames from 'classnames'; import type { AutocompleteController } from '@athoscommerce/snap-controller'; import { ComponentProps, StyleScript } from '../../../types'; -import { Theme, useTheme, CacheProvider } from '../../../providers'; +import { Theme, useTheme, CacheProvider, useTreePath } from '../../../providers'; import { defined, mergeProps, mergeStyles } from '../../../utilities'; import { Terms, TermsProps } from '../../Molecules/Terms/Terms'; -import { useCleanUpEmptyDivs } from '../../../hooks/useCleanUpEmptyDivs'; const defaultStyles: StyleScript = ({}) => { return css({ @@ -38,17 +36,21 @@ const defaultStyles: StyleScript = ({}) => { export const TermsList = observer((properties: TermsListProps): JSX.Element => { const globalTheme: Theme = useTheme(); + const globalTreePath = useTreePath(); + const defaultProps: Partial = { layout: [['Suggestions'], ['Trending'], ['History']], - historyTitle: 'History', - trendingTitle: 'Trending', - suggestionTitle: 'Suggestions', + historyTitle: 'Recent Searches', + trendingTitle: 'Popular Searches', + suggestionTitle: 'Search Suggestions', + treePath: globalTreePath, }; const props = mergeProps('termsList', globalTheme, defaultProps, properties); const { layout, historyTitle, + verticalOptions, trendingTitle, suggestionTitle, retainHistory, @@ -62,6 +64,7 @@ export const TermsList = observer((properties: TermsListProps): JSX.Element => { const subProps: TermsListSubProps = { terms: { + vertical: verticalOptions ? true : false, // default props // inherited props ...defined({ @@ -98,8 +101,6 @@ export const TermsList = observer((properties: TermsListProps): JSX.Element => { if (trending?.length) showTrending = true; } - useCleanUpEmptyDivs(['.ss__terms-list', '.ss__terms-list__row'], '.ss__terms-list__separator'); - const findModule = (module: TermsListModuleNames[] | TermsListModuleNames) => { if (typeof module !== 'string') { return
{module?.map((subModule) => findModule(subModule))}
; @@ -178,4 +179,5 @@ export interface TermsListProps extends ComponentProps { trendingTitle?: string; retainHistory?: boolean; retainTrending?: boolean; + verticalOptions?: boolean; } diff --git a/packages/snap-preact/components/src/components/Organisms/TermsList/readme.md b/packages/snap-preact/components/src/components/Organisms/TermsList/readme.md index d8ee7aea7..1147c004e 100644 --- a/packages/snap-preact/components/src/components/Organisms/TermsList/readme.md +++ b/packages/snap-preact/components/src/components/Organisms/TermsList/readme.md @@ -22,6 +22,22 @@ The `_` module is used a seperator module to center|left|right justify the other ``` +### horizontal + +The `horizontal` prop specifies if the terms should be rendered horizontally. + +```jsx + +``` + +### verticalOptions + +The `verticalOptions` prop specifies if the terms options should be rendered vertically. + +```jsx + +``` + ### historyTitle The `historyTitle` prop specifies the title to render above the history terms. diff --git a/packages/snap-preact/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.tsx b/packages/snap-preact/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.tsx index df3ff3e12..453a45a5b 100644 --- a/packages/snap-preact/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.tsx +++ b/packages/snap-preact/components/src/components/Templates/AutocompleteFixed/AutocompleteFixed.tsx @@ -129,7 +129,8 @@ export const AutocompleteFixed = observer((properties: AutocompleteFixedProps): }, searchInput: { // default props - internalClassName: 'autocomplete-fixed__search-input', + // autocomplete__search-input is required for useAcRenderedInput hook. + internalClassName: 'autocomplete-fixed__search-input autocomplete__search-input', placeholderText: inputPlaceholderText || undefined, submitSearchButton: { onClick: () => { diff --git a/packages/snap-preact/components/src/components/Templates/AutocompleteModal/AutocompleteModal.tsx b/packages/snap-preact/components/src/components/Templates/AutocompleteModal/AutocompleteModal.tsx index 3b135c8e0..e8d17de34 100644 --- a/packages/snap-preact/components/src/components/Templates/AutocompleteModal/AutocompleteModal.tsx +++ b/packages/snap-preact/components/src/components/Templates/AutocompleteModal/AutocompleteModal.tsx @@ -141,7 +141,8 @@ export const AutocompleteModal = observer((properties: AutocompleteModalProps): }, searchInput: { // default props - internalClassName: 'autocomplete-modal__search-input', + // autocomplete__search-input is required for useAcRenderedInput hook. + internalClassName: 'autocomplete-modal__search-input autocomplete__search-input', submitSearchButton: { onClick: () => { () => reset(); diff --git a/packages/snap-preact/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.tsx b/packages/snap-preact/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.tsx index 7877a1ef4..90c5fdf6b 100644 --- a/packages/snap-preact/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.tsx +++ b/packages/snap-preact/components/src/components/Templates/AutocompleteSlideout/AutocompleteSlideout.tsx @@ -103,7 +103,8 @@ export const AutocompleteSlideout = observer((properties: AutocompleteSlideoutPr }, searchInput: { // default props - internalClassName: 'autocomplete-slideout__search-input', + // autocomplete__search-input is required for useAcRenderedInput hook. + internalClassName: 'autocomplete-slideout__search-input autocomplete__search-input', inputName: inputName, submitSearchButton: { onClick: () => { @@ -166,7 +167,7 @@ export const AutocompleteSlideout = observer((properties: AutocompleteSlideoutPr className={classNames('ss__autocomplete-slideout', 'ss__autocomplete-slideout__slideout', className, internalClassName)} active={active} > -
useA11y(e, 0, true, reset)}> +
useA11y(e, 0, true, reset)}> {renderInput ? ( ) : ( diff --git a/packages/snap-preact/components/src/components/Templates/Recommendation/Recommendation.tsx b/packages/snap-preact/components/src/components/Templates/Recommendation/Recommendation.tsx index b17185633..5153d1381 100644 --- a/packages/snap-preact/components/src/components/Templates/Recommendation/Recommendation.tsx +++ b/packages/snap-preact/components/src/components/Templates/Recommendation/Recommendation.tsx @@ -14,7 +14,7 @@ import { Carousel, CarouselProps, defaultCarouselBreakpoints, defaultVerticalCar import { Result, ResultProps } from '../../Molecules/Result'; import { defined, mergeProps, mergeStyles } from '../../../utilities'; import { useIntersection } from '../../../hooks'; -import { Theme, useTheme, CacheProvider } from '../../../providers'; +import { Theme, useTheme, CacheProvider, useTreePath } from '../../../providers'; import { ComponentProps, BreakpointsProps, ResultComponent, StyleScript } from '../../../types'; import { useDisplaySettings } from '../../../hooks/useDisplaySettings'; import { RecommendationProfileTracker } from '../../Trackers/Recommendation/ProfileTracker'; @@ -32,6 +32,7 @@ const defaultStyles: StyleScript = ({ vertical }) => { export const Recommendation = observer((properties: RecommendationProps): JSX.Element => { const globalTheme: Theme = useTheme(); + const globalTreePath = useTreePath(); const defaultProps: Partial = { breakpoints: properties.vertical @@ -41,6 +42,7 @@ export const Recommendation = observer((properties: RecommendationProps): JSX.El loop: true, title: properties.controller?.store?.profile?.display?.templateParameters?.title, description: properties.controller?.store?.profile?.display?.templateParameters?.description, + treePath: globalTreePath, }; //mergeprops only uses names that are passed via properties, so this cannot be put in the defaultProps diff --git a/packages/snap-preact/components/src/components/Templates/RecommendationBundle/RecommendationBundle.tsx b/packages/snap-preact/components/src/components/Templates/RecommendationBundle/RecommendationBundle.tsx index 9a79b7a88..3f7c32ba0 100644 --- a/packages/snap-preact/components/src/components/Templates/RecommendationBundle/RecommendationBundle.tsx +++ b/packages/snap-preact/components/src/components/Templates/RecommendationBundle/RecommendationBundle.tsx @@ -7,7 +7,7 @@ import deepmerge from 'deepmerge'; import { Carousel, CarouselProps as CarouselProps } from '../../Molecules/Carousel'; import { Result, ResultProps } from '../../Molecules/Result'; import { cloneWithProps, defined, mergeProps, mergeStyles } from '../../../utilities'; -import { Theme, useTheme, CacheProvider } from '../../../providers'; +import { Theme, useTheme, CacheProvider, useTreePath } from '../../../providers'; import { ComponentProps, BreakpointsProps, ResultComponent, StyleScript, BreakpointsEntry } from '../../../types'; import { useDisplaySettings } from '../../../hooks/useDisplaySettings'; import { RecommendationProfileTracker } from '../../Trackers/Recommendation/ProfileTracker'; @@ -145,6 +145,8 @@ const defaultStyles: StyleScript { const globalTheme: Theme = useTheme(); + const globalTreePath = useTreePath(); + const defaultCarouselBreakpoints = { 0: { slidesPerView: 2, @@ -179,6 +181,7 @@ export const RecommendationBundle = observer((properties: RecommendationBundlePr onAddToCart: (e, items) => controller?.addToCart && controller.addToCart(items), title: properties.controller?.store?.profile?.display?.templateParameters?.title, description: properties.controller?.store?.profile?.display?.templateParameters?.description, + treePath: globalTreePath, }; //mergeprops only uses names that are passed via properties, so this cannot be put in the defaultProps diff --git a/packages/snap-preact/components/src/components/Templates/RecommendationBundleList/RecommendationBundleList.tsx b/packages/snap-preact/components/src/components/Templates/RecommendationBundleList/RecommendationBundleList.tsx index f7d326140..7e3b3414b 100644 --- a/packages/snap-preact/components/src/components/Templates/RecommendationBundleList/RecommendationBundleList.tsx +++ b/packages/snap-preact/components/src/components/Templates/RecommendationBundleList/RecommendationBundleList.tsx @@ -44,7 +44,6 @@ const defaultStyles: StyleScript = () => { '.ss__button': { cursor: 'pointer', - border: '1px solid black', }, '.ss__recommendation-bundle-list__wrapper__cta__inner__images': { display: 'flex', @@ -202,7 +201,7 @@ export const CTASlot = observer((props: BundledCTAProps): JSX.Element => { const mergedLang = useLang(lang as any, {}); return ( -
+ <>
{cartStore.items.map((item: any) => { @@ -242,13 +241,13 @@ export const CTASlot = observer((props: BundledCTAProps): JSX.Element => {
-
+
-
+ ); }); diff --git a/packages/snap-preact/components/src/components/Templates/RecommendationEmail/RecommendationEmail.tsx b/packages/snap-preact/components/src/components/Templates/RecommendationEmail/RecommendationEmail.tsx index 961a94ce4..8904e89b9 100644 --- a/packages/snap-preact/components/src/components/Templates/RecommendationEmail/RecommendationEmail.tsx +++ b/packages/snap-preact/components/src/components/Templates/RecommendationEmail/RecommendationEmail.tsx @@ -7,7 +7,7 @@ import type { Product } from '@athoscommerce/snap-store-mobx'; import classnames from 'classnames'; import { Result, ResultProps } from '../../Molecules/Result'; import { defined, mergeProps, mergeStyles } from '../../../utilities'; -import { Theme, ThemeComponent, useTheme } from '../../../providers'; +import { Theme, ThemeComponent, useTheme, useTreePath } from '../../../providers'; import { ComponentProps, ResultComponent, StyleScript } from '../../../types'; export const recommendationEmailThemeComponentProps: ThemeComponent<'recommendationEmailThemeComponentProps', RecommendationEmailProps> = { @@ -23,9 +23,12 @@ const defaultStyles: StyleScript = () => { export const RecommendationEmail = observer((properties: RecommendationEmailProps): JSX.Element => { const globalTheme: Theme = useTheme(); + const globalTreePath = useTreePath(); + const defaultProps: Partial = { resultWidth: '240px', name: properties.controller?.store?.profile?.tag?.toLowerCase(), + treePath: globalTreePath, }; const props = mergeProps('recommendationEmail', globalTheme, defaultProps, properties); diff --git a/packages/snap-preact/components/src/components/Templates/RecommendationGrid/RecommendationGrid.tsx b/packages/snap-preact/components/src/components/Templates/RecommendationGrid/RecommendationGrid.tsx index 8d4c07559..dbcac45ed 100644 --- a/packages/snap-preact/components/src/components/Templates/RecommendationGrid/RecommendationGrid.tsx +++ b/packages/snap-preact/components/src/components/Templates/RecommendationGrid/RecommendationGrid.tsx @@ -8,7 +8,7 @@ import type { Product } from '@athoscommerce/snap-store-mobx'; import { Result, ResultProps } from '../../Molecules/Result'; import { ComponentProps, BreakpointsProps, ResultComponent, StyleScript } from '../../../types'; import { defined, mergeProps, mergeStyles } from '../../../utilities'; -import { Theme, useTheme, CacheProvider } from '../../../providers'; +import { Theme, useTheme, CacheProvider, useTreePath } from '../../../providers'; import { useDisplaySettings } from '../../../hooks/useDisplaySettings'; import { RecommendationProfileTracker } from '../../Trackers/Recommendation/ProfileTracker'; import { ResultTracker } from '../../Trackers/ResultTracker'; @@ -37,11 +37,13 @@ const defaultStyles: StyleScript = ({ gapSize, columns export const RecommendationGrid = observer((properties: RecommendationGridProps): JSX.Element => { const globalTheme: Theme = useTheme(); + const globalTreePath = useTreePath(); const defaultProps: Partial = { results: properties.controller?.store?.results, gapSize: '20px', title: properties.controller?.store?.profile?.display?.templateParameters?.title, + treePath: globalTreePath, }; //mergeprops only uses names that are passed via properties, so this cannot be put in the defaultProps @@ -131,7 +133,13 @@ export const RecommendationGrid = observer((properties: RecommendationGridProps) } else { return ( - + ); } diff --git a/packages/snap-preact/components/src/components/Templates/Search/Search.tsx b/packages/snap-preact/components/src/components/Templates/Search/Search.tsx index 9d8f78b10..45ce9dbe0 100644 --- a/packages/snap-preact/components/src/components/Templates/Search/Search.tsx +++ b/packages/snap-preact/components/src/components/Templates/Search/Search.tsx @@ -7,7 +7,7 @@ import type { SearchController } from '@athoscommerce/snap-controller'; import { Results, ResultsProps } from '../../Organisms/Results'; import { defined, mergeProps, mergeStyles } from '../../../utilities'; import { ComponentProps, ListOption, ResultComponent, StyleScript } from '../../../types'; -import { Theme, useTheme, CacheProvider } from '../../../providers'; +import { Theme, useTheme, CacheProvider, useTreePath } from '../../../providers'; import { Sidebar, SidebarProps } from '../../Organisms/Sidebar'; import { Toolbar, ToolbarProps } from '../../Organisms/Toolbar'; import { NoResults, NoResultsProps } from '../../Organisms/NoResults'; @@ -56,11 +56,13 @@ const defaultStyles: StyleScript = (props) => { export const Search = observer((properties: SearchProps): JSX.Element => { const globalTheme: Theme = useTheme(); + const globalTreePath = useTreePath(); const defaultProps: Partial = { toggleSidebarButtonText: 'Filters', hideToggleSidebarButton: true, mobileDisplayAt: globalTheme?.variables?.breakpoints?.tablet ? `${globalTheme.variables?.breakpoints?.tablet}px` : '991px', + treePath: globalTreePath, }; const props = mergeProps(properties.alias || 'search', globalTheme, defaultProps, properties); @@ -80,6 +82,7 @@ export const Search = observer((properties: SearchProps): JSX.Element => { mobileDisplayAt, toggleSidebarStartClosed, treePath, + alias, } = props; let classNamePrefix = 'ss__search'; @@ -96,7 +99,7 @@ export const Search = observer((properties: SearchProps): JSX.Element => { const isMobile = useMediaQuery(`(max-width: ${mobileDisplayAt})`); - const [sidebarOpenState, setSidebarOpenState] = useState(Boolean(!toggleSidebarStartClosed)); + const [sidebarOpenState, setSidebarOpenState] = useState(Boolean(alias !== 'searchHorizontal' && !toggleSidebarStartClosed)); //initialize lang const defaultLang: Partial = { @@ -111,7 +114,11 @@ export const Search = observer((properties: SearchProps): JSX.Element => { const ToggleSidebar = (): JSX.Element => { return ( -
+
); @@ -154,7 +161,7 @@ export const Search = observer((properties: SearchProps): JSX.Element => { name: 'middle', internalClassName: `${classNamePrefix}__content__toolbar--middle-toolbar`, layout: isMobile - ? [['mobileSidebar', '_', 'paginationInfo'], ['filterSummary'], ['banner.banner']] + ? [['mobileSidebar', '_', 'paginationInfo'], ['banner.banner']] : [['sortBy', 'perPage', '_', 'paginationInfo'], ['banner.banner']], toggleSideBarButton: { ...toggleSidebarButtonProps }, // inherited props @@ -168,7 +175,7 @@ export const Search = observer((properties: SearchProps): JSX.Element => { // default props name: 'bottom', internalClassName: `${classNamePrefix}__content__toolbar--bottom-toolbar`, - layout: [['banner.footer'], ['_', 'pagination']], + layout: [['banner.footer'], ['_', 'pagination', '_']], toggleSideBarButton: { ...toggleSidebarButtonProps }, // inherited props ...defined({ diff --git a/packages/snap-preact/components/src/components/Templates/SearchHorizontal/SearchHorizontal.tsx b/packages/snap-preact/components/src/components/Templates/SearchHorizontal/SearchHorizontal.tsx index f7ad5fe85..37191bfc0 100644 --- a/packages/snap-preact/components/src/components/Templates/SearchHorizontal/SearchHorizontal.tsx +++ b/packages/snap-preact/components/src/components/Templates/SearchHorizontal/SearchHorizontal.tsx @@ -8,7 +8,7 @@ import { Search, SearchProps } from '../Search/Search'; export const SearchHorizontal = observer((properties: SearchHorizontalProps): JSX.Element => { return ( - + ); }); diff --git a/packages/snap-preact/components/src/hooks/useAcRenderedInput.tsx b/packages/snap-preact/components/src/hooks/useAcRenderedInput.tsx index 971547d7a..18060459d 100644 --- a/packages/snap-preact/components/src/hooks/useAcRenderedInput.tsx +++ b/packages/snap-preact/components/src/hooks/useAcRenderedInput.tsx @@ -28,8 +28,7 @@ export function useAcRenderedInput({ setTimeout(async () => { if (!renderedInputInitialized) { setInput(renderedInputRef!.current); - - controller.config.selector = '.ss__search-input__input'; + controller.config.selector = '.autocomplete__search-input input'; await controller.bind(); renderedInputRef?.current?.focus(); } diff --git a/packages/snap-preact/components/src/hooks/useLayoutOptions.tsx b/packages/snap-preact/components/src/hooks/useLayoutOptions.tsx index bdf77da83..5d8cab186 100644 --- a/packages/snap-preact/components/src/hooks/useLayoutOptions.tsx +++ b/packages/snap-preact/components/src/hooks/useLayoutOptions.tsx @@ -37,7 +37,6 @@ export const useLayoutOptions = (props: any, globalTheme: Theme) => { }, }; let shouldUseOverrides = false; - if (globalTheme.components && props.treePath) { // pull out the template (top level parent) component from the treePath to use in filtering out globalTheme overrides const templateComponent = props.treePath.split(' ')[0]; diff --git a/packages/snap-preact/components/src/providers/themeComponents.ts b/packages/snap-preact/components/src/providers/themeComponents.ts index 25e087f7c..33d16d64e 100644 --- a/packages/snap-preact/components/src/providers/themeComponents.ts +++ b/packages/snap-preact/components/src/providers/themeComponents.ts @@ -112,7 +112,7 @@ type ThemeComponentNamedSelectorsStartingWithTemplate< | `${TemplateComponentType} ${SubComponentType}.${ComponentNames}`; export type ThemeComponentRestrictedProps = Partial>; -type ThemeComponentOmittedProps = 'theme' | 'inherits' | 'disableStyles' | 'styleScript'; +type ThemeComponentOmittedProps = 'theme' | 'inherits' | 'disableStyles' | 'styleScript' | 'internalClassName' | 'className'; type ThemeComponentOverridesRestrictedProps = Partial>; type ThemeComponentOverrideOmittedProps = @@ -127,6 +127,7 @@ type ThemeComponentOverrideOmittedProps = | 'filter' | 'lang' | 'internalClassName' + | 'className' | 'ref' | 'snap' | 'name' diff --git a/packages/snap-preact/components/src/themes/base/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/base/components/organisms/autocomplete.ts new file mode 100644 index 000000000..abeed134d --- /dev/null +++ b/packages/snap-preact/components/src/themes/base/components/organisms/autocomplete.ts @@ -0,0 +1,22 @@ +import { css } from '@emotion/react'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; + +// CSS in JS style script for the Search component +const autocompleteStyleScript = ({}: AutocompleteProps) => { + return css({}); +}; + +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + ...(autocompleteThemeComponentProps.default?.['autocomplete'] || {}), + themeStyleScript: autocompleteStyleScript, + }, + }, + mobile: autocompleteThemeComponentProps.mobile, + desktop: autocompleteThemeComponentProps.desktop, + tablet: autocompleteThemeComponentProps.tablet, +}; diff --git a/packages/snap-preact/components/src/themes/base/components/organisms/index.ts b/packages/snap-preact/components/src/themes/base/components/organisms/index.ts index 4b04b40aa..d4300a69c 100644 --- a/packages/snap-preact/components/src/themes/base/components/organisms/index.ts +++ b/packages/snap-preact/components/src/themes/base/components/organisms/index.ts @@ -1,10 +1,19 @@ import { ThemeResponsiveComplete } from '../../../../providers'; +import { autocomplete } from './autocomplete'; // ORGANISMS Imports export const organisms: ThemeResponsiveComplete = { - default: {}, - mobile: {}, - tablet: {}, - desktop: {}, + default: { + ...autocomplete.default, + }, + mobile: { + ...autocomplete.mobile, + }, + tablet: { + ...autocomplete.tablet, + }, + desktop: { + ...autocomplete.desktop, + }, }; diff --git a/packages/snap-preact/components/src/themes/bocachica/components/atoms/button.ts b/packages/snap-preact/components/src/themes/bocachica/components/atoms/button.ts index 82405462a..333c08d82 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/atoms/button.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/atoms/button.ts @@ -6,7 +6,7 @@ import Color from 'color'; // CSS in JS style script for the Button component const buttonStyleScript = ({ backgroundColor, theme }: ButtonProps) => { const variables = theme?.variables; - const hoverBackgroundColorObj = new Color(backgroundColor || variables?.colors.primary); + const hoverBackgroundColorObj = new Color(backgroundColor || variables?.colors.primary || undefined); const hoverColorObj = hoverBackgroundColorObj.isDark() ? Color('#fff') : Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/bocachica/components/molecules/checkbox.ts b/packages/snap-preact/components/src/themes/bocachica/components/molecules/checkbox.ts index c1c39a894..c2761e1b0 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/molecules/checkbox.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/molecules/checkbox.ts @@ -6,7 +6,7 @@ import Color from 'color'; // CSS in JS style script for the Checkbox component const checkboxStyleScript = ({ color, theme }: CheckboxProps) => { const variables = theme?.variables; - const backgroundColorObj = new Color(color || variables?.colors.primary); + const backgroundColorObj = new Color(color || variables?.colors.primary || undefined); const backgroundTextColorObj = backgroundColorObj.isDark() ? new Color('#fff') : new Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/bocachica/components/molecules/facetGridOptions.ts b/packages/snap-preact/components/src/themes/bocachica/components/molecules/facetGridOptions.ts index e30020895..a25b2eb7e 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/molecules/facetGridOptions.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/molecules/facetGridOptions.ts @@ -6,7 +6,7 @@ import Color from 'color'; // CSS in JS style script for the FacetGridOptions component const facetGridOptionsStyleScript = ({ theme }: FacetGridOptionsProps) => { const variables = theme?.variables; - const backgroundColorObj = new Color(variables?.colors.primary); + const backgroundColorObj = new Color(variables?.colors.primary || undefined); const colorObj = backgroundColorObj.isDark() ? new Color('#fff') : new Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/bocachica/components/molecules/filter.ts b/packages/snap-preact/components/src/themes/bocachica/components/molecules/filter.ts index ecc32acdf..6902df7d1 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/molecules/filter.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/molecules/filter.ts @@ -7,7 +7,7 @@ import Color from 'color'; const filterStyleScript = ({ theme }: FilterProps) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const variables = theme?.variables; - const backgroundColor = new Color(variables?.colors.primary); + const backgroundColor = new Color(variables?.colors.primary || undefined); const backgroundTextColor = backgroundColor.isDark() ? '#fff' : '#000'; return css({ diff --git a/packages/snap-preact/components/src/themes/bocachica/components/molecules/loadMore.ts b/packages/snap-preact/components/src/themes/bocachica/components/molecules/loadMore.ts index b6db2ec0e..7269ad084 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/molecules/loadMore.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/molecules/loadMore.ts @@ -7,8 +7,8 @@ import Color from 'color'; const loadMoreStyleScript = ({ color, backgroundColor, theme }: LoadMoreProps) => { const variables = theme?.variables; - const barColour = new Color(color || variables?.colors.accent); - const backgroundColour = backgroundColor ? new Color(backgroundColor) : barColour.lightness(90); + const barColour = new Color(color || variables?.colors.accent || undefined); + const backgroundColour = backgroundColor ? new Color(backgroundColor || undefined) : barColour.lightness(90); return css({ '.ss__button': { diff --git a/packages/snap-preact/components/src/themes/bocachica/components/molecules/select.ts b/packages/snap-preact/components/src/themes/bocachica/components/molecules/select.ts index ffde53708..775a6b73b 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/molecules/select.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/molecules/select.ts @@ -6,7 +6,7 @@ import Color from 'color'; // CSS in JS style script for the Select component const selectStyleScript = ({ backgroundColor, theme }: SelectProps) => { const variables = theme?.variables; - const transparentSecondary = new Color(theme?.variables?.colors?.secondary).opaquer(0.2); + const transparentSecondary = new Color(theme?.variables?.colors?.secondary || undefined).opaquer(0.2); return css({ '.ss__dropdown': { '.ss__select__dropdown__button': { diff --git a/packages/snap-preact/components/src/themes/bocachica/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/bocachica/components/organisms/autocomplete.ts new file mode 100644 index 000000000..abeed134d --- /dev/null +++ b/packages/snap-preact/components/src/themes/bocachica/components/organisms/autocomplete.ts @@ -0,0 +1,22 @@ +import { css } from '@emotion/react'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; + +// CSS in JS style script for the Search component +const autocompleteStyleScript = ({}: AutocompleteProps) => { + return css({}); +}; + +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + ...(autocompleteThemeComponentProps.default?.['autocomplete'] || {}), + themeStyleScript: autocompleteStyleScript, + }, + }, + mobile: autocompleteThemeComponentProps.mobile, + desktop: autocompleteThemeComponentProps.desktop, + tablet: autocompleteThemeComponentProps.tablet, +}; diff --git a/packages/snap-preact/components/src/themes/bocachica/components/organisms/index.ts b/packages/snap-preact/components/src/themes/bocachica/components/organisms/index.ts index 257776ad6..103caf991 100644 --- a/packages/snap-preact/components/src/themes/bocachica/components/organisms/index.ts +++ b/packages/snap-preact/components/src/themes/bocachica/components/organisms/index.ts @@ -9,9 +9,10 @@ import { noResults } from './noResults'; import { sidebar } from './sidebar'; import { termsList } from './termsList'; import { toolbar } from './toolbar'; - +import { autocomplete } from './autocomplete'; export const organisms: ThemeResponsiveComplete = { default: { + ...autocomplete.default, ...facet.default, ...facetsHorizontal.default, ...filterSummary.default, @@ -22,6 +23,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.default, }, mobile: { + ...autocomplete.mobile, ...facet.mobile, ...facetsHorizontal.mobile, ...filterSummary.mobile, @@ -32,6 +34,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.mobile, }, tablet: { + ...autocomplete.tablet, ...facet.tablet, ...facetsHorizontal.tablet, ...filterSummary.tablet, @@ -42,6 +45,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.tablet, }, desktop: { + ...autocomplete.desktop, ...facet.desktop, ...facetsHorizontal.desktop, ...filterSummary.desktop, diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/breadcrumbs.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/breadcrumbs.ts new file mode 100644 index 000000000..c1436cbbf --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/breadcrumbs.ts @@ -0,0 +1,46 @@ +import { css } from '@emotion/react'; +import type { BreadcrumbsProps } from '../../../../components/Atoms/Breadcrumbs'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Breadcrumbs component +const breadcrumbsStyleScript = (props: BreadcrumbsProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__breadcrumbs__crumbs': { + margin: `0 -${custom.spacing.x1}px`, + '&, li': { + listStyle: 'none', + }, + '&, a': { + color: variables?.colors?.text, + }, + li: { + display: 'block', + padding: `0 ${custom.spacing.x1}px`, + '&:last-of-type': { + color: variables?.colors?.primary, + fontWeight: custom?.fonts?.weight01, + }, + }, + '.ss__breadcrumbs__crumbs__separator': { + '.ss__icon': { + width: `${custom.sizes.icon10}px`, + height: `${custom.sizes.icon10}px`, + }, + }, + }, + }); +}; + +// Breadcrumbs component props +export const breadcrumbs: ThemeComponent<'breadcrumbs', BreadcrumbsProps> = { + default: { + breadcrumbs: { + themeStyleScript: breadcrumbsStyleScript, + separator: false, + separatorIcon: custom.icons.arrowRight, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/button.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/button.ts new file mode 100644 index 000000000..a0d2116d6 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/button.ts @@ -0,0 +1,88 @@ +import { css } from '@emotion/react'; +import type { ButtonProps } from '../../../../components/Atoms/Button'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the Button component +const buttonStyleScript = (props: ButtonProps) => { + const variables = props?.theme?.variables; + const buttonDisabledSelectors = '&.ss__button--disabled'; + const buttonSelector = `&, &:hover, &:not(.ss__button--disabled):hover, ${buttonDisabledSelectors}`; + const buttonColor = new Color(props?.backgroundColor || variables?.colors?.primary || undefined); + const bottomBorderColor = new Color(props?.backgroundColor || variables?.colors?.secondary || undefined); + const fontColor = buttonColor.isDark() || buttonColor.hex().toLowerCase() == '#d15120' ? Color(custom.colors.white) : Color(custom.colors.black); + + // shared button styles + const disabledStyles = css({ + [buttonDisabledSelectors]: { + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }, + }); + + // default styles + const defaultStyles = css([ + { + boxSizing: 'border-box', + cursor: 'pointer', + display: 'inline-flex', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + position: 'relative', + padding: `0 ${custom.spacing.x4}px`, + color: fontColor.hex(), + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight01, + textAlign: 'center', + textTransform: custom.fonts.transform, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + '&:after': { + content: '""', + display: 'block', + position: 'absolute', + top: '-1px', + bottom: '-1px', + left: '-1px', + right: '-1px', + margin: 'auto', + borderBottom: `3px solid ${bottomBorderColor}`, + borderRadius: `${custom.sizes.radius}px`, + }, + [buttonSelector]: { + border: `1px solid ${buttonColor.hex()}`, + borderRadius: `${custom.sizes.radius}px`, + backgroundColor: buttonColor.hex(), + }, + '.ss__icon': { + width: `${custom.sizes.icon12}px`, + height: `${custom.sizes.icon12}px`, + flex: `0 0 ${custom.sizes.icon12}px`, + }, + '.ss__icon--filters': { + circle: { + fill: buttonColor.hex(), + }, + }, + }, + disabledStyles, + ]); + + return defaultStyles; +}; + +// Button component props +export const button: ThemeComponent<'button', ButtonProps> = { + default: { + button: { + themeStyleScript: buttonStyleScript, + native: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/dropdown.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/dropdown.ts new file mode 100644 index 000000000..93eed8788 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/dropdown.ts @@ -0,0 +1,40 @@ +import { css } from '@emotion/react'; +import type { DropdownProps } from '../../../../components/Atoms/Dropdown'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Dropdown component +const dropdownStyleScript = ({ theme }: DropdownProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = theme?.variables; + + return css({ + width: 'auto', + '&:not(.ss__facet__dropdown)': { + '&.ss__dropdown--open': { + '.ss__dropdown__content': { + zIndex: 200, + }, + }, + }, + '&.ss__dropdown--open': { + '.ss__dropdown__content': { + zIndex: 5, + }, + }, + '.ss__dropdown__content': { + minWidth: '1px', + left: 0, + right: 0, + zIndex: -1, + }, + }); +}; + +// Dropdown component props +export const dropdown: ThemeComponent<'dropdown', DropdownProps> = { + default: { + dropdown: { + themeStyleScript: dropdownStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/icon.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/icon.ts new file mode 100644 index 000000000..851bb434a --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/icon.ts @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; +import type { IconProps } from '../../../../components/Atoms/Icon'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Icon component +const iconStyleScript = (props: IconProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + fill: 'currentColor', + stroke: 'currentColor', + }); +}; + +// Icon component props +export const icon: ThemeComponent<'icon', IconProps> = { + default: { + icon: { + themeStyleScript: iconStyleScript, + size: `${custom.sizes.icon16}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/image.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/image.ts new file mode 100644 index 000000000..defdd577c --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/image.ts @@ -0,0 +1,46 @@ +import { css } from '@emotion/react'; +import type { ImageProps } from '../../../../components/Atoms/Image'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Image component +const imageStyleScript = (props: ImageProps & { visibility: React.CSSProperties['visibility'] }) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '&.ss__result__image': { + position: 'relative', + lineHeight: 0, + height: 0, + padding: '0 0 100% 0', + overflow: 'hidden', + '&, img': { + display: 'block', + }, + img: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + width: '100%', + height: '100%', + maxWidth: '100%', + maxHeight: '100%', + border: 0, + objectFit: 'contain', + objectPosition: 'center center', + }, + }, + }); +}; + +// Image component props +export const image: ThemeComponent<'image', ImageProps> = { + default: { + image: { + themeStyleScript: imageStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/index.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/index.ts new file mode 100644 index 000000000..0c9983f79 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/index.ts @@ -0,0 +1,69 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// ATOMS Imports +import { breadcrumbs } from './breadcrumbs'; +import { button } from './button'; +import { dropdown } from './dropdown'; +import { icon } from './icon'; +import { image } from './image'; +import { loadingBar } from './loadingBar'; +import { overlay } from './overlay'; +import { paginationInfo } from './paginationInfo'; +import { price } from './price'; +import { searchHeader } from './searchHeader'; +import { skeleton } from './skeleton'; + +export const atoms: ThemeResponsiveComplete = { + default: { + ...breadcrumbs.default, + ...button.default, + ...dropdown.default, + ...icon.default, + ...image.default, + ...loadingBar.default, + ...overlay.default, + ...price.default, + ...searchHeader.default, + ...skeleton.default, + ...paginationInfo.default, + }, + mobile: { + ...breadcrumbs.mobile, + ...button.mobile, + ...dropdown.mobile, + ...icon.mobile, + ...image.mobile, + ...loadingBar.mobile, + ...overlay.mobile, + ...price.mobile, + ...searchHeader.mobile, + ...skeleton.mobile, + ...paginationInfo.mobile, + }, + tablet: { + ...breadcrumbs.tablet, + ...button.tablet, + ...dropdown.tablet, + ...icon.tablet, + ...image.tablet, + ...loadingBar.tablet, + ...overlay.tablet, + ...price.tablet, + ...searchHeader.tablet, + ...skeleton.tablet, + ...paginationInfo.tablet, + }, + desktop: { + ...breadcrumbs.desktop, + ...button.desktop, + ...dropdown.desktop, + ...icon.desktop, + ...image.desktop, + ...loadingBar.desktop, + ...overlay.desktop, + ...price.desktop, + ...searchHeader.desktop, + ...skeleton.desktop, + ...paginationInfo.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/loadingBar.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/loadingBar.ts new file mode 100644 index 000000000..750f1917b --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/loadingBar.ts @@ -0,0 +1,24 @@ +import { css } from '@emotion/react'; +import type { LoadingBarProps } from '../../../../components/Atoms/Loading'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the LoadingBar component +const loadingBarStyleScript = (props: LoadingBarProps) => { + const variables = props?.theme?.variables; + + return css({ + background: variables?.colors?.primary, + '.ss__loading-bar__bar': { + background: variables?.colors?.secondary, + }, + }); +}; + +// LoadingBar component props +export const loadingBar: ThemeComponent<'loadingBar', LoadingBarProps> = { + default: { + loadingBar: { + themeStyleScript: loadingBarStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/overlay.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/overlay.ts new file mode 100644 index 000000000..fbdce2654 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/overlay.ts @@ -0,0 +1,24 @@ +import { css } from '@emotion/react'; +import type { OverlayProps } from '../../../../components/Atoms/Overlay'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Overlay component +const overlayStyleScript = (props: OverlayProps) => { + const backgroundColor = props?.color || 'rgba(0, 0, 0, 0.80)'; + + return css({ + cursor: 'pointer', + '&, &.ss__overlay--active': { + background: backgroundColor, + }, + }); +}; + +// Overlay component props +export const overlay: ThemeComponent<'overlay', OverlayProps> = { + default: { + overlay: { + themeStyleScript: overlayStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/paginationInfo.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/paginationInfo.ts new file mode 100644 index 000000000..020e34110 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/paginationInfo.ts @@ -0,0 +1,23 @@ +import { css } from '@emotion/react'; +import type { PaginationInfoProps } from '../../../../components/Atoms/PaginationInfo'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Pagination component +const paginationInfoStyleScript = ({ theme }: PaginationInfoProps) => { + const variables = theme?.variables; + + return css({ + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }); +}; + +// PaginationInfo component props +export const paginationInfo: ThemeComponent<'paginationInfo', PaginationInfoProps> = { + default: { + paginationInfo: { + themeStyleScript: paginationInfoStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/price.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/price.ts new file mode 100644 index 000000000..32bb151d0 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/price.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { PriceProps } from '../../../../components/Atoms/Price'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Price component +const priceStyleScript = (props: PriceProps) => { + const variables = props?.theme?.variables; + + return css({ + '&, span, &.ss__price, &.ss__price--strike': { + color: variables?.colors?.text, + }, + '& ~ .ss__result__price': { + paddingLeft: `${custom.spacing.x1 / 2}px`, + }, + }); +}; + +// Price component props +export const price: ThemeComponent<'price', PriceProps> = { + default: { + price: { + themeStyleScript: priceStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/searchHeader.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/searchHeader.ts new file mode 100644 index 000000000..da5228dd2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/searchHeader.ts @@ -0,0 +1,43 @@ +import { css } from '@emotion/react'; +import type { SearchHeaderProps } from '../../../../components/Atoms/SearchHeader'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the SearchHeader component +const searchHeaderStyleScript = (props: SearchHeaderProps) => { + const variables = props?.theme?.variables; + + return css({ + em: { + fontStyle: 'normal', + }, + '.ss__search-header__title': { + margin: 0, + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + textTransform: custom.fonts.transform, + color: variables?.colors?.secondary, + }, + '.ss__search-header__subtitle': { + margin: `${custom.spacing.x2}px 0 0 0`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: 400, + color: variables?.colors?.text, + a: { + color: variables?.colors?.secondary, + }, + }, + '.ss__search-header__results-query': { + color: variables?.colors?.primary, + }, + }); +}; + +// SearchHeader component props +export const searchHeader: ThemeComponent<'searchHeader', SearchHeaderProps> = { + default: { + searchHeader: { + themeStyleScript: searchHeaderStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/atoms/skeleton.ts b/packages/snap-preact/components/src/themes/everest/components/atoms/skeleton.ts new file mode 100644 index 000000000..62b806141 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/atoms/skeleton.ts @@ -0,0 +1,13 @@ +import type { SkeletonProps } from '../../../../components/Atoms/Skeleton'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// Skeleton component props +export const skeleton: ThemeComponent<'skeleton', SkeletonProps> = { + default: { + skeleton: { + backgroundColor: custom.colors.gray02, + animatedColor: custom.colors.gray01, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/index.ts b/packages/snap-preact/components/src/themes/everest/components/index.ts new file mode 100644 index 000000000..b431ef8ce --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/index.ts @@ -0,0 +1,34 @@ +import { atoms } from './atoms'; +import { molecules } from './molecules'; +import { organisms } from './organisms'; +import { templates } from './templates'; + +import type { ThemeComponentsRestricted } from '../../../providers'; + +export const components: ThemeComponentsRestricted = { + ...atoms.default, + ...molecules.default, + ...organisms.default, + ...templates.default, +}; + +export const mobileComponents: ThemeComponentsRestricted = { + ...atoms.mobile, + ...molecules.mobile, + ...organisms.mobile, + ...templates.mobile, +}; + +export const tabletComponents: ThemeComponentsRestricted = { + ...atoms.tablet, + ...molecules.tablet, + ...organisms.tablet, + ...templates.tablet, +}; + +export const desktopComponents: ThemeComponentsRestricted = { + ...atoms.desktop, + ...molecules.desktop, + ...organisms.desktop, + ...templates.desktop, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/calloutBadge.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/calloutBadge.ts new file mode 100644 index 000000000..367766c73 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/calloutBadge.ts @@ -0,0 +1,31 @@ +import { css } from '@emotion/react'; +import type { CalloutBadgeProps } from '../../../../components/Molecules/CalloutBadge'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const calloutBadgeStyleScript = () => { + return css({ + gap: `${custom.spacing.x2}px`, + '& > div': { + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + lineHeight: 1, + span: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + '.ss__badge-text': { + padding: `0`, + }, + }); +}; + +// CalloutBadge component props +export const calloutBadge: ThemeComponent<'calloutBadge', CalloutBadgeProps> = { + default: { + calloutBadge: { + themeStyleScript: calloutBadgeStyleScript, + limit: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/carousel.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/carousel.ts new file mode 100644 index 000000000..c1b097655 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/carousel.ts @@ -0,0 +1,119 @@ +import { css } from '@emotion/react'; +import type { CarouselProps } from '../../../../components/Molecules/Carousel'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Carousel component +const carouselStyleScript = (props: CarouselProps) => { + const variables = props?.theme?.variables; + + // shared button styles + const disabledStyles = css({ + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }); + + return css({ + position: 'relative', + '.ss__carousel__prev-wrapper--hidden > div, .ss__carousel__next-wrapper--hidden > div': { + ...disabledStyles, + }, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + width: '32px', + height: '32px', + display: 'block', + position: 'absolute', + top: 0, + bottom: '22%', + zIndex: 2, + margin: 'auto', + '& > div': { + display: 'flex', + flexFlow: 'column nowrap', + alignItems: 'center', + justifyContent: 'center', + padding: 0, + width: '100%', + height: '100%', + lineHeight: 1, + backgroundColor: variables?.colors?.primary, + color: custom.colors.white, + }, + '.swiper-button-disabled': { + ...disabledStyles, + }, + }, + '.ss__carousel__prev-wrapper': { + left: 0, + }, + '.ss__carousel__next-wrapper': { + right: 0, + }, + '.swiper-container': { + margin: '0 auto', + '&:has(.swiper-pagination)': { + paddingBottom: `${custom.spacing.x5}px`, + }, + '& > .swiper-wrapper': { + '& > .swiper-slide': { + '& > *, .ss__result': { + padding: 0, + margin: 0, + width: 'auto', + height: '100%', + }, + }, + }, + '& > .swiper-pagination': { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + '.swiper-pagination-bullet': { + margin: `0 ${custom.spacing.x1 / 2}px`, + width: '12px', + height: '12px', + minWidth: '1px', + flex: '0 1 auto', + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + opacity: 1, + }, + '.swiper-pagination-bullet-active': { + backgroundColor: variables?.colors?.primary, + borderColor: variables?.colors?.primary, + }, + }, + }, + '.swiper-grid-column': { + '& > .swiper-wrapper': { + flexFlow: 'row wrap', + '& > .swiper-slide': { + height: 'auto !important', + marginTop: '0 !important', + marginBottom: `${custom.spacing.x4}px`, + }, + }, + }, + }); +}; + +// Carousel component props +export const carousel: ThemeComponent<'carousel', CarouselProps> = { + default: { + carousel: { + themeStyleScript: carouselStyleScript, + }, + 'carousel icon.prev': { + icon: custom.icons.arrowLeft, + size: `${custom.sizes.icon12}px`, + }, + 'carousel icon.next': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/checkbox.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/checkbox.ts new file mode 100644 index 000000000..c195b8fdf --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/checkbox.ts @@ -0,0 +1,81 @@ +import { css } from '@emotion/react'; +import type { CheckboxProps } from '../../../../components/Molecules/Checkbox'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Checkbox component +const checkboxStyleScript = (props: CheckboxProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + // shared checkbox styles + const sharedStyles = css({ + position: 'relative', + top: '-1px', + }); + const sharedDefaultStyles = css({ + border: `1px solid ${custom.colors.gray02}`, + '&, *': { + boxSizing: 'border-box', + }, + '.ss__icon': { + width: '8px', + height: '8px', + }, + '&.ss__checkbox--active': { + borderColor: darkGray, + '.ss__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }); + const disabledStyles = css({ + '&.ss__checkbox--disabled': { + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }, + }); + + // default checkbox styles + const defaultStyles = css([ + sharedStyles, + sharedDefaultStyles, + { + backgroundColor: custom.colors.gray01, + }, + disabledStyles, + ]); + + // native checkbox styles + const nativeStyles = css([ + sharedStyles, + { + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + border: `1px solid ${custom.colors.gray02}`, + cursor: 'pointer', + }, + disabledStyles, + ]); + + // return checkbox styles + if (props?.native) { + return nativeStyles; + } else { + return defaultStyles; + } +}; + +// Checkbox component props +export const checkbox: ThemeComponent<'checkbox', CheckboxProps> = { + default: { + checkbox: { + themeStyleScript: checkboxStyleScript, + icon: custom.icons.check, + size: `${custom.sizes.icon16}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/errorHandler.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/errorHandler.ts new file mode 100644 index 000000000..c66af2df3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/errorHandler.ts @@ -0,0 +1,40 @@ +import { css } from '@emotion/react'; +import type { ErrorHandlerProps } from '../../../../components/Molecules/ErrorHandler'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the ErrorHandler component +const errorHandlerStyleScript = (props: ErrorHandlerProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__error-handler__message': { + display: 'block', + flex: `1 1 0%`, + color: variables?.colors?.text, + '.ss__icon': { + position: 'relative', + top: '2px', + }, + }, + '.ss__error-handler__button': { + gap: 0, + flex: `0 1 auto`, + padding: `0 ${custom.spacing.x1}px`, + height: '25px', + lineHeight: '25px', + }, + }); +}; + +// ErrorHandler component props +export const errorHandler: ThemeComponent<'errorHandler', ErrorHandlerProps> = { + default: { + errorHandler: { + themeStyleScript: errorHandlerStyleScript, + }, + 'errorHandler icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/facetGridOptions.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/facetGridOptions.ts new file mode 100644 index 000000000..ab0e828ca --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/facetGridOptions.ts @@ -0,0 +1,76 @@ +import { css } from '@emotion/react'; +import type { FacetGridOptionsProps } from '../../../../components/Molecules/FacetGridOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the FacetGridOptions component +const facetGridOptionsStyleScript = (props: FacetGridOptionsProps) => { + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const fontColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#d15120' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + const gridSize = props?.gridSize ? props.gridSize : '52px'; + + return css({ + gridTemplateColumns: `repeat(auto-fill, minmax(${gridSize}, 1fr))`, + gap: props?.gapSize ? props.gapSize : custom.spacing.x1, + alignItems: 'center', + '.ss__facet-grid-options__option': { + position: 'relative', + height: '100%', + aspectRatio: 1, + border: 0, + color: variables?.colors?.text, + '&, &:after, .ss__facet-grid-options__option__value': { + boxSizing: 'border-box', + }, + '&:after, .ss__facet-grid-options__option__value': { + display: 'block', + }, + '&:after': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 1, + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + }, + '.ss__facet-grid-options__option__value': { + position: 'relative', + zIndex: 2, + maxWidth: `calc(100% - ${custom.spacing.x2}px)`, + maxHeight: `calc(100% - ${custom.spacing.x2}px)`, + overflow: 'hidden', + '&, &.ss__facet-grid-options__option__value--smaller': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1, + }, + }, + }, + '.ss__facet-grid-options__option.ss__facet-grid-options__option--filtered': { + fontWeight: custom.fonts.weight01, + color: fontColor.hex(), + '&:after': { + backgroundColor: activeColor.hex(), + borderColor: activeColor.hex(), + }, + }, + }); +}; + +// FacetGridOptions component props +export const facetGridOptions: ThemeComponent<'facetGridOptions', FacetGridOptionsProps> = { + default: { + facetGridOptions: { + themeStyleScript: facetGridOptionsStyleScript, + gridSize: '52px', + gapSize: `${custom.spacing.x1}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/facetHierarchyOptions.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/facetHierarchyOptions.ts new file mode 100644 index 000000000..13419c29d --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/facetHierarchyOptions.ts @@ -0,0 +1,64 @@ +import { css } from '@emotion/react'; +import type { FacetHierarchyOptionsProps } from '../../../../components/Molecules/FacetHierarchyOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FacetHierarchyOptions component +const facetHierarchyOptionsStyleScript = (props: FacetHierarchyOptionsProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + + return css({ + '.ss__facet-hierarchy-options__option': { + display: 'block', + margin: `0 0 ${custom.spacing.x1}px 0`, + padding: 0, + color: variables?.colors?.text, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__facet-hierarchy-options__option__value': { + margin: 0, + '.ss__facet-hierarchy-options__option__value__count': { + position: 'relative', + top: '-1px', + margin: 0, + padding: `0 ${custom.spacing.x1}px`, + fontSize: custom.utils.convertPxToEm(10), + color: lightGray, + }, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--return': { + '&:before': { + display: 'none', + }, + '.ss__icon': { + position: 'relative', + top: '1px', + margin: `0 ${custom.spacing.x1}px 0 0`, + padding: 0, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--filtered': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '& ~ .ss__facet-hierarchy-options__option:not(.ss__facet-hierarchy-options__option--filtered)': { + paddingLeft: `${custom.spacing.x6}px`, + }, + }, + }); +}; + +// FacetHierarchyOptions component props +export const facetHierarchyOptions: ThemeComponent<'facetHierarchyOptions', FacetHierarchyOptionsProps> = { + default: { + facetHierarchyOptions: { + themeStyleScript: facetHierarchyOptionsStyleScript, + returnIcon: custom.icons.arrowLeft, + }, + 'facetHierarchyOptions icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/facetListOptions.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/facetListOptions.ts new file mode 100644 index 000000000..e42c39a96 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/facetListOptions.ts @@ -0,0 +1,54 @@ +import { css } from '@emotion/react'; +import type { FacetListOptionsProps } from '../../../../components/Molecules/FacetListOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FacetListOptions component +const facetListOptionsStyleScript = (props: FacetListOptionsProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const checkboxSpacing = custom.sizes.icon16 + custom.spacing.x2; + + return css({ + '.ss__facet-list-options__option': { + display: 'block', + position: 'relative', + margin: `0 0 ${custom.spacing.x1}px 0`, + color: variables?.colors?.text, + padding: props?.hideCheckbox ? `` : `0 0 0 ${checkboxSpacing}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__checkbox, .ss__radio': { + position: 'absolute', + top: '1.5px', + left: 0, + }, + '.ss__facet-list-options__option__value': { + margin: 0, + '.ss__facet-list-options__option__value__count': { + position: 'relative', + top: '-1px', + margin: 0, + padding: `0 ${custom.spacing.x1}px`, + fontSize: custom.utils.convertPxToEm(10), + color: lightGray, + }, + }, + }, + '.ss__facet-list-options__option.ss__facet-list-options__option--filtered': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }); +}; + +// FacetListOptions component props +export const facetListOptions: ThemeComponent<'facetListOptions', FacetListOptionsProps> = { + default: { + facetListOptions: { + themeStyleScript: facetListOptionsStyleScript, + respectSingleSelect: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/facetPaletteOptions.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/facetPaletteOptions.ts new file mode 100644 index 000000000..405114def --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/facetPaletteOptions.ts @@ -0,0 +1,211 @@ +import { css } from '@emotion/react'; +import type { FacetPaletteOptionsProps } from '../../../../components/Molecules/FacetPaletteOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FacetPaletteOptions component +const facetPaletteStyleScript = (props: FacetPaletteOptionsProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const hasCheckbox = !props?.hideCheckbox ? true : false; + + // set details for radius + const radius = 0; + const radiusUnit = 'px'; + const paletteRadius = radius ? `${radius}${radiusUnit}` : `0`; + + // determine inner border width + let innerBorder = 5; + if (props?.layout == 'list') { + innerBorder = hasCheckbox ? 2 : 3; + } + + // shared palette styles + const sharedStyles = css({ + '.ss__facet-palette-options__option': { + display: 'block', + color: variables?.colors?.text, + '&, &.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper': { + border: 0, + borderRadius: 0, + padding: 0, + }, + }, + '&.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper .ss__facet-palette-options__option__palette': { + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + }, + }, + '.ss__facet-palette-options__option__wrapper': { + overflow: 'hidden', + '.ss__facet-palette-options__option__palette': { + border: 0, + padding: 0, + '&, &:before, &:after': { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + borderRadius: paletteRadius, + boxSizing: 'border-box', + }, + '&:before, &:after': { + content: '""', + display: 'block', + }, + '&:before': { + border: `${innerBorder}px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + }, + }, + '.ss__facet-palette-options__option__value__count': { + position: 'relative', + top: props?.layout == 'list' ? '-1px' : '', + padding: props?.layout == 'list' ? `0 ${custom.spacing.x1}px` : ``, + fontSize: custom.utils.convertPxToEm(10), + color: lightGray, + }, + }, + }); + + // grid palette styles + const gridStyles = css([ + sharedStyles, + { + gridTemplateColumns: `repeat(auto-fill, minmax(${props?.gridSize ? props.gridSize : '52px'}, 1fr))`, + gap: props?.gapSize ? props.gapSize : custom.spacing.x1, + alignItems: 'center', + '.ss__facet-palette-options__option': { + textAlign: 'center', + '&, &.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper': { + position: 'relative', + height: 0, + padding: '0 0 100% 0', + }, + }, + '.ss__checkbox, .ss__radio': { + display: 'none', + }, + '.ss__facet-palette-options__option__value, .ss__facet-palette-options__option__value__count': { + display: 'block', + lineHeight: '0.85rem', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + '.ss__facet-palette-options__option__value': { + fontSize: custom.utils.convertPxToEm(12), + overflow: 'hidden', + margin: `${custom.spacing.x1}px 0 0 0`, + }, + '.ss__facet-palette-options__option__value__count': { + margin: `${custom.spacing.x1 / 2}px 0 0 0`, + }, + }, + }, + ]); + + // list variables + const listSize = hasCheckbox ? 16 : 22; + const listCheckboxSize = 16; + const listPadding = hasCheckbox ? custom.spacing.x4 + listSize + listCheckboxSize : custom.spacing.x2 + listSize; + + // list palette styles + const listStyles = css([ + sharedStyles, + { + '&.ss__facet-palette-options--list': { + display: 'block', + }, + '.ss__facet-palette-options__option': { + position: 'relative', + padding: `${hasCheckbox ? 0 : '2px'} 0 0 ${listPadding}px`, + margin: `0 0 ${custom.spacing.x1}px 0`, + minHeight: hasCheckbox ? '' : `${listSize + 2}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__checkbox, .ss__radio, .ss__facet-palette-options__option__wrapper': { + position: 'absolute', + top: `${hasCheckbox ? 2 : 0.5}px`, + }, + '.ss__checkbox, .ss__radio': { + left: 0, + }, + '.ss__facet-palette-options__option__wrapper': { + left: hasCheckbox ? `${listCheckboxSize + custom.spacing.x2}px` : 0, + width: `${listSize}px`, + height: `${listSize}px`, + lineHeight: `${listSize}px`, + }, + '.ss__facet-palette-options__option__value, .ss__facet-palette-options__option__value__count': { + display: 'inline', + overflow: 'visible', + textOverflow: 'unset', + textAlign: 'left', + whiteSpace: 'unset', + }, + '.ss__facet-palette-options__option__value__count': { + margin: 0, + }, + }, + }, + ]); + + return props?.layout == 'list' ? listStyles : gridStyles; +}; + +// FacetPaletteOptions component props +export const facetPaletteOptions: ThemeComponent<'facetPaletteOptions', FacetPaletteOptionsProps> = { + default: { + facetPaletteOptions: { + themeStyleScript: facetPaletteStyleScript, + hideIcon: true, + gridSize: '52px', + gapSize: `${custom.spacing.x1}px`, + colorMapping: { + brown: { + background: custom.colors.brown, + }, + multi: { + background: custom.colors.rainbow, + }, + 'multi-color': { + background: custom.colors.rainbow, + }, + purple: { + background: custom.colors.purple, + }, + rainbow: { + background: custom.colors.rainbow, + }, + }, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/facetSlider.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/facetSlider.ts new file mode 100644 index 000000000..079aead88 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/facetSlider.ts @@ -0,0 +1,200 @@ +import { css } from '@emotion/react'; +import type { FacetSliderProps } from '../../../../components/Molecules/FacetSlider'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the FacetSlider component +const facetSliderStyleScript = (props: FacetSliderProps) => { + // slider options + const slider = { + handles: 20, // handle size + values: 14, // values size + bar: 6, // bar size + ticks: 17, // size of ticks + valuesPosition: 'top', // position of slider values (top or bottom) + valuesAlign: 'sides', // alignment of slider values (sides or center) + }; + + const variables = props?.theme?.variables; + const fontColor = props?.valueTextColor || variables?.colors?.text; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + const valuesTop = slider.valuesPosition == 'top' ? true : false; + const valuesSides = slider.valuesAlign == 'sides' ? true : false; + const hasTicks = props?.showTicks ? true : false; + const hasStickyHandles = props?.stickyHandleLabel ? true : false; + const handleColor = new Color(props?.handleColor || variables?.colors?.primary || undefined); + const handleInnerColor = + handleColor.isDark() || handleColor.hex().toLowerCase() == '#d15120' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + + // values font styles + const valuesStyles = css({ + fontSize: custom.utils.convertPxToEm(slider.values), + lineHeight: `${slider.values}px`, + color: fontColor, + }); + + // shared slider styles + const sharedStyles = css({ + '&, *': { + boxSizing: 'border-box', + }, + '&, .ss__facet-slider__slider': { + margin: 'auto', + }, + '.ss__facet-slider__slider button, .ss__facet-slider__labels label': { + margin: 0, + padding: 0, + '&:focus': { + outline: 0, + }, + }, + '.ss__facet-slider__slider': { + display: 'block', + top: 0, + width: '100%', + height: `${slider.bar}px`, + '.ss__facet-slider__segment, .ss__facet-slider__rail, .ss__facet-slider__handles': { + height: '100%', + }, + '.ss__facet-slider__tick': { + '&:before, .ss__facet-slider__tick__label': { + transform: 'translate(-50%, 0)', + }, + '&:before': { + top: `${slider.ticks / 2}px`, + backgroundColor: darkGray, + }, + '.ss__facet-slider__tick__label': { + top: `${slider.ticks}px`, + color: props?.tickTextColor || variables?.colors?.text, + lineHeight: 1, + }, + }, + '.ss__facet-slider__segment': { + backgroundColor: props?.trackColor || custom.colors.gray01, + border: `1px solid ${props?.trackColor || custom.colors.gray02}`, + borderRadius: `${slider.bar}px`, + }, + '.ss__facet-slider__rail': { + backgroundColor: props?.railColor || variables?.colors?.secondary, + border: `1px solid ${props?.railColor || variables?.colors?.secondary}`, + }, + '.ss__facet-slider__handles': { + position: 'relative', + margin: `0 ${slider.handles / 2 - 2}px`, + button: { + '.ss__facet-slider__handle': { + transform: 'none', + width: `${slider.handles}px`, + height: `${slider.handles}px`, + lineHeight: `${slider.handles}px`, + backgroundColor: handleColor.hex(), + border: `1px solid ${handleColor.hex()}`, + '&:after': { + width: `${slider.handles / 4}px`, + height: `${slider.handles / 4}px`, + backgroundColor: handleInnerColor.hex(), + border: `1px solid ${handleInnerColor.hex()}`, + }, + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + backgroundColor: 'transparent', + '&': { + ...valuesStyles, + }, + }, + }, + }, + }, + }, + '.ss__facet-slider__labels': { + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + justifyContent: valuesSides ? '' : 'center', + '.ss__facet-slider__label': { + '&': { + ...valuesStyles, + }, + '&:after': { + display: valuesSides ? 'none' : '', + padding: `0 ${custom.spacing.x1}px`, + }, + '& ~ .ss__facet-slider__label': { + marginLeft: valuesSides ? 'auto' : '', + }, + }, + }, + }); + + // spacing and size calculations + const handlesSizeHalf = (slider.handles - slider.bar) / 2; + const handlesSpacing = slider.handles + custom.spacing.x2; + const ticksSpacing = slider.ticks + custom.spacing.x1; + const stickySpacing = slider.values + custom.spacing.x2; + const handlesPlusSticky = handlesSizeHalf + stickySpacing; + const ticksPlusSticky = ticksSpacing + stickySpacing; + + // spacing styles for different configurations + // note: default for facet slider is no ticks, no stick handles, values bottom + let spacingStyles = css({}); + + if (hasTicks && hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${valuesTop ? handlesPlusSticky : handlesSizeHalf}px auto ${valuesTop ? ticksSpacing : ticksPlusSticky}px auto`, + '.ss__facet-slider__handles button .ss__facet-slider__handle': { + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + top: valuesTop ? `auto` : `${handlesSizeHalf + ticksPlusSticky - slider.bar}px`, + bottom: valuesTop ? `${handlesSpacing}px` : ``, + }, + }, + }, + }); + } else if (hasTicks && !hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${handlesSizeHalf}px auto ${ticksSpacing}px auto`, + }, + '.ss__facet-slider__labels': { + order: valuesTop ? -1 : '', + margin: `${valuesTop ? 0 : custom.spacing.x2}px 0 ${valuesTop ? custom.spacing.x2 : 0}px 0`, + }, + }); + } else if (!hasTicks && hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${valuesTop ? handlesPlusSticky : handlesSizeHalf}px auto ${valuesTop ? handlesSizeHalf : handlesPlusSticky}px auto`, + '.ss__facet-slider__handles button .ss__facet-slider__handle': { + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + top: valuesTop ? 'auto' : `${handlesSpacing}px`, + bottom: valuesTop ? `${handlesSpacing}px` : ``, + }, + }, + }, + }); + } else { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${handlesSizeHalf}px auto`, + }, + '.ss__facet-slider__labels': { + order: valuesTop ? -1 : '', + margin: `${valuesTop ? 0 : custom.spacing.x2}px 0 ${valuesTop ? custom.spacing.x2 : 0}px 0`, + }, + }); + } + + return css([sharedStyles, spacingStyles]); +}; + +// FacetSlider component props +export const facetSlider: ThemeComponent<'facetSlider', FacetSliderProps> = { + default: { + facetSlider: { + themeStyleScript: facetSliderStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/filter.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/filter.ts new file mode 100644 index 000000000..15aede8a4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/filter.ts @@ -0,0 +1,44 @@ +import { css } from '@emotion/react'; +import type { FilterProps } from '../../../../components/Molecules/Filter'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Filter component +const filterStyleScript = (props: FilterProps) => { + const variables = props?.theme?.variables; + + return css({ + display: 'block', + padding: 0, + '.ss__filter__button': { + position: 'relative', + height: 'auto', + lineHeight: 1.5, + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + fontWeight: 'normal', + color: variables?.colors?.text, + '&, &:hover, &:not(.ss__button--disabled):hover, &.ss__button--disabled': { + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + }, + '.ss__button__content': { + '.ss__filter__label': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + }); +}; + +// Filter component props +export const filter: ThemeComponent<'filter', FilterProps> = { + default: { + filter: { + themeStyleScript: filterStyleScript, + icon: custom.icons.close, + }, + 'filter icon': { + size: `${custom.sizes.icon10}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/grid.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/grid.ts new file mode 100644 index 000000000..934405320 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/grid.ts @@ -0,0 +1,188 @@ +import { css } from '@emotion/react'; +import type { GridProps } from '../../../../components/Molecules/Grid'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// grid size +const gridSize = 42; + +// CSS in JS style script for the Grid component +const gridStyleScript = (props: Partial) => { + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const fontColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#d15120' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + return css({ + '.ss__grid__title': { + margin: `0 0 ${custom.spacing.x1}px 0`, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + lineHeight: 1, + }, + '.ss__grid__options': { + display: 'flex', + flexFlow: 'row wrap', + gap: props?.gapSize ? props.gapSize : custom.spacing.x1, + alignItems: 'center', + '&:before, &:after': { + display: 'none', + }, + '.ss__grid__option': { + flex: '0 1 auto', + minWidth: '1px', + '&, &.ss__grid__option--selected': { + border: 0, + }, + '.ss__grid__option__inner .ss__grid__option__label, .ss__grid__show-more-wrapper': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1, + }, + }, + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + position: 'relative', + width: `${gridSize}px`, + maxHeight: `${gridSize}px`, + aspectRatio: 1, + color: variables?.colors?.text, + overflow: 'hidden', + '&, &:after, *': { + boxSizing: 'border-box', + }, + '&:before': { + display: 'none', + }, + '&:after': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 1, + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&.ss__grid__option--dark, &:has(.ss__grid__option__inner--grey)': { + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + color: fontColor.hex(), + }, + }, + }, + '&.ss__grid__option--selected': { + '&:after': { + opacity: 0.3, + }, + '&:has(.ss__grid__option__inner:not([style]))': { + backgroundColor: activeColor.hex(), + '&:after': { + borderColor: activeColor.hex(), + opacity: 1, + }, + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + color: fontColor.hex(), + }, + }, + }, + '&:has(.ss__grid__option__inner .ss__image)': { + backgroundColor: 'transparent', + '&:after': { + borderColor: custom.colors.black, + opacity: 0.3, + }, + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + color: variables?.colors?.text, + }, + }, + }, + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + '&.ss__grid__option--disabled, &.ss__grid__option--unavailable': { + opacity: 1, + cursor: 'not-allowed', + pointerEvents: 'none', + '.ss__grid__option__inner:after': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 3, + margin: 'auto', + backgroundColor: darkGray.replace('#', ''), + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center center', + backgroundImage: `url("data:image/svg+xml,%3Csvg style=%27transform: rotate%28-45deg%29%27 xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 56 56%27 preserveAspectRatio=%27xMinYMid%27%3E%3Cpath fill=%27%23${darkGray.replace( + '#', + '' + )}%27 d=%27M0 23.297h56v9.406h-56v-9.406z%27 /%3E%3C/svg%3E")`, + }, + }, + '.ss__grid__option__inner': { + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + '.ss__grid__option__label': { + display: 'block', + position: 'absolute', + zIndex: 2, + maxWidth: `calc(100% - ${custom.spacing.x2}px)`, + maxHeight: `calc(100% - ${custom.spacing.x2}px)`, + overflow: 'hidden', + }, + }, + }, + '.ss__grid__show-more-wrapper': { + maxHeight: 'none', + }, + }, + '.ss__grid__show-more-wrapper': { + '&:not(.ss__grid__option)': { + margin: `${custom.spacing.x2}px 0 0 0`, + }, + '&, .ss__grid__show-more': { + cursor: 'pointer', + }, + '.ss__grid__show-more': { + fontSize: custom.utils.convertPxToEm(12), + fontWeight: custom.fonts.weight01, + lineHeight: 1, + color: variables?.colors?.primary, + }, + }, + }); +}; + +// Grid component props +export const grid: ThemeComponent<'grid', GridProps> = { + default: { + grid: { + themeStyleScript: gridStyleScript, + gapSize: `${custom.spacing.x1}px`, + hideLabels: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/index.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/index.ts new file mode 100644 index 000000000..870baa582 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/index.ts @@ -0,0 +1,144 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// MOLECULES Imports +import { calloutBadge } from './calloutBadge'; +import { carousel } from './carousel'; +import { checkbox } from './checkbox'; +import { errorHandler } from './errorHandler'; +import { facetGridOptions } from './facetGridOptions'; +import { facetHierarchyOptions } from './facetHierarchyOptions'; +import { facetListOptions } from './facetListOptions'; +import { facetPaletteOptions } from './facetPaletteOptions'; +import { facetSlider } from './facetSlider'; +import { filter } from './filter'; +import { grid } from './grid'; +import { layoutSelector } from './layoutSelector'; +import { list } from './list'; +import { loadMore } from './loadMore'; +import { overlayBadge } from './overlayBadge'; +import { pagination } from './pagination'; +import { radio } from './radio'; +import { radioList } from './radioList'; +import { result } from './result'; +import { searchInput } from './searchInput'; +import { select } from './select'; +import { slideout } from './slideout'; +import { rating } from './rating'; +import { swatches } from './swatches'; +import { variantSelection } from './variantSelection'; +import { terms } from './terms'; + +export const molecules: ThemeResponsiveComplete = { + default: { + ...carousel.default, + ...checkbox.default, + ...errorHandler.default, + ...facetGridOptions.default, + ...facetHierarchyOptions.default, + ...facetListOptions.default, + ...facetPaletteOptions.default, + ...facetSlider.default, + ...filter.default, + ...grid.default, + ...layoutSelector.default, + ...list.default, + ...loadMore.default, + ...overlayBadge.default, + ...pagination.default, + ...radio.default, + ...radioList.default, + ...result.default, + ...searchInput.default, + ...select.default, + ...slideout.default, + ...rating.default, + ...swatches.default, + ...variantSelection.default, + ...terms.default, + ...calloutBadge.default, + }, + mobile: { + ...carousel.mobile, + ...checkbox.mobile, + ...errorHandler.mobile, + ...facetGridOptions.mobile, + ...facetHierarchyOptions.mobile, + ...facetListOptions.mobile, + ...facetPaletteOptions.mobile, + ...facetSlider.mobile, + ...filter.mobile, + ...grid.mobile, + ...layoutSelector.mobile, + ...list.mobile, + ...loadMore.mobile, + ...overlayBadge.mobile, + ...pagination.mobile, + ...radio.mobile, + ...radioList.mobile, + ...result.mobile, + ...searchInput.mobile, + ...select.mobile, + ...slideout.mobile, + ...rating.mobile, + ...swatches.mobile, + ...variantSelection.mobile, + ...terms.mobile, + ...calloutBadge.mobile, + }, + tablet: { + ...carousel.tablet, + ...checkbox.tablet, + ...errorHandler.tablet, + ...facetGridOptions.tablet, + ...facetHierarchyOptions.tablet, + ...facetListOptions.tablet, + ...facetPaletteOptions.tablet, + ...facetSlider.tablet, + ...filter.tablet, + ...grid.tablet, + ...layoutSelector.tablet, + ...list.tablet, + ...loadMore.tablet, + ...overlayBadge.tablet, + ...pagination.tablet, + ...radio.tablet, + ...radioList.tablet, + ...result.tablet, + ...searchInput.tablet, + ...select.tablet, + ...slideout.tablet, + ...rating.tablet, + ...swatches.tablet, + ...variantSelection.tablet, + ...terms.tablet, + ...calloutBadge.tablet, + }, + desktop: { + ...carousel.desktop, + ...checkbox.desktop, + ...errorHandler.desktop, + ...facetGridOptions.desktop, + ...facetHierarchyOptions.desktop, + ...facetListOptions.desktop, + ...facetPaletteOptions.desktop, + ...facetSlider.desktop, + ...filter.desktop, + ...grid.desktop, + ...layoutSelector.desktop, + ...list.desktop, + ...loadMore.desktop, + ...overlayBadge.desktop, + ...pagination.desktop, + ...radio.desktop, + ...radioList.desktop, + ...result.desktop, + ...searchInput.desktop, + ...select.desktop, + ...slideout.desktop, + ...rating.desktop, + ...swatches.desktop, + ...variantSelection.desktop, + ...terms.desktop, + ...calloutBadge.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/layoutSelector.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/layoutSelector.ts new file mode 100644 index 000000000..36639c34d --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/layoutSelector.ts @@ -0,0 +1,76 @@ +import { css } from '@emotion/react'; +import type { LayoutSelectorProps } from '../../../../components/Molecules/LayoutSelector'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the LayoutSelector component +const layoutSelectorStyleScript = (props: LayoutSelectorProps) => { + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const activeIconColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#d15120' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + + // dropdown styles + const dropdownStyles = css({ + '.ss__dropdown': { + '.ss__dropdown__button .ss__button__content': { + gap: `${custom.spacing.x2}px`, + }, + }, + }); + + // list styles + const listStyles = css({ + '.ss__list__options': { + display: 'flex', + '.ss__list__option': { + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + padding: `0 ${custom.spacing.x2}px`, + margin: 0, + }, + '.ss__list__option--selected': { + borderColor: activeColor.hex(), + backgroundColor: activeColor.hex(), + color: activeIconColor.hex(), + '&, *': { + cursor: 'text', + }, + }, + }, + }); + + if (props?.type == 'dropdown') { + return dropdownStyles; + } else if (props?.type == 'list') { + return listStyles; + } else { + return dropdownStyles; + } +}; + +// LayoutSelector component props +export const layoutSelector: ThemeComponent<'layoutSelector', LayoutSelectorProps> = { + default: { + layoutSelector: { + themeStyleScript: layoutSelectorStyleScript, + type: 'list', + }, + 'layoutSelector select': { + hideSelection: false, + separator: '', + }, + 'layoutSelector list': { + hideTitleText: true, + hideOptionLabels: true, + }, + 'layoutSelector radioList': { + hideTitleText: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/list.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/list.ts new file mode 100644 index 000000000..1ea3e1484 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/list.ts @@ -0,0 +1,45 @@ +import { css } from '@emotion/react'; +import type { ListProps } from '../../../../components/Molecules/List'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the List component +const listStyleScript = (props: ListProps) => { + const variables = props?.theme?.variables; + + return css({ + '&, .ss__list__options': { + display: 'block', + }, + '.ss__list__title, .ss__list__options .ss__list__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + }, + '.ss__list__title': { + display: 'block', + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + lineHeight: 1, + }, + '.ss__list__options': { + '.ss__list__option': { + gap: `${custom.spacing.x2}px`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__list__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }, + }); +}; + +// List component props +export const list: ThemeComponent<'list', ListProps> = { + default: { + list: { + themeStyleScript: listStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/loadMore.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/loadMore.ts new file mode 100644 index 000000000..3da120d93 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/loadMore.ts @@ -0,0 +1,53 @@ +import { css } from '@emotion/react'; +import type { LoadMoreProps } from '../../../../components/Molecules/LoadMore'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the LoadMore component +const loadMoreStyleScript = (props: LoadMoreProps) => { + const variables = props?.theme?.variables; + const indicatorColor = new Color(props?.backgroundColor || custom.colors.gray01 || undefined); + const indicatorBorderColor = new Color(props?.backgroundColor || custom.colors.gray02 || undefined); + const barColor = new Color(props?.color || variables?.colors?.primary || undefined); + + return css({ + '&.ss__load-more': { + '&, .ss__load-more__progress': { + gap: `${custom.spacing.x2}px`, + }, + '& > .ss__load-more__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + '.ss__button': { + '.ss__button__content': { + display: 'flex', + alignItems: 'center', + }, + }, + '.ss__load-more__progress': { + '.ss__load-more__progress__indicator': { + backgroundColor: indicatorColor.hex(), + border: `1px solid ${indicatorBorderColor}`, + '.ss__load-more__progress__indicator__bar': { + backgroundColor: barColor.hex(), + margin: '-1px', + }, + }, + '.ss__load-more__progress__text': { + color: variables?.colors?.text, + }, + }, + }, + }); +}; + +// LoadMore component props +export const loadMore: ThemeComponent<'loadMore', LoadMoreProps> = { + default: { + loadMore: { + themeStyleScript: loadMoreStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/overlayBadge.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/overlayBadge.ts new file mode 100644 index 000000000..4f5fce065 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/overlayBadge.ts @@ -0,0 +1,34 @@ +import { css } from '@emotion/react'; +import type { OverlayBadgeProps } from '../../../../components/Molecules/OverlayBadge'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const overlayBadgeStyleScript = () => { + return css({ + '.ss__overlay-badge__grid-wrapper': { + gap: `${custom.spacing.x1}px`, + bottom: 'auto', + '.ss__overlay-badge__grid-wrapper__slot': { + gap: 0, + '& > div': { + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + lineHeight: 1, + span: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }); +}; + +// OverlayBadge component props +export const overlayBadge: ThemeComponent<'overlayBadge', OverlayBadgeProps> = { + default: { + overlayBadge: { + themeStyleScript: overlayBadgeStyleScript, + limit: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/pagination.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/pagination.ts new file mode 100644 index 000000000..855be34e3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/pagination.ts @@ -0,0 +1,73 @@ +import { css } from '@emotion/react'; +import type { PaginationProps } from '../../../../components/Molecules/Pagination'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Pagination component +const paginationStyleScript = (props: PaginationProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + nav: { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + justifyContent: 'center', + lineHeight: 1, + '.ss__pagination__page, span': { + padding: `0 ${custom.spacing.x1}px`, + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.text, + }, + '.ss__pagination__page': { + minWidth: '1px', + minHeight: '1px', + }, + '.ss__pagination__page--active': { + color: variables?.colors?.primary, + }, + '.ss__pagination__page--previous, .ss__pagination__page--next': { + lineHeight: `${custom.sizes.icon12}px`, + '.ss__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + nav: { + '.ss__pagination__page, span': { + padding: `0 ${custom.spacing.x2}px`, + fontSize: custom.utils.convertPxToEm(16), + }, + '.ss__pagination__page--previous, .ss__pagination__page--next': { + lineHeight: `${custom.sizes.icon14}px`, + }, + }, + }, + }); +}; + +// Pagination component props +export const pagination: ThemeComponent<'pagination', PaginationProps> = { + default: { + pagination: { + themeStyleScript: paginationStyleScript, + }, + 'pagination icon': { + size: `${custom.sizes.icon12}px`, + }, + 'pagination icon.prev': { + icon: custom.icons.arrowLeft, + }, + 'pagination icon.next': { + icon: custom.icons.arrowRight, + }, + }, + mobile: { + 'pagination icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/radio.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/radio.ts new file mode 100644 index 000000000..46a2b5147 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/radio.ts @@ -0,0 +1,81 @@ +import { css } from '@emotion/react'; +import type { RadioProps } from '../../../../components/Molecules/Radio'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Radio component +const radioStyleScript = (props: RadioProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + // shared radio styles + const sharedDefaultStyles = css({ + border: `1px solid ${custom.colors.gray02}`, + '&, & .ss__icon': { + borderRadius: '50%', + }, + '.ss__icon': { + display: 'none', + }, + '&.ss__radio--active': { + borderColor: darkGray, + '.ss__icon': { + display: 'block', + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }); + const disabledStyles = css({ + '&.ss__radio--disabled': { + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }, + }); + + // default radio styles + const defaultStyles = css([ + sharedDefaultStyles, + { + backgroundColor: custom.colors.gray01, + }, + disabledStyles, + ]); + + // native radio styles + const nativeStyles = css([ + { + lineHeight: 0, + '.ss__radio__input': { + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + border: `1px solid ${custom.colors.gray02}`, + cursor: 'pointer', + }, + }, + disabledStyles, + ]); + + // return radio styles + if (props?.native) { + return nativeStyles; + } else { + return defaultStyles; + } +}; + +// Radio component props +export const radio: ThemeComponent<'radio', RadioProps> = { + default: { + radio: { + themeStyleScript: radioStyleScript, + size: `${custom.sizes.icon14}px`, + }, + 'radio icon': { + icon: 'square', + size: `${custom.sizes.icon10 - 2}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/radioList.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/radioList.ts new file mode 100644 index 000000000..0aa063233 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/radioList.ts @@ -0,0 +1,47 @@ +import { css } from '@emotion/react'; +import type { RadioListProps } from '../../../../components/Molecules/RadioList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RadioList component +const radioListStyleScript = (props: RadioListProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__radio-list__title, .ss__radio-list__options-wrapper .ss__radio-list__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + }, + '.ss__radio-list__title': { + display: 'block', + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + lineHeight: 1, + }, + '.ss__radio-list__options-wrapper': { + '.ss__radio-list__option': { + gap: `${custom.spacing.x2}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__radio-list__option__icon, .ss__radio-list__option__label': { + padding: 0, + }, + }, + '.ss__radio-list__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }, + }); +}; + +// RadioList component props +export const radioList: ThemeComponent<'radioList', RadioListProps> = { + default: { + radioList: { + themeStyleScript: radioListStyleScript, + hideOptionLabels: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/rating.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/rating.ts new file mode 100644 index 000000000..1371653fe --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/rating.ts @@ -0,0 +1,54 @@ +import { css } from '@emotion/react'; +import type { RatingProps } from '../../../../components/Molecules/Rating'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Rating component +const ratingStyleScript = (props: RatingProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + return css({ + flexWrap: 'wrap', + gap: `${custom.spacing.x1}px`, + lineHeight: 1, + '.ss__rating__icons': { + '.ss__rating__stars': { + margin: '0 -1px', + '.ss__rating__stars__star': { + margin: '0 1px', + }, + }, + '.ss__rating__stars--empty': { + '.ss__rating__stars__star .ss__icon': { + fill: darkGray, + stroke: darkGray, + }, + }, + '.ss__rating__stars--full': { + '.ss__rating__stars__star .ss__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }, + '.ss__rating__count, .ss__rating__text': { + fontSize: custom.utils.convertPxToEm(12), + color: variables?.colors?.text, + }, + }); +}; + +// Rating component props +export const rating: ThemeComponent<'rating', RatingProps> = { + default: { + rating: { + themeStyleScript: ratingStyleScript, + emptyIcon: 'star', + fullIcon: 'star', + }, + 'rating icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/result.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/result.ts new file mode 100644 index 000000000..5a4071925 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/result.ts @@ -0,0 +1,123 @@ +import { css } from '@emotion/react'; +import type { ResultProps } from '../../../../components/Molecules/Result'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Result component +const resultStyleScript = (props: ResultProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + + return css({ + '&.ss__result--sale': { + '.ss__result__details': { + '.ss__result__details__pricing': { + '.ss__result__price:not(.ss__price--strike)': { + '&, span': { + color: variables?.colors?.primary, + }, + }, + }, + }, + }, + '&.ss__result--grid': { + display: 'block', + }, + '&.ss__result--list': { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + '.ss__result__image-wrapper, .ss__result__details': { + minWidth: '1px', + }, + '.ss__result__image-wrapper': { + flex: '0 0 33.33%', + margin: `0 ${custom.spacing.x4}px 0 0`, + }, + '.ss__result__details': { + flex: '1 1 0%', + textAlign: 'left', + margin: 0, + '.ss__callout-badge, .ss__result__rating-wrapper': { + justifyContent: 'flex-start', + }, + '.ss__result__details__title': { + flex: '1 1 0%', + a: { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + }, + }, + '.ss__result__details__pricing': { + flex: '0 1 auto', + order: -1, + }, + }, + }, + '.ss__result__image-wrapper': { + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + '.ss__result__details': { + padding: 0, + display: 'flex', + flexFlow: 'row wrap', + gap: `${custom.spacing.x2}px`, + '& > *, .ss__result__details__title, .ss__result__details__title, .ss__result__details__pricing': { + margin: 0, + }, + '& > *': { + minWidth: '1px', + flex: '1 1 100%', + }, + '.ss__result__details__title': { + order: -2, + a: { + color: variables?.colors?.text, + }, + }, + '.ss__result__details__pricing': { + '.ss__result__price': { + fontSize: custom.utils.convertPxToEm(16), + '&:not(.ss__price--strike)': { + fontWeight: custom.fonts.weight01, + }, + }, + '.ss__price--strike': { + fontSize: custom.utils.convertPxToEm(14), + '&, span': { + color: lightGray, + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '&.ss__result--list': { + display: 'block', + '.ss__result__details': { + textAlign: 'center', + '.ss__callout-badge, .ss__result__rating-wrapper': { + justifyContent: 'center', + }, + '.ss__result__details__title, .ss__result__details__pricing': { + flex: '1 1 100%', + }, + '.ss__result__details__pricing': { + order: 0, + }, + }, + '.ss__result__image-wrapper': { + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + }, + }, + }); +}; + +// Result component props +export const result: ThemeComponent<'result', ResultProps> = { + default: { + result: { + themeStyleScript: resultStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/searchInput.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/searchInput.ts new file mode 100644 index 000000000..8ae4ecfd1 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/searchInput.ts @@ -0,0 +1,91 @@ +import { css } from '@emotion/react'; +import type { SearchInputProps } from '../../../../components/Molecules/SearchInput'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the SearchInput component +const searchInputStyleScript = (props: SearchInputProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const darkPrimary = custom.utils.darkenColor(variables?.colors?.primary, 0.15); + + return css({ + '&.ss__search-input': { + margin: `0 0 ${custom.spacing.x2}px`, + border: 0, + height: '35px', + '& > *': { + minWidth: '1px', + }, + '.ss__search-input__input, .ss__search-input__icons, .ss__button': { + height: '100%', + lineHeight: 1, + }, + '.ss__search-input__icons, .ss__search-input__button--close-search-button': { + flex: '0 1 auto', + }, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '35px', + boxSizing: 'border-box', + justifyContent: 'center', + '&, &:hover': { + border: 0, + }, + '&, .ss__icon': { + padding: 0, + }, + '.ss__icon': { + fill: custom.colors.white, + stroke: custom.colors.white, + }, + }, + '.ss__search-input__input': { + flex: '1 1 0%', + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + padding: `0 ${custom.spacing.x2}px`, + minHeight: '1px', + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.text, + '&::-webkit-input-placeholder': { + color: lightGray, + }, + '&::-ms-input-placeholder': { + color: lightGray, + }, + '&::placeholder': { + color: lightGray, + }, + }, + '.ss__search-input__icons': { + gap: '1px', + margin: '0 0 0 -1px', + backgroundColor: darkPrimary, + }, + '.ss__search-input__button--close-search-button': { + margin: '0 -1px 0 0', + }, + }, + }); +}; + +// SearchInput component props +export const searchInput: ThemeComponent<'searchInput', SearchInputProps> = { + default: { + searchInput: { + themeStyleScript: searchInputStyleScript, + }, + 'searchInput icon': { + size: `${custom.sizes.icon14}px`, + }, + 'searchInput button.close-search icon': { + icon: custom.icons.arrowLeft, + }, + 'searchInput button.clear-search icon': { + icon: custom.icons.close, + }, + 'searchInput button.submit-search icon': { + icon: custom.icons.search, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/select.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/select.ts new file mode 100644 index 000000000..96d04d7a1 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/select.ts @@ -0,0 +1,149 @@ +import { css } from '@emotion/react'; +import type { SelectProps } from '../../../../components/Molecules/Select'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Select component +const selectStyleScript = (props: SelectProps) => { + const variables = props?.theme?.variables; + + // shared styles for select menus + const sharedStyles = css({ + border: `1px solid ${custom.colors.gray02}`, + color: variables?.colors?.text, + backgroundColor: custom.colors.gray01, + }); + + // default styles + const defaultStyles = css([ + { + display: 'block', + '.ss__dropdown': { + '.ss__dropdown__button .ss__button, .ss__dropdown__content .ss__select__select': { + ...sharedStyles, + }, + '.ss__dropdown__button': { + '.ss__button': { + display: 'flex', + padding: `0 ${custom.spacing.x2}px`, + textAlign: 'left', + '.ss__button__content': { + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__select__selection__icon': { + margin: 0, + }, + '.ss__select__selection': { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + fontWeight: 'normal', + }, + '.ss__select__dropdown__button__icon': { + transition: 'transform ease 0.5s', + }, + }, + }, + }, + '.ss__dropdown__content': { + marginTop: `${custom.spacing.x2}px`, + '.ss__select__select': { + padding: `${custom.spacing.x2}px`, + margin: 0, + '.ss__select__select__option': { + gap: `${custom.spacing.x2}px`, + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + color: 'inherit', + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + backgroundColor: 'transparent', + }, + }, + '.ss__select__select__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }, + }, + }, + '.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__button': { + '.ss__select__dropdown__button__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + }, + }, + ]); + + // native styles + const nativeStyles = css([ + sharedStyles, + { + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + padding: `0 ${custom.spacing.x2}px`, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__select__label, .ss__select__select': { + fontSize: custom.utils.convertPxToEm(14), + }, + '.ss__select__label': { + fontWeight: custom.fonts.weight01, + }, + '.ss__select__select': { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + backgroundColor: 'transparent', + border: 'none', + appearance: 'none', + color: 'inherit', + cursor: 'pointer', + '&[disabled]': { + cursor: 'not-allowed', + }, + '&::-ms-expand': { + display: 'none', + }, + }, + '.ss__select__dropdown__button__icon': { + width: `${custom.sizes.icon12}px`, + height: `${custom.sizes.icon12}px`, + }, + }, + ]); + + return props?.native ? nativeStyles : defaultStyles; +}; + +// Select component props +export const select: ThemeComponent<'select', SelectProps> = { + default: { + select: { + themeStyleScript: selectStyleScript, + iconOpen: custom.icons.arrowDown, + iconClose: custom.icons.arrowDown, + }, + 'select icon.open': { + size: `${custom.sizes.icon12}px`, + }, + 'select dropdown button': { + native: false, + }, + 'select dropdown button icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/slideout.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/slideout.ts new file mode 100644 index 000000000..ce31c4a0a --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/slideout.ts @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; +import type { SlideoutProps } from '../../../../components/Molecules/Slideout'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Slideout component +const slideoutStyleScript = (props: SlideoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({}); +}; + +// Slideout component props +export const slideout: ThemeComponent<'slideout', SlideoutProps> = { + default: { + slideout: { + themeStyleScript: slideoutStyleScript, + overlayColor: '', + }, + 'slideout button.slideout': { + icon: custom.icons.filter, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/swatches.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/swatches.ts new file mode 100644 index 000000000..2f58434d4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/swatches.ts @@ -0,0 +1,249 @@ +import { css } from '@emotion/react'; +import type { SwatchesProps } from '../../../../components/Molecules/Swatches'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// Swatch carousel sizes and spacing +const swatchSize = 30; +const swatchSpacing = custom.spacing.x1; + +// CSS in JS style script for the Swatches component +const swatchesStyleScript = (props: SwatchesProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const fontColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#d15120' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + // shared styles for swatches + const sharedStyles = css({ + margin: 0, + }); + + // carousel styles + const carouselStyles = css([ + sharedStyles, + { + margin: 0, + '.ss__carousel': { + '& > div': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + position: 'static', + bottom: 0, + width: `${swatchSize}px`, + height: `${swatchSize}px`, + }, + '.ss__carousel__prev-wrapper': { + margin: `0 ${swatchSpacing}px 0 0`, + }, + '.ss__carousel__next-wrapper': { + margin: `0 0 0 ${swatchSpacing}px`, + }, + '.swiper-container': { + maxWidth: `calc(100% - ${swatchSize * 2 + swatchSpacing * 2}px)`, + '& > .swiper-wrapper': { + '& > .swiper-slide': { + overflow: 'hidden', + width: `${swatchSize}px`, + height: `${swatchSize}px`, + '&:has(.ss__swatches__carousel__swatch.ss__swatches__carousel__swatch--unavailable)': { + '&:before': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + margin: 'auto', + width: '100%', + height: '1px', + borderTop: `3px solid ${darkGray}`, + transform: 'rotate(-45deg)', + }, + }, + }, + }, + }, + '.swiper-container > .swiper-wrapper > .swiper-slide > *, .ss__swatches__carousel__swatch': { + height: `${swatchSize}px`, + lineHeight: 0, + border: 0, + }, + '.ss__swatches__carousel__swatch': { + position: 'relative', + aspectRatio: 1, + color: variables?.colors?.text, + overflow: 'hidden', + '&, &:before, &:after, *': { + boxSizing: 'border-box', + }, + '&:before, &:after': { + content: '""', + display: 'block', + width: 'auto', + height: 'auto', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + transform: 'none', + }, + '&:before': { + border: `3px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&.ss__swatches__carousel__swatch--dark, &:has(.ss__swatches__carousel__swatch__inner--grey)': { + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + color: fontColor.hex(), + }, + }, + }, + '&.ss__swatches__carousel__swatch--selected': { + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + '&:has(.ss__swatches__carousel__swatch__inner:not([style]))': { + backgroundColor: activeColor.hex(), + '&:after': { + borderColor: activeColor.hex(), + opacity: 1, + }, + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + color: fontColor.hex(), + }, + }, + }, + '&:has(.ss__swatches__carousel__swatch__inner .ss__image)': { + backgroundColor: 'transparent', + '&:after': { + borderColor: custom.colors.black, + opacity: 0.3, + }, + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + color: variables?.colors?.text, + }, + }, + }, + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + '&.ss__swatches__carousel__swatch--disabled, &.ss__swatches__carousel__swatch--unavailable': { + opacity: 1, + cursor: 'not-allowed', + pointerEvents: 'none', + '.ss__swatches__carousel__swatch__inner:after': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 3, + margin: 'auto', + backgroundColor: darkGray.replace('#', ''), + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center center', + backgroundImage: `url("data:image/svg+xml,%3Csvg style=%27transform: rotate%28-45deg%29%27 xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 56 56%27 preserveAspectRatio=%27xMinYMid%27%3E%3Cpath fill=%27%23${darkGray.replace( + '#', + '' + )}%27 d=%27M0 23.297h56v9.406h-56v-9.406z%27 /%3E%3C/svg%3E")`, + }, + }, + '.ss__swatches__carousel__swatch__inner': { + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + '.ss__swatches__carousel__swatch__value': { + display: 'block', + position: 'absolute', + zIndex: 2, + maxWidth: `calc(100% - ${custom.spacing.x2}px)`, + maxHeight: `calc(100% - ${custom.spacing.x2}px)`, + overflow: 'hidden', + textAlign: 'center', + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1, + }, + }, + }, + }, + }, + ]); + + // grid styles + const gridStyles = css([ + sharedStyles, + { + '.ss__grid': { + '.ss__grid__options': { + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + width: `${swatchSize}px`, + maxHeight: `${swatchSize}px`, + }, + }, + }, + }, + ]); + + // return swatch styles + if (props?.type == 'grid') { + return gridStyles; + } else { + return carouselStyles; + } +}; + +// Swatches component props +export const swatches: ThemeComponent<'swatches', SwatchesProps> = { + default: { + swatches: { + themeStyleScript: swatchesStyleScript, + }, + 'swatches carousel': { + autoAdjustSlides: false, + centerInsufficientSlides: false, + slidesPerView: 'auto', + slidesPerGroup: 3, + spaceBetween: `${swatchSpacing}px`, + }, + }, + desktop: { + 'swatches carousel': { + slidesPerView: 'auto', + slidesPerGroup: 2, + spaceBetween: `${swatchSpacing}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/terms.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/terms.ts new file mode 100644 index 000000000..1edc387a2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/terms.ts @@ -0,0 +1,87 @@ +import { css } from '@emotion/react'; +import type { TermsProps } from '../../../../components/Molecules/Terms'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Terms component +const termsStyleScript = (props: TermsProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + return css({ + width: '100%', + textAlign: 'left', + 'ul, ul li': { + padding: 0, + margin: 0, + listStyle: 'none', + }, + '.ss__terms__title': { + '&, h5': { + padding: 0, + }, + h5: { + margin: `0 0 ${custom.spacing.x4}px 0`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + textTransform: custom.fonts.transform ? custom.fonts.transform : 'none', + color: variables?.colors?.secondary, + }, + }, + '.ss__terms__options': { + flexFlow: 'row wrap', + justifyContent: 'flex-start', + gap: `${custom.spacing.x1}px ${custom.spacing.x4}px`, + '&, .ss__terms__option': { + listStyle: 'none', + padding: 0, + }, + '.ss__terms__option': { + flex: '0 1 auto', + minWidth: '1px', + color: variables?.colors?.primary, + a: { + padding: 0, + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.primary, + em: { + color: variables?.colors?.text, + fontStyle: 'normal', + fontSize: 'inherit', + fontWeight: 'inherit', + }, + }, + }, + '.ss__terms__option--active': { + 'a, a em': { + fontWeight: custom?.fonts?.weight01, + color: variables?.colors?.primary, + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__terms__title': { + h5: { + fontSize: custom.utils.convertPxToEm(14), + }, + }, + '.ss__terms__options': { + '.ss__terms__option': { + a: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }); +}; + +// Terms component props +export const terms: ThemeComponent<'terms', TermsProps> = { + default: { + terms: { + themeStyleScript: termsStyleScript, + emIfy: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/molecules/variantSelection.ts b/packages/snap-preact/components/src/themes/everest/components/molecules/variantSelection.ts new file mode 100644 index 000000000..41509c306 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/molecules/variantSelection.ts @@ -0,0 +1,149 @@ +import { css } from '@emotion/react'; +import type { VariantSelectionProps } from '../../../../components/Molecules/VariantSelection'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Swatches component +const variantSelectionStyleScript = (props: VariantSelectionProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + + // shared styles for variant selections + const sharedStyles = css({ + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }); + + // dropdown styles + const dropdownStyles = css([ + sharedStyles, + { + '.ss__dropdown': { + '.ss__dropdown__button, .ss__dropdown__content': { + border: `1px solid ${custom.colors.gray02}`, + color: variables?.colors?.text, + backgroundColor: custom.colors.gray01, + }, + '.ss__dropdown__button': { + width: 'auto', + display: 'flex', + padding: `0 ${custom.spacing.x2}px`, + textAlign: 'left', + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__dropdown__button-wrapper': { + flex: '1 1 0%', + gap: `${custom.spacing.x1}px`, + paddingRight: `${custom.spacing.x1}px`, + fontWeight: 'normal', + '.ss__dropdown__button-wrapper__label': { + fontWeight: custom?.fonts?.weight01, + textTransform: 'capitalize', + }, + }, + '.ss__variant-selection__icon': { + transition: 'transform ease 0.5s', + }, + }, + '.ss__dropdown__content': { + marginTop: `-1px`, + padding: `${custom.spacing.x2}px`, + '.ss__variant-selection__options': { + '&, .ss__variant-selection__option': { + listStyle: 'none', + padding: 0, + margin: 0, + }, + '.ss__variant-selection__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + fontWeight: 'normal', + }, + }, + '.ss__variant-selection__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '.ss__variant-selection__option--unavailable': { + color: lightGray, + cursor: 'not-allowed', + }, + }, + }, + }, + '.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__variant-selection__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + }, + ]); + + // list styles + const listStyles = css([ + sharedStyles, + { + '.ss__list': { + '.ss__list__title, .ss__list__options, .ss__list__options .ss__list__option': { + width: '100%', + color: variables?.colors?.text, + }, + '.ss__list__title': { + textTransform: 'capitalize', + }, + '.ss__list__options': { + '.ss__list__option': { + label: { + color: 'inherit', + }, + }, + '.ss__list__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '.ss__list__option--unavailable': { + color: lightGray, + cursor: 'not-allowed', + textDecoration: 'line-through', + }, + }, + }, + }, + ]); + + // swatches syles + const swatchesStyles = css([sharedStyles]); + + // return variant selection styles + if (props?.type == 'list') { + return listStyles; + } else if (props?.type == 'swatches') { + return swatchesStyles; + } else { + return dropdownStyles; + } +}; + +// VariantSelection component props +export const variantSelection: ThemeComponent<'variantSelection', VariantSelectionProps> = { + default: { + variantSelection: { + themeStyleScript: variantSelectionStyleScript, + }, + 'variantSelection dropdown icon': { + size: `${custom.sizes.icon12}px`, + icon: custom.icons.arrowDown, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/autocomplete.ts new file mode 100644 index 000000000..a37374b5b --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/autocomplete.ts @@ -0,0 +1,392 @@ +import { css } from '@emotion/react'; +import type { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; + +// CSS in JS style script for the Autocomplete component +const autocompleteStyleScript = (props: AutocompleteProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const headerSelectors = + '.ss__autocomplete__terms .ss__autocomplete__title h5, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__header, .ss__autocomplete__content__results .ss__autocomplete__title h5, .ss__autocomplete__content__info a, .ss__no-results__recommendations h3'; + const activeSelectors = + '.ss__autocomplete__terms .ss__autocomplete__terms__options .ss__autocomplete__terms__option--active a, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__options .ss__facet-list-options .ss__facet-list-options__option--filtered, .ss__autocomplete__content__results .ss__results .ss__result:hover .ss__result__details .ss__result__details__title a, .ss__autocomplete__content__info a:hover'; + + return css({ + '&.ss__autocomplete': { + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.white, + width: props?.width, + right: 0, + left: 'auto', + top: 'auto', + margin: `${custom.spacing.x1}px 0 0 0`, + gap: `${custom.spacing.x4}px`, + 'a, div, p': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1.5, + color: variables?.colors?.text, + }, + a: { + display: 'block', + }, + '.ss__banner': { + img: { + maxWidth: '100%', + maxHeight: '150px', + height: 'auto', + }, + }, + [headerSelectors]: { + margin: `0 0 ${custom.spacing.x4}px 0`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + lineHeight: 1.2, + color: variables?.colors?.secondary, + }, + [activeSelectors]: { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '& > div': { + minWidth: '1px', + maxWidth: 'none', + flex: '0 1 auto', + padding: `${custom.spacing.x4}px 0`, + order: 0, + '&:first-of-type': { + paddingLeft: `${custom.spacing.x4}px`, + }, + '&:last-of-type': { + paddingRight: `${custom.spacing.x4}px`, + }, + '&.ss__autocomplete__terms': { + padding: 0, + }, + }, + '.ss__autocomplete__terms': { + width: '200px', + backgroundColor: custom.colors.gray01, + textAlign: 'left', + '& > div:first-of-type .ss__autocomplete__title': { + marginTop: `${custom.spacing.x2}px`, + }, + '& > div:last-of-type .ss__autocomplete__terms__options': { + marginBottom: `${custom.spacing.x2}px`, + }, + '& > div': { + '.ss__autocomplete__title': { + padding: 0, + h5: { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + }, + }, + '.ss__autocomplete__terms__options': { + '.ss__autocomplete__terms__option': { + a: { + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.primary, + em: { + color: variables?.colors?.text, + fontStyle: 'normal', + fontSize: 'inherit', + fontWeight: 'inherit', + }, + }, + }, + '.ss__autocomplete__terms__option--active': { + 'a, a em': { + fontWeight: custom?.fonts?.weight01, + color: variables?.colors?.primary, + }, + }, + }, + }, + }, + '.ss__autocomplete__facets': { + width: '200px', + textAlign: 'left', + '.ss__facets': { + '.ss__facet': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&.ss__facet--showing-all': { + '.ss__facet__options': { + maxHeight: 'none', + overflow: 'visible', + padding: 0, + }, + }, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__facet__header': { + borderBottom: 0, + padding: 0, + '.ss__facet__header__inner': { + fontSize: 'inherit', + fontWeight: 'inherit', + color: 'inherit', + }, + }, + '.ss__facet__options': { + margin: 0, + maxHeight: 'none', + overflow: 'visible', + '.ss__facet-hierarchy-options .ss__facet-hierarchy-options__option, .ss__facet-list-options .ss__facet-list-options__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__facet-list-options': { + '.ss__facet-list-options__option': {}, + }, + }, + }, + }, + }, + '.ss__autocomplete__content': { + flex: '1 1 0%', + overflow: 'visible', + justifyContent: 'flex-start', + }, + '.ss__autocomplete__content__results': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '.ss__results': { + overflowY: 'auto', + overflowX: 'hidden', + maxHeight: '75vh', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__result': { + '.ss__result__details': { + gap: `${custom.spacing.x1}px`, + '.ss__result__details__pricing': { + '.ss__result__price': { + fontSize: custom.utils.convertPxToEm(14), + }, + '.ss__price--strike': { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + '.ss__inline-banner': { + maxHeight: '250px', + overflow: 'hidden', + }, + }, + }, + '.ss__autocomplete__content__info': { + padding: 0, + a: { + margin: 0, + '.ss__icon': { + fill: 'currentColor', + stroke: 'currentColor', + }, + }, + }, + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + '.ss__no-results__recommendations': { + margin: `${custom.spacing.x4}px 0 0 0`, + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '&.ss__autocomplete': { + flexFlow: 'row wrap', + gap: 0, + width: props?.width, + left: 0, + right: 0, + [headerSelectors]: { + fontSize: custom.utils.convertPxToEm(14), + }, + '& > div': { + flex: '1 1 100%', + borderBottom: `1px solid ${custom.colors.gray02}`, + '&:last-of-type': { + borderBottomWidth: 0, + }, + '&, &.ss__autocomplete__terms': { + padding: `${custom.spacing.x4}px`, + }, + }, + '.ss__autocomplete__terms': { + backgroundColor: 'transparent', + display: 'flex', + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + width: 'auto', + '& > div': { + minWidth: '1px', + flex: '1 1 0%', + '&:first-of-type .ss__autocomplete__title': { + marginTop: 0, + }, + '&:last-of-type .ss__autocomplete__terms__options': { + marginBottom: 0, + }, + '.ss__autocomplete__title h5': { + padding: 0, + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__autocomplete__terms__options': { + gap: `${custom.spacing.x1}px ${custom.spacing.x4}px`, + flexFlow: 'row wrap', + justifyContent: 'flex-start', + '.ss__autocomplete__terms__option': { + flex: '0 1 auto', + a: { + padding: 0, + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }, + '.ss__autocomplete__terms > div .ss__autocomplete__terms__options, .ss__autocomplete__facets .ss__facets': { + display: 'flex', + }, + '.ss__autocomplete__terms > div .ss__autocomplete__terms__options, .ss__autocomplete__facets .ss__facets .ss__facet': { + minWidth: '1px', + }, + '.ss__autocomplete__facets': { + width: 'auto', + '.ss__facets': { + gap: `0 ${custom.spacing.x4}px`, + flexFlow: 'row nowrap', + '.ss__facet': { + flex: '1 1 0%', + '&, &:last-of-type': { + margin: 0, + }, + }, + }, + }, + '.ss__autocomplete__content__info': { + a: { + '.ss__icon': { + position: 'relative', + top: '1px', + }, + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '&.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__recommendation-grid__results': { + gridTemplateColumns: `repeat(2, 1fr)`, + '& > div:nth-of-type(n+3)': { + display: 'none', + }, + }, + }, + }, + }); +}; + +// Autocomplete component props +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + themeStyleScript: autocompleteStyleScript, + width: '900px', + }, + 'autocomplete facet': { + limit: 5, + disableOverflow: true, + disableCollapse: true, + }, + 'autocomplete facets': { + limit: 3, + }, + 'autocomplete facetListOptions': { + hideCheckbox: true, + }, + 'autocomplete facetPaletteOptions': { + gridSize: '38px', + hideLabel: false, + }, + 'autocomplete facetGridOptions': { + gridSize: '38px', + }, + 'autocomplete results': { + rows: 2, + columns: 3, + }, + 'autocomplete recommendationGrid': { + rows: 2, + columns: 4, + }, + 'autocomplete icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteThemeComponentProps.mobile, + autocomplete: { + width: '100%', + }, + 'autocomplete results': { + rows: 1, + columns: 3, + }, + 'autocomplete recommendationGrid': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteThemeComponentProps.tablet, + autocomplete: { + width: '100%', + }, + 'autocomplete results': { + rows: 1, + columns: 4, + }, + 'autocomplete recommendationGrid': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteThemeComponentProps.desktop, + autocomplete: {}, + 'autocomplete results': { + rows: 2, + columns: 3, + }, + 'autocomplete recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/autocompleteLayout.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/autocompleteLayout.ts new file mode 100644 index 000000000..c45578d69 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/autocompleteLayout.ts @@ -0,0 +1,451 @@ +import { css } from '@emotion/react'; +import type { AutocompleteLayoutProps } from '../../../../components/Organisms/AutocompleteLayout'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Autocomplete Layout component +const autocompleteLayoutStyleScript = (props: AutocompleteLayoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const textSelectors = 'a, div, p'; + const headerSelectors = + '.ss__terms-list .ss__terms .ss__terms__title h5, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__header, .ss__autocomplete__content .ss__autocomplete__content__results .ss__autocomplete__title h5, .ss__autocomplete__button--see-more .ss__button__content, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__title'; + const activeSelectors = + '.ss__terms-list .ss__terms .ss__terms__options .ss__terms__option.ss__terms__option--active a, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__options .ss__facet-list-options .ss__facet-list-options__option--filtered, .ss__autocomplete__content .ss__autocomplete__content__results .ss__results .ss__result:hover .ss__result__details .ss__result__details__title a, .ss__autocomplete__button--see-more:hover .ss__button__content'; + + // get autocomplete layout + const acLayout = props?.layout ? props.layout : 'standard'; + + // shared autocomplete styles + const sharedStyles = css({ + alignContent: acLayout == 'standard' ? 'normal' : 'flex-start', + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.white, + [textSelectors]: { + fontSize: custom.utils.convertPxToEm(acLayout == 'terms' ? 15 : 12), + lineHeight: 1.5, + color: variables?.colors?.text, + }, + a: { + display: 'block', + }, + 'ul, ul li': { + padding: 0, + margin: 0, + listStyle: 'none', + }, + '.ss__banner': { + img: { + maxWidth: '100%', + maxHeight: '150px', + height: 'auto', + }, + }, + [headerSelectors]: { + margin: `0 0 ${custom.spacing.x4}px 0`, + padding: 0, + fontSize: custom.utils.convertPxToEm(acLayout == 'terms' ? 17 : 16), + fontWeight: custom.fonts.weight02, + lineHeight: 1.2, + color: variables?.colors?.secondary, + }, + [activeSelectors]: { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '.ss__autocomplete__row, .ss__autocomplete__column': { + '.ss__search-input': { + background: 'transparent', + width: 'auto', + height: '30px', + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + }, + '.ss__autocomplete__column': { + alignContent: 'flex-start', + minWidth: '1px', + }, + }); + const sharedTabletStyles = css({ + alignContent: 'flex-start', + [textSelectors]: { + fontSize: acLayout == 'terms' ? custom.utils.convertPxToEm(12) : '', + }, + [headerSelectors]: { + fontSize: custom.utils.convertPxToEm(14), + }, + }); + + // terms wrapper styles + const termsWrapperStyles = css({ + '.ss__autocomplete__terms-wrapper': { + backgroundColor: 'transparent', + padding: `${custom.spacing.x4}px`, + }, + }); + + // facets styles + const facetsStyles = css({ + '.ss__autocomplete__facets-wrapper': { + padding: `${custom.spacing.x4}px`, + }, + '.ss__autocomplete__facets': { + padding: 0, + '.ss__facets': { + '.ss__facet': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + '&.ss__facet--showing-all': { + '.ss__facet__options': { + maxHeight: 'none', + overflow: 'visible', + padding: 0, + }, + }, + '.ss__facet__header': { + borderBottom: 0, + '.ss__facet__header__inner': { + fontSize: 'inherit', + fontWeight: 'inherit', + color: 'inherit', + }, + }, + '.ss__facet__options': { + '.ss__facet-hierarchy-options .ss__facet-hierarchy-options__option, .ss__facet-list-options .ss__facet-list-options__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + }, + }, + }, + }); + + // content styles + const contentStyles = css({ + '.ss__autocomplete__column:has(.ss__autocomplete__content)': { + alignContent: 'flex-start', + }, + '.ss__autocomplete__content': { + overflow: 'visible', + justifyContent: 'flex-start', + padding: `${custom.spacing.x4}px`, + borderTop: `1px solid ${custom.colors.gray02}`, + '.ss__autocomplete__content-inner': { + padding: 0, + }, + }, + }); + + // results layout styles + const resultsLayoutStyles = css({ + gap: `${custom.spacing.x4}px`, + overflowY: 'auto', + overflowX: 'hidden', + maxHeight: '75vh', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__result': { + '.ss__result__details': { + gap: `${custom.spacing.x1}px`, + '.ss__result__details__pricing': { + '.ss__result__price': { + fontSize: custom.utils.convertPxToEm(14), + }, + '.ss__price--strike': { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }); + + // results styles + const resultsStyles = css({ + '.ss__autocomplete__content__results': { + '.ss__results': { + ...resultsLayoutStyles, + }, + }, + }); + + // no results styles + const noResultsStyles = css({ + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + '.ss__autocomplete__content__no-results__recommendations': { + '.ss__recommendation-grid': { + margin: `${custom.spacing.x4}px 0 0 0`, + }, + '.ss__recommendation-grid__title': { + textAlign: 'left', + }, + '.ss__recommendation-grid__results': { + ...resultsLayoutStyles, + }, + }, + }, + }); + + // see more styles + const seeMoreStyles = css({ + '.ss__autocomplete__button--see-more': { + padding: `${custom.spacing.x4}px`, + paddingTop: 0, + height: 'auto', + '&, &:hover': { + backgroundColor: 'transparent', + border: 0, + }, + '.ss__button__content': { + margin: 0, + '.ss__icon': { + position: 'relative', + top: '0.5px', + margin: `0 0 0 ${custom.spacing.x1}px`, + }, + }, + }, + }); + const seeMoreTabletStyles = css({ + order: -1, + textAlign: 'left', + '.ss__button__content': { + '.ss__icon': { + top: '1.5px', + }, + }, + }); + + // standard styles + const standardStyles = css([ + sharedStyles, + { + '.ss__autocomplete__column': { + '&:has(.ss__autocomplete__terms-wrapper)': { + flex: '1 0 200px', + maxWidth: '200px', + }, + '&:has(.ss__autocomplete__facets-wrapper)': { + flex: '1 0 200px', + maxWidth: '200px', + marginRight: `-${custom.spacing.x4}px`, + }, + }, + '.ss__autocomplete__terms-wrapper': { + backgroundColor: custom.colors.gray01, + height: '100%', + }, + '.ss__terms-list': { + display: 'block', + '.ss__terms-list__row': { + '&:first-of-type .ss__terms .ss__terms__title': { + marginTop: `${custom.spacing.x2}px`, + }, + '&:last-of-type .ss__terms .ss__terms__options': { + marginBottom: `${custom.spacing.x2}px`, + }, + }, + '.ss__terms': { + '.ss__terms__title': { + h5: { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + }, + }, + '.ss__terms__options': { + display: 'block', + margin: 0, + '.ss__terms__option': { + a: { + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + }, + }, + '.ss__terms__option--active': { + backgroundColor: custom.colors.white, + }, + }, + }, + }, + }, + facetsStyles, + contentStyles, + resultsStyles, + noResultsStyles, + seeMoreStyles, + { + [`@media (max-width: ${tabletBp}px)`]: { + '&': sharedTabletStyles, + '.ss__autocomplete__row:has(.ss__autocomplete__column)': { + display: 'block', + '.ss__autocomplete__column': { + width: '100%', + maxWidth: 'none', + }, + }, + '.ss__autocomplete__column': { + '&:has(.ss__autocomplete__facets-wrapper)': { + marginRight: 0, + }, + }, + '.ss__autocomplete__terms-wrapper': { + backgroundColor: 'transparent', + padding: `${custom.spacing.x4}px`, + }, + '.ss__terms-list': { + display: 'flex', + '.ss__terms-list__row': { + '&:first-of-type .ss__terms .ss__terms__title': { + marginTop: 0, + }, + '&:last-of-type .ss__terms .ss__terms__options': { + marginBottom: 0, + }, + }, + '.ss__terms': { + '.ss__terms__title': { + h5: { + padding: 0, + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + }, + '.ss__terms__options': { + display: 'flex', + '.ss__terms__option': { + a: { + padding: 0, + }, + }, + }, + }, + }, + '.ss__autocomplete__facets-wrapper': { + borderTop: `1px solid ${custom.colors.gray02}`, + }, + '.ss__autocomplete__facets': { + '.ss__facets': { + gap: `0 ${custom.spacing.x4}px`, + flexFlow: 'row nowrap', + minWidth: '1px', + '.ss__facet': { + flex: '1 1 0%', + minWidth: '1px', + '&, &:last-of-type': { + margin: 0, + }, + }, + }, + }, + '.ss__autocomplete__button--see-more': { + ...seeMoreTabletStyles, + }, + }, + }, + ]); + + // mini styles + const miniStyles = css([ + sharedStyles, + termsWrapperStyles, + contentStyles, + resultsStyles, + noResultsStyles, + seeMoreStyles, + { + [`@media (max-width: ${tabletBp}px)`]: { + '&': sharedTabletStyles, + '.ss__autocomplete__button--see-more': { + ...seeMoreTabletStyles, + }, + }, + }, + { + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + gridTemplateColumns: `repeat(2, 1fr)`, + }, + }, + }, + ]); + + // terms styles + const termsStyles = css([ + sharedStyles, + termsWrapperStyles, + contentStyles, + { + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + fontSize: custom.utils.convertPxToEm(14), + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + }, + }, + seeMoreStyles, + { + [`@media (max-width: ${tabletBp}px)`]: { + '&': sharedTabletStyles, + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + '.ss__autocomplete__button--see-more': { + ...seeMoreTabletStyles, + }, + }, + }, + ]); + + // return autocomplete styles + if (acLayout == 'terms') { + return termsStyles; + } else if (acLayout == 'mini') { + return miniStyles; + } else { + return standardStyles; + } +}; + +// Autocomplete Layout component props +export const autocompleteLayout: ThemeComponent<'autocompleteLayout', AutocompleteLayoutProps> = { + default: { + autocompleteLayout: { + themeStyleScript: autocompleteLayoutStyleScript, + contentTitle: 'Product Suggestions', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/facet.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/facet.ts new file mode 100644 index 000000000..3108a816a --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/facet.ts @@ -0,0 +1,80 @@ +import { css } from '@emotion/react'; +import type { FacetProps } from '../../../../components/Organisms/Facet'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Facet component +const facetStyleScript = (props: FacetProps) => { + const variables = props?.theme?.variables; + + return css({ + '&.ss__facet--collapsed': { + '.ss__facet__header': { + '.ss__icon': { + transform: 'rotate(0deg)', + }, + }, + }, + '&.ss__facet--showing-all': { + '.ss__facet__options': { + maxHeight: `490px`, + overflowY: 'auto', + overflowX: 'hidden', + paddingRight: `${custom.spacing.x2}px`, + }, + }, + '.ss__facet__header': { + gap: `${custom.spacing.x2}px`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + '.ss__icon': { + transition: 'transform ease 0.5s', + transform: 'rotate(180deg)', + width: `${custom.sizes.icon12}px`, + height: `${custom.sizes.icon12}px`, + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + '.ss__facet__options': { + marginTop: 0, + maxHeight: 'none', + overflow: 'visible', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + }, + '.ss__facet__show-more-less': { + margin: `${custom.spacing.x2}px 0 0 0`, + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '.ss__icon': { + position: 'relative', + top: '-0.5px', + marginRight: `${custom.spacing.x1}px`, + width: `${custom.sizes.icon10}px`, + height: `${custom.sizes.icon10}px`, + }, + }, + }); +}; + +// Facet component props +export const facet: ThemeComponent<'facet', FacetProps> = { + default: { + facet: { + themeStyleScript: facetStyleScript, + iconCollapse: custom.icons.arrowDown, + iconExpand: custom.icons.arrowDown, + iconOverflowMore: custom.icons.plus, + iconOverflowLess: custom.icons.minus, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/facets.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/facets.ts new file mode 100644 index 000000000..ff933eb03 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/facets.ts @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; +import type { FacetsProps } from '../../../../components/Organisms/Facets'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Facets component +const facetsStyleScript = (props: FacetsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '&.ss__facets': { + display: 'block', + width: 'auto', + }, + }); +}; + +// Facets component props +export const facets: ThemeComponent<'facets', FacetsProps> = { + default: { + facets: { + themeStyleScript: facetsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/facetsHorizontal.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/facetsHorizontal.ts new file mode 100644 index 000000000..ea6f24945 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/facetsHorizontal.ts @@ -0,0 +1,239 @@ +import { css } from '@emotion/react'; +import type { FacetsHorizontalProps } from '../../../../components/Organisms/FacetsHorizontal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Facets component +const facetsHorizontalStyleScript = (props: FacetsHorizontalProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const columnsSelector = `.ss__facet-hierarchy-options, .ss__facet-list-options, .ss__facet-palette-options.ss__facet-palette-options--list`; + + return css({ + margin: 0, + '.ss__facets-horizontal__header': { + gap: 0, + margin: `0 -${custom.spacing.x1}px -${custom.spacing.x2}px -${custom.spacing.x1}px `, + position: 'relative', + '& > *': { + boxSizing: 'border-box', + minWidth: '1px', + width: `${100 / 6}%`, + flex: '0 1 auto', + padding: `0 ${custom.spacing.x1}px`, + }, + '& > *, .ss__facets-horizontal__header__dropdown, .ss__mobile-sidebar': { + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + '.ss__facets-horizontal__header__dropdown': { + position: 'static', + '&.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__dropdown__button__heading': { + '.ss__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + '.ss__dropdown__content': { + width: 'auto', + minWidth: '1px', + maxHeight: 'none', + overflowY: 'visible', + padding: `${custom.spacing.x2}px`, + marginTop: `${custom.spacing.x2}px`, + left: `${custom.spacing.x1}px`, + right: `${custom.spacing.x1}px`, + }, + }, + '.ss__dropdown__button, .ss__dropdown__content': { + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + }, + '.ss__dropdown__button': { + display: 'block', + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + padding: `0 ${custom.spacing.x2}px`, + textAlign: 'left', + color: variables?.colors?.text, + '.ss__dropdown__button__heading': { + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + gap: `${custom.spacing.x1}px`, + padding: 0, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + span: { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + fontWeight: custom.fonts.weight01, + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + '.ss__icon': { + transition: 'transform ease 0.5s', + }, + }, + }, + '.ss__dropdown__content': { + width: 'auto', + padding: `${custom.spacing.x2}px`, + [columnsSelector]: { + display: 'flex', + flexFlow: 'row wrap', + gap: `0 ${custom.spacing.x2}px`, + '& > *': { + flex: '0 1 auto', + width: `${100 / 4 - 2}%`, + minWidth: '1px', + boxSizing: 'border-box', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + }, + '.ss__checkbox, .ss__radio, .ss__search-input .ss__search-input__input': { + backgroundColor: custom.colors.white, + }, + '.ss__facet': { + margin: 0, + }, + '.ss__facet.ss__facet--showing-all .ss__facet__options': { + maxHeight: '360px', + }, + '.ss__facet-list-options': { + marginBottom: `-${custom.spacing.x1}px`, + '.ss__facet-list-options__option:last-of-type': { + marginBottom: `${custom.spacing.x1}px`, + }, + }, + '.ss__facet-hierarchy-options': { + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--filtered': { + '& ~ .ss__facet-hierarchy-options__option:not(.ss__facet-hierarchy-options__option--filtered)': { + paddingLeft: 0, + }, + }, + }, + '.ss__facet-grid-options': { + '.ss__facet-grid-options__option:not(.ss__facet-grid-options__option--filtered)': { + '&:after': { + backgroundColor: custom.colors.white, + }, + }, + }, + '.ss__facet--slider': { + '.ss__facet__options': { + display: 'flex', + minHeight: '100px', + '.ss__facet-slider': { + width: '100%', + }, + }, + }, + '.ss__facet__show-more-less': { + textAlign: 'center', + }, + }, + }, + '.ss__mobile-sidebar': { + '.ss__slideout__button .ss__button': { + display: 'flex', + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__facets-horizontal__header': { + '& > *': { + width: `${100 / 4}%`, + }, + '.ss__facets-horizontal__header__dropdown .ss__dropdown__content': { + [columnsSelector]: { + '& > *': { + width: `${100 / 3 - 2}%`, + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__facets-horizontal__header': { + '& > *': { + width: `${100 / 2}%`, + }, + '.ss__facets-horizontal__header__dropdown .ss__dropdown__content': { + [columnsSelector]: { + '& > *': { + width: `${100 / 2 - 2}%`, + }, + }, + }, + }, + }, + }); +}; + +// FacetsHorizontal component props +export const facetsHorizontal: ThemeComponent<'facetsHorizontal', FacetsHorizontalProps> = { + default: { + facetsHorizontal: { + themeStyleScript: facetsHorizontalStyleScript, + iconExpand: custom.icons.arrowDown, + iconCollapse: custom.icons.arrowDown, + alwaysShowFiltersButton: true, + }, + 'facetsHorizontal dropdown button icon': { + size: `${custom.sizes.icon12}px`, + }, + 'facetsHorizontal dropdown facet': { + statefulOverflow: true, + display: { + list: { + limit: 32, + }, + hierarchy: { + limit: 32, + }, + grid: { + limit: 34, + }, + palette: { + limit: 34, + }, + }, + }, + 'facetsHorizontal mobileSidebar facet': { + statefulOverflow: true, + display: { + list: { + limit: 10, + }, + hierarchy: { + limit: 10, + }, + grid: { + limit: 12, + }, + palette: { + limit: 12, + }, + }, + }, + 'facetsHorizontal facetGridOptions': { + gridSize: '62px', + }, + 'facetsHorizontal mobileSidebar facetGridOptions': { + gridSize: '52px', + }, + 'facetsHorizontal facetPaletteOptions': { + gridSize: '62px', + }, + 'facetsHorizontal mobileSidebar facetPaletteOptions': { + gridSize: '52px', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/filterSummary.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/filterSummary.ts new file mode 100644 index 000000000..7c60576c1 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/filterSummary.ts @@ -0,0 +1,90 @@ +import { css } from '@emotion/react'; +import type { FilterSummaryProps } from '../../../../components/Organisms/FilterSummary'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FilterSummary component +const filterSummaryStyleScript = (props: FilterSummaryProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + const listSpacing = custom.sizes.icon16 + custom.spacing.x2; + + // shared palette styles + const sharedStyles = css({ + '.ss__filter-summary__title': { + padding: 0, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__filter-summary__filters': { + margin: 0, + }, + }); + + // inline filter summary styles + const inlineStyles = css([ + sharedStyles, + { + '&.ss__filter-summary--inline': { + '.ss__filter-summary__filters': { + gap: `${custom.spacing.x1}px`, + }, + }, + }, + ]); + + // list filter summary styles + const listStyles = css([ + sharedStyles, + { + '&.ss__filter-summary--list': { + '.ss__filter-summary__filters': { + '.ss__filter': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__filter__button': { + '.ss__button__content': { + position: 'relative', + padding: `0 0 0 ${listSpacing}px`, + '.ss__filter__button__icon': { + position: 'absolute', + top: '1.5px', + left: 0, + padding: '3px', + backgroundColor: custom.colors.gray01, + border: `1px solid ${darkGray}`, + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + boxSizing: 'border-box', + }, + '.ss__filter__label, .ss__filter__value': { + margin: 0, + }, + '.ss__filter__label': { + padding: '0 4px 0 0', + }, + }, + }, + }, + }, + }, + }, + ]); + + return props?.type == 'list' ? listStyles : inlineStyles; +}; + +// FilterSummary component props +export const filterSummary: ThemeComponent<'filterSummary', FilterSummaryProps> = { + default: { + filterSummary: { + themeStyleScript: filterSummaryStyleScript, + clearAllIcon: custom.icons.close, + filterIcon: custom.icons.close, + hideTitle: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/index.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/index.ts new file mode 100644 index 000000000..11cfc74d3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/index.ts @@ -0,0 +1,74 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// ORGANISMS Imports +import { autocomplete } from './autocomplete'; +import { autocompleteLayout } from './autocompleteLayout'; +import { facet } from './facet'; +import { facets } from './facets'; +import { facetsHorizontal } from './facetsHorizontal'; +import { filterSummary } from './filterSummary'; +import { mobileSidebar } from './mobileSidebar'; +import { noResults } from './noResults'; +import { results } from './results'; +import { sidebar } from './sidebar'; +import { termsList } from './termsList'; +import { toolbar } from './toolbar'; + +export const organisms: ThemeResponsiveComplete = { + default: { + ...autocomplete.default, + ...autocompleteLayout.default, + ...facet.default, + ...facets.default, + ...facetsHorizontal.default, + ...filterSummary.default, + ...mobileSidebar.default, + ...noResults.default, + ...results.default, + ...sidebar.default, + ...toolbar.default, + ...termsList.default, + }, + mobile: { + ...autocomplete.mobile, + ...autocompleteLayout.mobile, + ...facet.mobile, + ...facets.mobile, + ...facetsHorizontal.mobile, + ...filterSummary.mobile, + ...mobileSidebar.mobile, + ...noResults.mobile, + ...results.mobile, + ...sidebar.mobile, + ...toolbar.mobile, + ...termsList.mobile, + }, + tablet: { + ...autocomplete.tablet, + ...autocompleteLayout.tablet, + ...facet.tablet, + ...facets.tablet, + ...facetsHorizontal.tablet, + ...filterSummary.tablet, + ...mobileSidebar.tablet, + ...noResults.tablet, + ...results.tablet, + ...sidebar.tablet, + ...toolbar.tablet, + ...termsList.tablet, + }, + desktop: { + ...autocomplete.desktop, + ...autocompleteLayout.desktop, + ...facet.desktop, + ...facets.desktop, + ...facetsHorizontal.desktop, + ...filterSummary.desktop, + ...mobileSidebar.desktop, + ...noResults.desktop, + ...results.desktop, + ...sidebar.desktop, + ...toolbar.desktop, + ...termsList.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/mobileSidebar.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/mobileSidebar.ts new file mode 100644 index 000000000..5ffe75c68 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/mobileSidebar.ts @@ -0,0 +1,130 @@ +import { css } from '@emotion/react'; +import type { MobileSidebarProps } from '../../../../components/Organisms/MobileSidebar'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the MobileSidebar component +const mobileSidebarStyleScript = (props: MobileSidebarProps) => { + const variables = props?.theme?.variables; + const headerHeight = 60; + const footerHeight = 75; + + return css({ + '.ss__mobile-sidebar__slideout': { + overflowY: 'hidden', + padding: 0, + width: '100%', + '.ss__mobile-sidebar__content': { + height: '100%', + '.ss__mobile-sidebar__header, .ss__mobile-sidebar__footer': { + padding: `0 ${custom.spacing.x4}px`, + gap: `${custom.spacing.x2}px`, + alignItems: 'center', + }, + '.ss__mobile-sidebar__header': { + height: `${headerHeight}px`, + backgroundColor: variables?.colors?.primary, + color: custom.colors.white, + '.ss__mobile-sidebar__header__title': { + margin: 0, + fontSize: custom.utils.convertPxToEm(18), + }, + '.ss__mobile-sidebar__header__close-button': { + padding: 0, + width: '16px', + height: '16px', + lineHeight: '16px', + '.ss__icon': { + width: '100%', + height: '100%', + lineHeight: 1, + }, + }, + }, + '.ss__mobile-sidebar__footer': { + height: `${footerHeight}px`, + backgroundColor: custom.colors.white, + borderTop: `1px solid ${custom.colors.gray02}`, + '.ss__button': { + flex: `1 1 0%`, + }, + }, + '.ss__mobile-sidebar__inner': { + height: `calc(100% - ${headerHeight + footerHeight}px)`, + overflowY: 'auto', + overflowX: 'hidden', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__layout': { + overflow: 'hidden', + display: 'block', + '& > *': { + borderBottom: `1px solid ${custom.colors.gray02}`, + padding: `${custom.spacing.x4}px`, + '&:last-of-type': { + borderBottomWidth: 0, + }, + }, + }, + '.ss__select--native': { + padding: `0 ${custom.spacing.x4}px`, + borderTop: 0, + height: '40px', + lineHeight: '40px', + }, + '.ss__filter-summary, .ss__facets': { + padding: 0, + }, + '.ss__filter-summary .ss__filter-summary__title, .ss__facets .ss__facet .ss__facet__header': { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: 0, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.text, + }, + '.ss__filter-summary .ss__filter-summary__filters, .ss__facets .ss__facet .ss__dropdown__content': { + padding: `${custom.spacing.x4}px`, + }, + '.ss__facets .ss__facet': { + margin: 0, + width: 'auto', + '&.ss__facet--collapsed': { + borderBottom: `1px solid ${custom.colors.gray02}`, + }, + '.ss__facet__header': { + '.ss__icon': { + fill: 'currentColor', + stroke: 'currentColor', + }, + }, + }, + }, + }, + }, + }); +}; + +// MobileSidebar component props +export const mobileSidebar: ThemeComponent<'mobileSidebar', MobileSidebarProps> = { + default: { + mobileSidebar: { + themeStyleScript: mobileSidebarStyleScript, + }, + 'mobileSidebar button.close': { + icon: custom.icons.close, + }, + 'mobileSidebar toolbar filterSummary': { + title: 'Current Filters', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/noResults.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/noResults.ts new file mode 100644 index 000000000..c7a685676 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/noResults.ts @@ -0,0 +1,61 @@ +import { css } from '@emotion/react'; +import type { NoResultsProps } from '../../../../components/Organisms/NoResults'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the NoResults component +const noResultsStyleScript = (props: NoResultsProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + 'h1, h2, h3, h4, h5, h6, ul': { + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + 'h1, h2, h3, h4, h5, h6, .ss__no-results__recommendations .ss__recommendation .ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(20), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + 'ul li, p': { + color: variables?.colors?.text, + }, + a: { + color: variables?.colors?.primary, + '&:hover': { + color: variables?.colors?.secondary, + }, + }, + ul: { + padding: 0, + marginLeft: `${custom.spacing.x8}px`, + listStyle: 'none', + li: { + listStyle: 'disc', + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + '.ss__no-results__recommendations': { + '.ss__recommendation': { + margin: `${custom.spacing.x4}px 0`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + 'h1, h2, h3, h4, h5, h6, .ss__no-results__recommendations .ss__recommendation .ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(18), + }, + }, + }); +}; + +// NoResults component props +export const noResults: ThemeComponent<'noResults', NoResultsProps> = { + default: { + noResults: { + themeStyleScript: noResultsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/results.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/results.ts new file mode 100644 index 000000000..fabe87ac2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/results.ts @@ -0,0 +1,39 @@ +import { css } from '@emotion/react'; +import type { ResultsProps } from '../../../../components/Organisms/Results'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Results component +const resultsStyleScript = (props: ResultsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '& > *': { + minWidth: '1px', + }, + }); +}; + +// Results component props +export const results: ThemeComponent<'results', ResultsProps> = { + default: { + results: { + themeStyleScript: resultsStyleScript, + gapSize: `${custom.spacing.x6}px ${custom.spacing.x4}px`, + columns: 4, + }, + }, + mobile: { + results: { + gapSize: `${custom.spacing.x6}px ${custom.spacing.x2}px`, + columns: 2, + }, + }, + tablet: { + results: { + columns: 3, + }, + }, + desktop: {}, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/sidebar.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/sidebar.ts new file mode 100644 index 000000000..60ef58fa2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/sidebar.ts @@ -0,0 +1,57 @@ +import { css } from '@emotion/react'; +import type { SidebarProps } from '../../../../components/Organisms/Sidebar'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Sidebar component +const sidebarStyleScript = (props: SidebarProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__sidebar__title': { + margin: `0 0 ${custom.spacing.x6}px 0`, + fontSize: custom.utils.convertPxToEm(20), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__sidebar__inner': { + '.ss__layout': { + '&, .ss__layout__row': { + display: 'block', + }, + '.ss__layout__row': { + minWidth: '1px', + '& > div:only-child': { + width: 'auto', + }, + }, + }, + '.ss__layout .ss__layout__row, .ss__facets .ss__facet': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__filter-summary .ss__filter-summary__title, .ss__facets .ss__facet .ss__facet__header': { + margin: ` 0 0 ${custom.spacing.x4}px 0`, + padding: ` 0 0 ${custom.spacing.x2}px 0`, + borderBottom: `2px solid ${variables?.colors?.primary}`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + }, + }); +}; + +// Sidebar component props +export const sidebar: ThemeComponent<'sidebar', SidebarProps> = { + default: { + sidebar: { + themeStyleScript: sidebarStyleScript, + }, + 'sidebar toolbar filterSummary': { + title: 'Current Filters', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/termsList.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/termsList.ts new file mode 100644 index 000000000..82e5dcc2c --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/termsList.ts @@ -0,0 +1,29 @@ +import { css } from '@emotion/react'; +import type { TermsListProps } from '../../../../components/Organisms/TermsList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the TermsList component +const termsListStyleScript = (props: TermsListProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + backgroundColor: 'transparent', + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + '.ss__terms-list-row': { + flex: '1 1 0%', + minWidth: '1px', + }, + }); +}; + +// TermsList component props +export const termsList: ThemeComponent<'termsList', TermsListProps> = { + default: { + termsList: { + themeStyleScript: termsListStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/organisms/toolbar.ts b/packages/snap-preact/components/src/themes/everest/components/organisms/toolbar.ts new file mode 100644 index 000000000..8370fe5ee --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/organisms/toolbar.ts @@ -0,0 +1,73 @@ +import { css } from '@emotion/react'; +import { ThemeComponent } from '../../../../providers'; +import { ToolbarProps } from '../../../../components/Organisms/Toolbar'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Toolbar component +const toolbarStyleScript = (props: ToolbarProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '.ss__layout': { + gap: `${custom.spacing.x2}px`, + margin: 0, + }, + '&[class*="bottom"]': { + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(14), + }, + }, + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(16), + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(18), + }, + }, + '& > .ss__layout > .ss__layout__row > .ss__filter-summary': { + display: 'flex', + flexFlow: 'row wrap', + '.ss__filter-summary__title, .ss__filter-summary__filters': { + minWidth: '1px', + }, + '.ss__filter-summary__title': { + flex: '0 1 auto', + padding: `0 ${custom.spacing.x2}px 0 0`, + }, + '.ss__filter-summary__filters': { + flex: '1 1 0%', + }, + '&.ss__filter-summary--inline': { + '.ss__filter-summary__title': { + paddingTop: `${custom.spacing.x1}px`, + paddingBottom: `${custom.spacing.x1}px`, + }, + }, + '&.ss__filter-summary--list': { + '.ss__filter-summary__filters': { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + gap: `${custom.spacing.x2}px`, + '.ss__filter': { + margin: 0, + }, + }, + }, + }, + }); +}; + +// Toolbar component props +export const toolbar: ThemeComponent<'toolbar', ToolbarProps> = { + default: { + toolbar: { + themeStyleScript: toolbarStyleScript, + }, + 'toolbar filterSummary': { + title: `Current Filters:`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteFixed.ts b/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteFixed.ts new file mode 100644 index 000000000..7e1248d02 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteFixed.ts @@ -0,0 +1,187 @@ +import { css } from '@emotion/react'; +import { autocompleteFixedThemeComponentProps } from '../../../themeComponents/autocompleteFixed'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteFixedProps } from '../../../../components/Templates/AutocompleteFixed'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const autocompleteFixedStyleScript = (props: AutocompleteFixedProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + return css({ + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '& > .ss__search-input.autocomplete-fixed__search-input': { + height: '40px', + margin: `0 0 ${custom.spacing.x2}px 0`, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '40px', + }, + }, + '.ss__autocomplete-fixed__inner__layout-wrapper': { + maxHeight: 'none', + width: 'auto', + '&, .ss__autocomplete': { + overflowY: 'visible', + }, + '.ss__autocomplete': { + maxWidth: 'none', + width: props?.width, + right: 0, + left: '-102px', + top: 'auto', + margin: 'auto', + }, + }, + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '.ss__autocomplete-fixed__inner__layout-wrapper': { + '.ss__autocomplete': { + maxWidth: '100%', + width: props?.width, + left: 0, + right: 0, + }, + }, + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '.ss__autocomplete-fixed__inner__layout-wrapper': { + '.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + '& > *:nth-of-type(n+3)': { + display: 'none', + }, + }, + }, + }, + }, + }, + }, + }, + }); +}; + +export const autocompleteFixed: ThemeComponent<'autocompleteFixed', AutocompleteFixedProps> = { + default: { + ...autocompleteFixedThemeComponentProps.default, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.default?.['autocompleteFixed'] || {}), + themeStyleScript: autocompleteFixedStyleScript, + width: '900px', + layout: 'standard', + }, + 'autocompleteFixed facetPaletteOptions': { + gridSize: '38px', + hideLabel: false, + }, + 'autocompleteFixed facetGridOptions': { + gridSize: '38px', + }, + 'autocompleteFixed facet': { + ...(autocompleteFixedThemeComponentProps.default?.['autocompleteFixed facet'] || {}), + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocompleteFixed results': { + rows: 2, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 2, + columns: 4, + }, + 'autocompleteFixed button.see-more icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteFixedThemeComponentProps.mobile, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.mobile?.['autocompleteFixed'] || {}), + width: 'auto', + layout: 'mini', + }, + 'autocompleteFixed results': { + rows: 1, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteFixedThemeComponentProps.tablet, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.tablet?.['autocompleteFixed'] || {}), + width: 'auto', + layout: 'standard', + }, + 'autocompleteFixed facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocompleteFixed results': { + rows: 1, + columns: 4, + }, + 'autocompleteFixed recommendationGrid': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteFixedThemeComponentProps.desktop, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.desktop?.['autocompleteFixed'] || {}), + layout: 'standard', + }, + 'autocompleteFixed results': { + rows: 2, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteModal.ts b/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteModal.ts new file mode 100644 index 000000000..6c01ac334 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteModal.ts @@ -0,0 +1,204 @@ +import { css } from '@emotion/react'; +import { autocompleteModalThemeComponentProps } from '../../../themeComponents/autocompleteModal'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteModalProps } from '../../../../components/Templates/AutocompleteModal'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const autocompleteModalStyleScript = (props: AutocompleteModalProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '.ss__modal': { + '&, .ss__modal__content': { + height: '100%', + }, + '.ss__modal__content': { + backgroundColor: 'transparent', + justifyContent: 'center', + '&, .ss__autocomplete-modal__inner': { + position: 'static', + display: 'flex', + flexFlow: 'column nowrap', + }, + '.ss__autocomplete-modal__inner': { + width: props?.width, + maxHeight: 'none', + height: '80vh', + overflow: 'hidden', + '& > .ss__search-input.autocomplete-modal__search-input, .ss__autocomplete': { + minHeight: '1px', + minWidth: '1px', + }, + '& > .ss__search-input.autocomplete-modal__search-input': { + flex: '0 1 auto', + height: '40px', + margin: 0, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '40px', + }, + }, + '.ss__autocomplete': { + flex: '1 1 0%', + borderWidth: 0, + overflowY: 'auto', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + maxHeight: 'none', + overflow: 'visible', + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + width: props?.width, + height: '100%', + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + '.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + '& > *:nth-of-type(n+5)': { + display: 'none', + }, + }, + }, + }, + }, + }, + }, + }); +}; + +export const autocompleteModal: ThemeComponent<'autocompleteModal', AutocompleteModalProps> = { + default: { + ...autocompleteModalThemeComponentProps.default, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.default?.['autocompleteModal'] || {}), + themeStyleScript: autocompleteModalStyleScript, + width: '70vw', + layout: 'standard', + }, + 'autocompleteModal facetPaletteOptions': { + gridSize: '38px', + hideLabel: false, + }, + 'autocompleteModal facetGridOptions': { + gridSize: '38px', + }, + 'autocompleteModal facet': { + ...(autocompleteModalThemeComponentProps.default?.['autocompleteModal facet'] || {}), + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + 'autocompleteModal button.see-more icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteModalThemeComponentProps.mobile, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.mobile?.['autocompleteModal'] || {}), + width: '100%', + layout: 'mini', + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 3, + }, + }, + tablet: { + ...autocompleteModalThemeComponentProps.tablet, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.tablet?.['autocompleteModal'] || {}), + width: '80vw', + layout: 'standard', + }, + 'autocompleteModal facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocompleteModal results': { + rows: 2, + columns: 4, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + }, + desktop: { + ...autocompleteModalThemeComponentProps.desktop, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.desktop?.['autocompleteModal'] || {}), + width: '80vw', + layout: 'standard', + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteSlideout.ts b/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteSlideout.ts new file mode 100644 index 000000000..580ff67d0 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/autocompleteSlideout.ts @@ -0,0 +1,129 @@ +import { css } from '@emotion/react'; +import { autocompleteSlideoutThemeComponentProps } from '../../../themeComponents/autocompleteSlideout'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteSlideoutProps } from '../../../../components/Templates/AutocompleteSlideout'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const autocompleteSlideoutStyleScript = (props: AutocompleteSlideoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + border: 0, + padding: `${custom.spacing.x4}px`, + '.ss__autocomplete-slideout__inner': { + display: 'flex', + flexFlow: 'column nowrap', + height: '100%', + '& > .ss__search-input.autocomplete-slideout__search-input, .ss__autocomplete': { + minHeight: '1px', + minWidth: '1px', + }, + '& > .ss__search-input.autocomplete-slideout__search-input': { + flex: '0 1 auto', + height: '40px', + margin: `0 0 ${custom.spacing.x2}px 0`, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '40px', + }, + }, + '.ss__autocomplete': { + flex: '1 1 0%', + alignContent: 'flex-start', + borderWidth: 0, + overflowY: 'auto', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '& > .ss__autocomplete__row .ss__autocomplete__column': { + padding: `${custom.spacing.x4}px 0`, + }, + '.ss__autocomplete__terms-wrapper, .ss__autocomplete__content, .ss__autocomplete__button--see-more': { + paddingLeft: 0, + paddingRight: 0, + }, + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + maxHeight: 'none', + overflow: 'visible', + }, + }, + }, + }); +}; + +export const autocompleteSlideout: ThemeComponent<'autocompleteSlideout', AutocompleteSlideoutProps> = { + default: { + ...autocompleteSlideoutThemeComponentProps.default, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.default?.['autocompleteSlideout'] || {}), + themeStyleScript: autocompleteSlideoutStyleScript, + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout button.see-more icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteSlideoutThemeComponentProps.mobile, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.mobile?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 2, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 2, + }, + }, + tablet: { + ...autocompleteSlideoutThemeComponentProps.tablet, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.tablet?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, + desktop: { + ...autocompleteSlideoutThemeComponentProps.desktop, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.desktop?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/index.ts b/packages/snap-preact/components/src/themes/everest/components/templates/index.ts new file mode 100644 index 000000000..e6bef36ce --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/index.ts @@ -0,0 +1,79 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// TEMPLATES +import { autocompleteFixed } from './autocompleteFixed'; +import { autocompleteModal } from './autocompleteModal'; +import { autocompleteSlideout } from './autocompleteSlideout'; +import { recommendation } from './recommendation'; +import { recommendationBundle } from './recommendationBundle'; +import { recommendationBundleEasyAdd } from './recommendationBundleEasyAdd'; +import { recommendationBundleList } from './recommendationBundleList'; +import { recommendationBundleVertical } from './recommendationBundleVertical'; +import { recommendationGrid } from './recommendationGrid'; +import { recommendationEmail } from './recommendationEmail'; +import { search } from './search'; +import { searchHorizontal } from './searchHorizontal'; +import { searchCollapsible } from './searchCollapsible'; + +export const templates: ThemeResponsiveComplete = { + default: { + ...autocompleteFixed.default, + ...autocompleteModal.default, + ...autocompleteSlideout.default, + ...recommendation.default, + ...recommendationBundle.default, + ...recommendationBundleEasyAdd.default, + ...recommendationBundleList.default, + ...recommendationBundleVertical.default, + ...recommendationGrid.default, + ...recommendationEmail.default, + ...search.default, + ...searchCollapsible.default, + ...searchHorizontal.default, + }, + mobile: { + ...autocompleteFixed.mobile, + ...autocompleteModal.mobile, + ...autocompleteSlideout.mobile, + ...recommendation.mobile, + ...recommendationBundle.mobile, + ...recommendationBundleEasyAdd.mobile, + ...recommendationBundleList.mobile, + ...recommendationBundleVertical.mobile, + ...recommendationGrid.mobile, + ...recommendationEmail.mobile, + ...search.mobile, + ...searchCollapsible.mobile, + ...searchHorizontal.mobile, + }, + tablet: { + ...autocompleteFixed.tablet, + ...autocompleteModal.tablet, + ...autocompleteSlideout.tablet, + ...recommendation.tablet, + ...recommendationBundle.tablet, + ...recommendationBundleEasyAdd.tablet, + ...recommendationBundleList.tablet, + ...recommendationBundleVertical.tablet, + ...recommendationGrid.tablet, + ...recommendationEmail.tablet, + ...search.tablet, + ...searchCollapsible.tablet, + ...searchHorizontal.tablet, + }, + desktop: { + ...autocompleteFixed.desktop, + ...autocompleteModal.desktop, + ...autocompleteSlideout.desktop, + ...recommendation.desktop, + ...recommendationBundle.desktop, + ...recommendationBundleEasyAdd.desktop, + ...recommendationBundleList.desktop, + ...recommendationBundleVertical.desktop, + ...recommendationGrid.desktop, + ...recommendationEmail.desktop, + ...search.desktop, + ...searchCollapsible.desktop, + ...searchHorizontal.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendation.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendation.ts new file mode 100644 index 000000000..5765da87c --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendation.ts @@ -0,0 +1,122 @@ +import { css } from '@emotion/react'; +import type { RecommendationProps } from '../../../../components/Templates/Recommendation'; +import { recommendationThemeComponentProps } from '../../../themeComponents/recommendation'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Recommendation component +const recommendationStyleScript = (props: RecommendationProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const arrowSizes = { + default: 32, + tablet: 28, + mobile: 24, + }; + + return css({ + margin: `${custom.spacing.x8}px 0`, + '.ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + textAlign: 'center', + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__carousel': { + padding: `0 ${custom.spacing.x4 + arrowSizes.default}px`, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__carousel': { + padding: `0 ${custom.spacing.x4 + arrowSizes.tablet}px`, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + width: `${arrowSizes.tablet}px`, + height: `${arrowSizes.tablet}px`, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + position: 'relative', + '.ss__recommendation__title': { + textAlign: 'left', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + paddingRight: `${arrowSizes.mobile * 2 + custom.spacing.x1 + custom.spacing.x4}px`, + }, + '.ss__carousel': { + padding: 0, + position: 'static', + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: '4.5px', + bottom: 'auto', + left: 'auto', + width: `${arrowSizes.mobile}px`, + height: `${arrowSizes.mobile}px`, + }, + '.ss__carousel__prev-wrapper': { + right: `${arrowSizes.mobile + custom.spacing.x1}px`, + }, + '.ss__carousel__next-wrapper': { + right: 0, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(18), + }, + '.ss__carousel': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: 0, + }, + }, + }, + }); +}; + +// Recommendation component props come from Template export +export const recommendation: ThemeComponent<'recommendation', RecommendationProps> = { + default: { + ...recommendationThemeComponentProps.default, + recommendation: { + ...(recommendationThemeComponentProps.default?.['recommendation'] || {}), + themeStyleScript: recommendationStyleScript, + spaceBetween: custom.spacing.x4, + }, + }, + mobile: { + ...recommendationThemeComponentProps.mobile, + recommendation: { + ...(recommendationThemeComponentProps.mobile?.['recommendation'] || {}), + spaceBetween: custom.spacing.x2, + }, + 'recommendation icon.prev': { + size: `${custom.sizes.icon08}px`, + }, + 'recommendation icon.next': { + size: `${custom.sizes.icon08}px`, + }, + }, + tablet: { + ...recommendationThemeComponentProps.tablet, + recommendation: { + ...(recommendationThemeComponentProps.tablet?.['recommendation'] || {}), + spaceBetween: custom.spacing.x4, + }, + 'recommendation icon.prev': { + size: `${custom.sizes.icon10}px`, + }, + 'recommendation icon.next': { + size: `${custom.sizes.icon10}px`, + }, + }, + desktop: { + ...recommendationThemeComponentProps.desktop, + recommendation: { + ...(recommendationThemeComponentProps.desktop?.['recommendation'] || {}), + spaceBetween: custom.spacing.x4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundle.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundle.ts new file mode 100644 index 000000000..471791147 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundle.ts @@ -0,0 +1,250 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleProps } from '../../../../components/Templates/RecommendationBundle'; +import { recommendationBundleThemeComponentProps } from '../../../themeComponents/recommendationBundle'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundle component +const recommendationBundleStyleScript = (props: RecommendationBundleProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x8}px 0`, + '.ss__recommendation-bundle__title': { + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__recommendation-bundle__wrapper': { + flexFlow: `row nowrap`, + margin: `0 -${custom.spacing.x2}px`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + padding: `0 ${custom.spacing.x2}px`, + boxSizing: 'border-box', + }, + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__cta': { + width: `20%`, + }, + '.ss__recommendation-bundle__wrapper__carousel': { + width: `60%`, + }, + }, + '.ss__recommendation-result-tracker, .ss__recommendation-bundle__wrapper__selector, .ss__recommendation-bundle__wrapper .ss__recommendation-bundle__wrapper__selector__result-wrapper': + { + height: '100%', + margin: 0, + }, + '.ss__recommendation-bundle__wrapper__seed-container': { + '.ss__recommendation-bundle__wrapper__selector__result-wrapper__seed-badge': { + top: '5px', + left: '5px', + backgroundColor: variables?.colors?.primary, + fontSize: custom.utils.convertPxToEm(12), + fontWeight: custom.fonts.weight01, + lineHeight: `20px`, + color: custom.colors.white, + padding: `0 ${custom.spacing.x2}px`, + }, + }, + '.ss__recommendation-bundle__wrapper__selector': { + width: 'auto !important', + }, + '.ss__recommendation-bundle__wrapper__selector__result-wrapper, .ss__carousel .swiper-container > .swiper-wrapper > .swiper-slide': { + '.ss__result': { + width: '100%', + flex: '1 1 0%', + }, + }, + '.ss__recommendation-bundle__wrapper__selector__result-wrapper': { + display: 'flex', + flexFlow: `column wrap`, + '&, .ss__result': { + position: 'relative', + }, + '&:has(.ss__overlay-badge)': { + '.ss__result': { + '.ss__overlay-badge .ss__overlay-badge__grid-wrapper': { + top: '25px', + }, + }, + }, + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + }, + '.ss__icon--plus': { + display: 'none', + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + margin: 'auto 0', + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle__wrapper__cta': { + position: 'relative', + paddingTop: `${custom.spacing.x4}px`, + paddingBottom: `${custom.spacing.x4}px`, + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'center', + alignItems: 'center', + gap: `${custom.spacing.x4}px`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + margin: `0 ${custom.spacing.x2}px 0 ${custom.spacing.x4}px`, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal, .ss__recommendation-bundle__wrapper__cta__button': { + position: 'relative', + zIndex: 2, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal': { + color: variables?.colors?.text, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__prices': { + margin: `${custom.spacing.x1}px 0 0 0`, + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + '&:after': { + content: '""', + display: 'block', + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + boxSizing: 'border-box', + position: 'absolute', + top: 0, + left: '10px', + right: 0, + bottom: 0, + zIndex: 1, + margin: 'auto', + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__recommendation-bundle__wrapper': { + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__cta': { + width: `25%`, + }, + '.ss__recommendation-bundle__wrapper__carousel': { + width: `50%`, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle__wrapper': { + flexFlow: 'row wrap', + width: 'auto', + maxWidth: 'none', + margin: `0 -${custom.spacing.x1}px`, + '& > *': { + padding: `0 ${custom.spacing.x1}px`, + }, + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__carousel': { + width: `50%`, + }, + }, + '.ss__recommendation-bundle__wrapper__cta': { + width: 'auto', + margin: `${custom.spacing.x4}px 0 0 0`, + padding: `${custom.spacing.x4}px`, + '& > *': { + margin: 0, + }, + '&:after': { + left: 0, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__recommendation-bundle__title': { + fontSize: custom.utils.convertPxToEm(18), + }, + }, + }); +}; + +// RecommendationBundle component props come from Template export +export const recommendationBundle: ThemeComponent<'recommendationBundle', RecommendationBundleProps> = { + default: { + ...recommendationBundleThemeComponentProps.default, + recommendationBundle: { + ...(recommendationBundleThemeComponentProps.default?.['recommendationBundle'] || {}), + themeStyleScript: recommendationBundleStyleScript, + }, + 'recommendationBundle icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + 'recommendationBundle icon.bundle-selector': { + icon: custom.icons.plus, + size: `${custom.sizes.icon14}px`, + }, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, + mobile: { + ...recommendationBundleThemeComponentProps.mobile, + 'recommendationBundle carousel': { + spaceBetween: 0, + }, + }, + tablet: { + ...recommendationBundleThemeComponentProps.tablet, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, + desktop: { + ...recommendationBundleThemeComponentProps.desktop, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleEasyAdd.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleEasyAdd.ts new file mode 100644 index 000000000..0a4272b23 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleEasyAdd.ts @@ -0,0 +1,134 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleEasyAddProps } from '../../../../components/Templates/RecommendationBundleEasyAdd'; +import { recommendationBundleEasyAddThemeComponentProps } from '../../../themeComponents/recommendationBundleEasyAdd'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleEasyAdd component +const recommendationBundleEasyAddStyleScript = (props: RecommendationBundleEasyAddProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-easy-add__title': { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle-easy-add__wrapper': { + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + '& > div': { + width: '50%', + minWidth: '1px', + flex: '0 1 auto', + boxSizing: 'border-box', + }, + '.ss__recommendation-bundle-easy-add__wrapper__selector__result-wrapper, .ss__recommendation-bundle-easy-add__wrapper__cta': { + margin: 0, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta': { + padding: `${custom.spacing.x4}px`, + width: 'auto', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'center', + alignItems: 'center', + gap: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal': { + color: variables?.colors?.text, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__prices': { + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle-easy-add__wrapper': { + flexFlow: 'row wrap', + '& > div': { + width: 'auto', + flex: '1 1 100%', + }, + }, + }, + }); +}; + +// RecommendationBundleEasyAdd component props come from Template export +export const recommendationBundleEasyAdd: ThemeComponent<'recommendationBundleEasyAdd', RecommendationBundleEasyAddProps> = { + default: { + ...recommendationBundleEasyAddThemeComponentProps.default, + recommendationBundleEasyAdd: { + ...(recommendationBundleEasyAddThemeComponentProps.default?.['recommendationBundleEasyAdd'] || {}), + themeStyleScript: recommendationBundleEasyAddStyleScript, + ctaInline: true, + }, + 'recommendationBundleEasyAdd icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + }, + mobile: { + ...recommendationBundleEasyAddThemeComponentProps.mobile, + }, + tablet: { + ...recommendationBundleEasyAddThemeComponentProps.tablet, + }, + desktop: { + ...recommendationBundleEasyAddThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleList.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleList.ts new file mode 100644 index 000000000..d66f9abdf --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleList.ts @@ -0,0 +1,177 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleListProps } from '../../../../components/Templates/RecommendationBundleList'; +import { recommendationBundleListThemeComponentProps } from '../../../themeComponents/recommendationBundleList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleEasyAdd component +const recommendationBundleListStyleScript = (props: RecommendationBundleListProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-list__title': { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle-list__wrapper': { + flexFlow: 'row wrap', + margin: `0 -${custom.spacing.x1}px`, + '&, & > div': { + boxSizing: 'border-box', + }, + '& > div': { + width: '50%', + minWidth: '1px', + flex: '0 1 auto', + padding: `0 ${custom.spacing.x1}px`, + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper': { + margin: 0, + gap: `${custom.spacing.x2}px`, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper__checkbox, .ss__result': { + minWidth: '1px', + }, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper__checkbox': { + flex: '0 1 auto', + }, + '.ss__result': { + flex: '1 1 0%', + '.ss__result__image-wrapper': { + display: 'none', + }, + '.ss__result__details': { + gap: 0, + }, + }, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta': { + '.ss__recommendation-bundle-list__wrapper__cta__inner': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + lineHeight: 1, + }, + '.ss__recommendation-bundle-list__wrapper__cta__inner__images': { + flexFlow: 'row nowrap', + gap: `${custom.spacing.x2 + custom.sizes.icon12}px`, + '.ss__recommendation-bundle-list__wrapper__cta__inner__image-wrapper': { + flex: '1 1 0%', + minWidth: '1px', + padding: 0, + '.ss__icon': { + top: 0, + bottom: 0, + right: `-${custom.spacing.x2 / 2 + custom.sizes.icon12}px`, + margin: 'auto 0', + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal': { + padding: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__prices': { + margin: `${custom.spacing.x1}px 0 0 0`, + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + }, + '.ss__recommendation-bundle-list__cta__button__wrapper': { + margin: `${custom.spacing.x4}px 0`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle-list__wrapper': { + '& > div': { + width: 'auto', + flex: '1 1 100%', + }, + }, + }, + }); +}; + +// RecommendationBundleList component props come from Template export +export const recommendationBundleList: ThemeComponent<'recommendationBundleList', RecommendationBundleListProps> = { + default: { + ...recommendationBundleListThemeComponentProps.default, + recommendationBundleList: { + ...(recommendationBundleListThemeComponentProps.default?.['recommendationBundleList'] || {}), + themeStyleScript: recommendationBundleListStyleScript, + separatorIconSeedOnly: false, + }, + 'recommendationBundleList icon.bundle-cart-separator': { + icon: custom.icons.plus, + size: `${custom.sizes.icon12}px`, + }, + 'recommendationBundleList icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + 'recommendationBundleList result': { + hideImage: true, + hideBadge: true, + }, + }, + mobile: { + ...recommendationBundleListThemeComponentProps.mobile, + }, + tablet: { + ...recommendationBundleListThemeComponentProps.tablet, + }, + desktop: { + ...recommendationBundleListThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleVertical.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleVertical.ts new file mode 100644 index 000000000..dba4de860 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationBundleVertical.ts @@ -0,0 +1,159 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleVerticalProps } from '../../../../components/Templates/RecommendationBundleVertical'; +import { recommendationBundleVerticalThemeComponentProps } from '../../../themeComponents/recommendationBundleVertical'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleVertical component +const recommendationBundleVerticalStyleScript = (props: RecommendationBundleVerticalProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-vertical__title': { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle-vertical__wrapper': { + gap: `${custom.spacing.x4}px`, + '& > div': { + minWidth: '1px', + flex: '1 1 100%', + }, + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper': { + margin: 0, + '&, .ss__result': { + position: 'relative', + }, + '&:has(.ss__overlay-badge)': { + '.ss__result': { + '.ss__overlay-badge .ss__overlay-badge__grid-wrapper': { + top: '25px', + }, + }, + }, + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper__seed-badge': { + top: '5px', + left: '5px', + backgroundColor: variables?.colors?.primary, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight01, + lineHeight: `24px`, + color: custom.colors.white, + padding: `0 ${custom.spacing.x2}px`, + }, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta': { + padding: `${custom.spacing.x4}px`, + width: 'auto', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'center', + alignItems: 'center', + gap: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal': { + color: variables?.colors?.text, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__prices': { + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle-vertical__wrapper': { + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper': { + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper__seed-badge': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: `20px`, + }, + }, + }, + }, + }); +}; + +// RecommendationBundleVertical component props come from Template export +export const recommendationBundleVertical: ThemeComponent<'recommendationBundleVertical', RecommendationBundleVerticalProps> = { + default: { + ...recommendationBundleVerticalThemeComponentProps.default, + recommendationBundleVertical: { + ...(recommendationBundleVerticalThemeComponentProps.default?.['recommendationBundleVertical'] || {}), + themeStyleScript: recommendationBundleVerticalStyleScript, + }, + 'recommendationBundleVertical icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + 'recommendationBundleVertical icon.bundle-selector': { + icon: custom.icons.plus, + size: `${custom.sizes.icon14}px`, + }, + }, + mobile: { + ...recommendationBundleVerticalThemeComponentProps.mobile, + }, + tablet: { + ...recommendationBundleVerticalThemeComponentProps.tablet, + }, + desktop: { + ...recommendationBundleVerticalThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendationEmail.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationEmail.ts new file mode 100644 index 000000000..c87c85f65 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationEmail.ts @@ -0,0 +1,52 @@ +import { css } from '@emotion/react'; +import type { RecommendationEmailProps } from '../../../../components/Templates/RecommendationEmail'; +import { recommendationEmailThemeComponentProps } from '../../../themeComponents/recommendationEmail'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationEmail component +const recommendationEmailStyleScript = (props: RecommendationEmailProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + width: '400px !important', + height: '680px', + margin: `0 0 ${custom.spacing.x6}px 0`, + padding: `0 ${custom.spacing.x2}px`, + overflow: 'hidden', + '.ss__result': { + fontSize: '16px', + '.ss__result__details .ss__result__details__title a': { + display: 'block', + height: '26px', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + }, + }); +}; + +// RecommendationEmail component props come from Template export +export const recommendationEmail: ThemeComponent<'recommendationEmail', RecommendationEmailProps> = { + default: { + ...recommendationEmailThemeComponentProps.default, + recommendationEmail: { + ...(recommendationEmailThemeComponentProps.default?.['recommendationEmail'] || {}), + themeStyleScript: recommendationEmailStyleScript, + }, + 'recommendationEmail image': { + lazy: false, + }, + }, + mobile: { + ...recommendationEmailThemeComponentProps.mobile, + }, + tablet: { + ...recommendationEmailThemeComponentProps.tablet, + }, + desktop: { + ...recommendationEmailThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/recommendationGrid.ts b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationGrid.ts new file mode 100644 index 000000000..d14e34a46 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/recommendationGrid.ts @@ -0,0 +1,72 @@ +import { css } from '@emotion/react'; +import type { RecommendationGridProps } from '../../../../components/Templates/RecommendationGrid'; +import { recommendationGridThemeComponentProps } from '../../../themeComponents/recommendationGrid'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundle component +const recommendationGridStyleScript = (props: RecommendationGridProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x8}px 0`, + maxHeight: 'none', + '.ss__recommendation-grid__title': { + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + textAlign: 'center', + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__recommendation-grid__results': { + overflowX: 'auto', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-grid__title': { + textAlign: 'left', + }, + }, + }); +}; + +// RecommendationGrid component props come from Template export +export const recommendationGrid: ThemeComponent<'recommendationGrid', RecommendationGridProps> = { + default: { + ...recommendationGridThemeComponentProps.default, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.default?.['recommendationGrid'] || {}), + themeStyleScript: recommendationGridStyleScript, + gapSize: `${custom.spacing.x6}px ${custom.spacing.x4}px`, + columns: 4, + }, + }, + mobile: { + ...recommendationGridThemeComponentProps.mobile, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.mobile?.['recommendationGrid'] || {}), + gapSize: `${custom.spacing.x6}px ${custom.spacing.x2}px`, + columns: 2, + }, + }, + tablet: { + ...recommendationGridThemeComponentProps.tablet, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.tablet?.['recommendationGrid'] || {}), + columns: 3, + }, + }, + desktop: { + ...recommendationGridThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/search.ts b/packages/snap-preact/components/src/themes/everest/components/templates/search.ts new file mode 100644 index 000000000..3e2a9488e --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/search.ts @@ -0,0 +1,80 @@ +import { css } from '@emotion/react'; +import type { SearchProps } from '../../../../components/Templates/Search'; +import { searchThemeComponentProps } from '../../../themeComponents/search'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchStyleScript = (props: SearchProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '&.ss__search--sidebar-open': { + '.ss__button': { + '.ss__icon--filter': { + transform: 'rotate(-180deg)', + }, + '.ss__icon--filters': { + circle: { + '&:last-child': { + transform: 'translateX(-35%)', + }, + transform: 'translateX(35%)', + }, + }, + }, + }, + '.ss__search__header-section, .ss__search__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '.ss__toolbar .ss__layout': { + gap: `${custom.spacing.x4}px`, + }, + }, + '.ss__search__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search__sidebar, .ss__search__content': { + minWidth: '1px', + }, + '.ss__search__sidebar': { + flex: '0 1 auto', + }, + '.ss__search__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__search__main-section': { + '.ss__toolbar': { + '.ss__select': { + flex: '1 1 0%', + }, + }, + }, + }, + }); +}; + +// Search component props come from Template export +export const search: ThemeComponent<'search', SearchProps> = { + default: { + ...searchThemeComponentProps.default, + search: { + ...(searchThemeComponentProps.default?.['search'] || {}), + themeStyleScript: searchStyleScript, + }, + 'search filterSummary': { + type: 'list', + }, + }, + mobile: { + ...searchThemeComponentProps.mobile, + }, + tablet: { + ...searchThemeComponentProps.tablet, + }, + desktop: { + ...searchThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/searchCollapsible.ts b/packages/snap-preact/components/src/themes/everest/components/templates/searchCollapsible.ts new file mode 100644 index 000000000..bff1a4fc4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/searchCollapsible.ts @@ -0,0 +1,88 @@ +import { css } from '@emotion/react'; +import type { SearchCollapsibleProps } from '../../../../components/Templates/SearchCollapsible'; +import { searchCollapsibleThemeComponentProps } from '../../../themeComponents/searchCollapsible'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchCollapsibleStyleScript = (props: SearchCollapsibleProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '&.ss__search-collapsible--sidebar-open': { + '.ss__button': { + '.ss__icon--filter': { + transform: 'rotate(-180deg)', + }, + '.ss__icon--filters': { + circle: { + '&:last-child': { + transform: 'translateX(-35%)', + }, + transform: 'translateX(35%)', + }, + }, + }, + }, + '.ss__search-collapsible__header-section, .ss__search-collapsible__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '.ss__toolbar .ss__layout': { + gap: `${custom.spacing.x4}px`, + }, + }, + '.ss__search-collapsible__header-section': { + '.ss__search-header': { + textAlign: 'center', + }, + }, + '.ss__search-collapsible__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search-collapsible__sidebar, .ss__search-collapsible__content': { + minWidth: '1px', + }, + '.ss__search-collapsible__sidebar': { + flex: '0 1 auto', + }, + '.ss__search-collapsible__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__toolbar': { + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(16), + }, + }, + }, + }); +}; + +export const searchCollapsible: ThemeComponent<'searchCollapsible', SearchCollapsibleProps> = { + default: { + ...searchCollapsibleThemeComponentProps.default, + searchCollapsible: { + ...(searchCollapsibleThemeComponentProps.default?.['searchCollapsible'] || {}), + themeStyleScript: searchCollapsibleStyleScript, + }, + 'searchCollapsible sidebar': { + hideTitleText: true, + }, + 'searchCollapsible button.sidebar-toggle': { + icon: custom.icons.filter, + }, + 'searchCollapsible filterSummary': { + type: 'list', + }, + }, + mobile: { + ...searchCollapsibleThemeComponentProps.mobile, + }, + tablet: { + ...searchCollapsibleThemeComponentProps.tablet, + }, + desktop: { + ...searchCollapsibleThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/components/templates/searchHorizontal.ts b/packages/snap-preact/components/src/themes/everest/components/templates/searchHorizontal.ts new file mode 100644 index 000000000..3501da121 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/components/templates/searchHorizontal.ts @@ -0,0 +1,78 @@ +import { css } from '@emotion/react'; +import type { SearchHorizontalProps } from '../../../../components/Templates/SearchHorizontal'; +import { searchHorizontalThemeComponentProps } from '../../../themeComponents/searchHorizontal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchHorizontalStyleScript = (props: SearchHorizontalProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '.ss__search-horizontal__header-section, .ss__search-horizontal__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '.ss__toolbar .ss__layout': { + gap: `${custom.spacing.x4}px`, + '.ss__layout__row': { + '&:has(.ss__facets-horizontal)': { + alignItems: 'flex-start', + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__facets-horizontal': { + flex: '1 1 0%', + }, + }, + }, + }, + }, + '.ss__search-horizontal__header-section': { + '.ss__search-header': { + textAlign: 'center', + }, + }, + '.ss__search-horizontal__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search-horizontal__sidebar, .ss__search-horizontal__content': { + minWidth: '1px', + }, + '.ss__search-horizontal__sidebar': { + flex: '0 1 auto', + }, + '.ss__search-horizontal__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__search-horizontal__main-section': { + '.ss__toolbar': { + '.ss__select': { + flex: '1 1 0%', + }, + }, + }, + }, + }); +}; + +export const searchHorizontal: ThemeComponent<'searchHorizontal', SearchHorizontalProps> = { + default: { + ...searchHorizontalThemeComponentProps.default, + searchHorizontal: { + ...(searchHorizontalThemeComponentProps.default?.['searchHorizontal'] || {}), + themeStyleScript: searchHorizontalStyleScript, + }, + }, + mobile: { + ...searchHorizontalThemeComponentProps.mobile, + }, + tablet: { + ...searchHorizontalThemeComponentProps.tablet, + }, + desktop: { + ...searchHorizontalThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/custom.ts b/packages/snap-preact/components/src/themes/everest/custom.ts new file mode 100644 index 000000000..854c2f26b --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/custom.ts @@ -0,0 +1,108 @@ +import { IconType } from '../../components/Atoms/Icon'; +import Color from 'color'; + +// calculate spacing +const spacing = 5; +const spacingCalc = (value: number) => { + return spacing * value; +}; + +export const custom: { + breakpoints: { + [key: string]: number; + }; + colors: { + [key: string]: string; + }; + fonts: { + [key: string]: any; + }; + icons: { + [key: string]: IconType; + }; + sizes: { + [key: string]: number; + }; + spacing: { + [key: string]: number; + }; + utils: { + convertPxToEm: (value: number) => string; + lightenColor: (color: string | undefined, amount: number) => string; + darkenColor: (color: string | undefined, amount: number) => string; + }; +} = { + breakpoints: { + small: 540, + mobile: 767, + tablet: 1024, + desktop: 1280, + }, + colors: { + white: '#ffffff', + black: '#000000', + gray01: '#f8f8f8', // lighter gray: bg color under terms, dropdown, checkboxes + gray02: '#ebebeb', // light gray: borders for autocomplete, dropdown, checkboxes + brown: '#845329', // for color palette + purple: '#7c368e', // for color palette + rainbow: + 'linear-gradient(rgb(40, 87, 218) 20%, rgb(40, 218, 70) 20%, rgb(40, 218, 70) 40%, rgb(245, 228, 24) 40%, rgb(245, 228, 24) 60%, rgb(242, 133, 0) 60%, rgb(242, 133, 0) 80%, rgb(218, 40, 72) 80%, rgb(218, 40, 72))', // for color palette + }, + fonts: { + weight01: 700, // main font weight + weight02: 700, // header font weight + style: false, + transform: 'uppercase', + }, + icons: { + arrowLeft: 'chevron-left', + arrowRight: 'chevron-right', + arrowDown: 'chevron-down', + arrowUp: 'chevron-up', + bag: 'bag', + check: 'square', + close: 'close', + minus: 'minus', + plus: 'plus', + filter: 'filter', + filters: 'filters', + search: 'search', + sort: 'sort', + }, + sizes: { + font: 16, // base font size + height: 35, // refers to height for button and dropdown sizes + icon08: 8, + icon10: 10, + icon12: 12, + icon14: 14, + icon16: 16, + radius: 3, // global border radius value + }, + spacing: { + x1: spacing, + x2: spacingCalc(2), + x3: spacingCalc(3), + x4: spacingCalc(4), + x5: spacingCalc(5), + x6: spacingCalc(6), + x7: spacingCalc(7), + x8: spacingCalc(8), + }, + utils: { + convertPxToEm: (value: number) => { + // translates px to rem + return `${value / custom.sizes.font}rem`; + }, + lightenColor: (color: string | undefined, amount: number) => { + // lighten a color + const lightColor = new Color(color || '#515151').lighten(amount).hex().toLowerCase(); + return lightColor; + }, + darkenColor: (color: string | undefined, amount: number) => { + // darken a color + const darkColor = new Color(color || '#515151').darken(amount).hex().toLowerCase(); + return darkColor; + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/everest/everest.ts b/packages/snap-preact/components/src/themes/everest/everest.ts new file mode 100644 index 000000000..13771cc90 --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/everest.ts @@ -0,0 +1,24 @@ +import { ThemeComplete, ThemeVariables } from '../../providers'; +import { components } from './components'; +import { responsive } from './responsive'; + +const everestVariables: ThemeVariables = { + breakpoints: { + mobile: 767, + tablet: 991, + desktop: 1199, + }, + colors: { + text: '#515151', + primary: '#d15120', + secondary: '#94280b', + accent: '#a8391c', + }, +}; + +export const everest: ThemeComplete = { + name: 'everest', + variables: everestVariables, + components, + responsive, +}; diff --git a/packages/snap-preact/components/src/themes/everest/responsive.ts b/packages/snap-preact/components/src/themes/everest/responsive.ts new file mode 100644 index 000000000..61ae08bfe --- /dev/null +++ b/packages/snap-preact/components/src/themes/everest/responsive.ts @@ -0,0 +1,8 @@ +import { ThemeResponsive } from '../../providers/theme'; +import { mobileComponents, tabletComponents, desktopComponents } from './components'; + +export const responsive: ThemeResponsive = { + mobile: mobileComponents, + tablet: tabletComponents, + desktop: desktopComponents, +}; diff --git a/packages/snap-preact/components/src/themes/index.ts b/packages/snap-preact/components/src/themes/index.ts index fe1bf6ae5..b668ce1ff 100644 --- a/packages/snap-preact/components/src/themes/index.ts +++ b/packages/snap-preact/components/src/themes/index.ts @@ -1,4 +1,7 @@ export * from './base/base'; export * from './bocachica/bocachica'; -export * from './snappy/snappy'; +export * from './everest/everest'; +export * from './matterhorn/matterhorn'; +export * from './pike/pike'; export * from './snapnco/snapnco'; +export * from './snappy/snappy'; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/breadcrumbs.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/breadcrumbs.ts new file mode 100644 index 000000000..c1436cbbf --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/breadcrumbs.ts @@ -0,0 +1,46 @@ +import { css } from '@emotion/react'; +import type { BreadcrumbsProps } from '../../../../components/Atoms/Breadcrumbs'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Breadcrumbs component +const breadcrumbsStyleScript = (props: BreadcrumbsProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__breadcrumbs__crumbs': { + margin: `0 -${custom.spacing.x1}px`, + '&, li': { + listStyle: 'none', + }, + '&, a': { + color: variables?.colors?.text, + }, + li: { + display: 'block', + padding: `0 ${custom.spacing.x1}px`, + '&:last-of-type': { + color: variables?.colors?.primary, + fontWeight: custom?.fonts?.weight01, + }, + }, + '.ss__breadcrumbs__crumbs__separator': { + '.ss__icon': { + width: `${custom.sizes.icon10}px`, + height: `${custom.sizes.icon10}px`, + }, + }, + }, + }); +}; + +// Breadcrumbs component props +export const breadcrumbs: ThemeComponent<'breadcrumbs', BreadcrumbsProps> = { + default: { + breadcrumbs: { + themeStyleScript: breadcrumbsStyleScript, + separator: false, + separatorIcon: custom.icons.arrowRight, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/button.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/button.ts new file mode 100644 index 000000000..3ce996b7c --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/button.ts @@ -0,0 +1,75 @@ +import { css } from '@emotion/react'; +import type { ButtonProps } from '../../../../components/Atoms/Button'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the Button component +const buttonStyleScript = (props: ButtonProps) => { + const variables = props?.theme?.variables; + const buttonDisabledSelectors = '&.ss__button--disabled'; + const buttonSelector = `&, &:hover, &:not(.ss__button--disabled):hover, ${buttonDisabledSelectors}`; + const buttonColor = new Color(props?.backgroundColor || variables?.colors?.primary || undefined); + const fontColor = buttonColor.isDark() || buttonColor.hex().toLowerCase() == '#00aeef' ? Color(custom.colors.white) : Color(custom.colors.black); + + // shared button styles + const disabledStyles = css({ + [buttonDisabledSelectors]: { + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }, + }); + + // default styles + const defaultStyles = css([ + { + boxSizing: 'border-box', + cursor: 'pointer', + display: 'inline-flex', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + position: 'relative', + padding: `0 ${custom.spacing.x4}px`, + color: fontColor.hex(), + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight01, + textAlign: 'center', + textTransform: custom.fonts.transform, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + [buttonSelector]: { + border: `1px solid ${buttonColor.hex()}`, + borderRadius: `${custom.sizes.radius}px`, + backgroundColor: buttonColor.hex(), + }, + '.ss__icon': { + width: `${custom.sizes.icon12}px`, + height: `${custom.sizes.icon12}px`, + flex: `0 0 ${custom.sizes.icon12}px`, + }, + '.ss__icon--filters': { + circle: { + fill: buttonColor.hex(), + }, + }, + }, + disabledStyles, + ]); + + return defaultStyles; +}; + +// Button component props +export const button: ThemeComponent<'button', ButtonProps> = { + default: { + button: { + themeStyleScript: buttonStyleScript, + native: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/dropdown.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/dropdown.ts new file mode 100644 index 000000000..93eed8788 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/dropdown.ts @@ -0,0 +1,40 @@ +import { css } from '@emotion/react'; +import type { DropdownProps } from '../../../../components/Atoms/Dropdown'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Dropdown component +const dropdownStyleScript = ({ theme }: DropdownProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = theme?.variables; + + return css({ + width: 'auto', + '&:not(.ss__facet__dropdown)': { + '&.ss__dropdown--open': { + '.ss__dropdown__content': { + zIndex: 200, + }, + }, + }, + '&.ss__dropdown--open': { + '.ss__dropdown__content': { + zIndex: 5, + }, + }, + '.ss__dropdown__content': { + minWidth: '1px', + left: 0, + right: 0, + zIndex: -1, + }, + }); +}; + +// Dropdown component props +export const dropdown: ThemeComponent<'dropdown', DropdownProps> = { + default: { + dropdown: { + themeStyleScript: dropdownStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/icon.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/icon.ts new file mode 100644 index 000000000..851bb434a --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/icon.ts @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; +import type { IconProps } from '../../../../components/Atoms/Icon'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Icon component +const iconStyleScript = (props: IconProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + fill: 'currentColor', + stroke: 'currentColor', + }); +}; + +// Icon component props +export const icon: ThemeComponent<'icon', IconProps> = { + default: { + icon: { + themeStyleScript: iconStyleScript, + size: `${custom.sizes.icon16}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/image.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/image.ts new file mode 100644 index 000000000..defdd577c --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/image.ts @@ -0,0 +1,46 @@ +import { css } from '@emotion/react'; +import type { ImageProps } from '../../../../components/Atoms/Image'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Image component +const imageStyleScript = (props: ImageProps & { visibility: React.CSSProperties['visibility'] }) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '&.ss__result__image': { + position: 'relative', + lineHeight: 0, + height: 0, + padding: '0 0 100% 0', + overflow: 'hidden', + '&, img': { + display: 'block', + }, + img: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + width: '100%', + height: '100%', + maxWidth: '100%', + maxHeight: '100%', + border: 0, + objectFit: 'contain', + objectPosition: 'center center', + }, + }, + }); +}; + +// Image component props +export const image: ThemeComponent<'image', ImageProps> = { + default: { + image: { + themeStyleScript: imageStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/index.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/index.ts new file mode 100644 index 000000000..0c9983f79 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/index.ts @@ -0,0 +1,69 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// ATOMS Imports +import { breadcrumbs } from './breadcrumbs'; +import { button } from './button'; +import { dropdown } from './dropdown'; +import { icon } from './icon'; +import { image } from './image'; +import { loadingBar } from './loadingBar'; +import { overlay } from './overlay'; +import { paginationInfo } from './paginationInfo'; +import { price } from './price'; +import { searchHeader } from './searchHeader'; +import { skeleton } from './skeleton'; + +export const atoms: ThemeResponsiveComplete = { + default: { + ...breadcrumbs.default, + ...button.default, + ...dropdown.default, + ...icon.default, + ...image.default, + ...loadingBar.default, + ...overlay.default, + ...price.default, + ...searchHeader.default, + ...skeleton.default, + ...paginationInfo.default, + }, + mobile: { + ...breadcrumbs.mobile, + ...button.mobile, + ...dropdown.mobile, + ...icon.mobile, + ...image.mobile, + ...loadingBar.mobile, + ...overlay.mobile, + ...price.mobile, + ...searchHeader.mobile, + ...skeleton.mobile, + ...paginationInfo.mobile, + }, + tablet: { + ...breadcrumbs.tablet, + ...button.tablet, + ...dropdown.tablet, + ...icon.tablet, + ...image.tablet, + ...loadingBar.tablet, + ...overlay.tablet, + ...price.tablet, + ...searchHeader.tablet, + ...skeleton.tablet, + ...paginationInfo.tablet, + }, + desktop: { + ...breadcrumbs.desktop, + ...button.desktop, + ...dropdown.desktop, + ...icon.desktop, + ...image.desktop, + ...loadingBar.desktop, + ...overlay.desktop, + ...price.desktop, + ...searchHeader.desktop, + ...skeleton.desktop, + ...paginationInfo.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/loadingBar.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/loadingBar.ts new file mode 100644 index 000000000..750f1917b --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/loadingBar.ts @@ -0,0 +1,24 @@ +import { css } from '@emotion/react'; +import type { LoadingBarProps } from '../../../../components/Atoms/Loading'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the LoadingBar component +const loadingBarStyleScript = (props: LoadingBarProps) => { + const variables = props?.theme?.variables; + + return css({ + background: variables?.colors?.primary, + '.ss__loading-bar__bar': { + background: variables?.colors?.secondary, + }, + }); +}; + +// LoadingBar component props +export const loadingBar: ThemeComponent<'loadingBar', LoadingBarProps> = { + default: { + loadingBar: { + themeStyleScript: loadingBarStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/overlay.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/overlay.ts new file mode 100644 index 000000000..fbdce2654 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/overlay.ts @@ -0,0 +1,24 @@ +import { css } from '@emotion/react'; +import type { OverlayProps } from '../../../../components/Atoms/Overlay'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Overlay component +const overlayStyleScript = (props: OverlayProps) => { + const backgroundColor = props?.color || 'rgba(0, 0, 0, 0.80)'; + + return css({ + cursor: 'pointer', + '&, &.ss__overlay--active': { + background: backgroundColor, + }, + }); +}; + +// Overlay component props +export const overlay: ThemeComponent<'overlay', OverlayProps> = { + default: { + overlay: { + themeStyleScript: overlayStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/paginationInfo.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/paginationInfo.ts new file mode 100644 index 000000000..020e34110 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/paginationInfo.ts @@ -0,0 +1,23 @@ +import { css } from '@emotion/react'; +import type { PaginationInfoProps } from '../../../../components/Atoms/PaginationInfo'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Pagination component +const paginationInfoStyleScript = ({ theme }: PaginationInfoProps) => { + const variables = theme?.variables; + + return css({ + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }); +}; + +// PaginationInfo component props +export const paginationInfo: ThemeComponent<'paginationInfo', PaginationInfoProps> = { + default: { + paginationInfo: { + themeStyleScript: paginationInfoStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/price.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/price.ts new file mode 100644 index 000000000..32bb151d0 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/price.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { PriceProps } from '../../../../components/Atoms/Price'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Price component +const priceStyleScript = (props: PriceProps) => { + const variables = props?.theme?.variables; + + return css({ + '&, span, &.ss__price, &.ss__price--strike': { + color: variables?.colors?.text, + }, + '& ~ .ss__result__price': { + paddingLeft: `${custom.spacing.x1 / 2}px`, + }, + }); +}; + +// Price component props +export const price: ThemeComponent<'price', PriceProps> = { + default: { + price: { + themeStyleScript: priceStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/searchHeader.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/searchHeader.ts new file mode 100644 index 000000000..d72852e4e --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/searchHeader.ts @@ -0,0 +1,42 @@ +import { css } from '@emotion/react'; +import type { SearchHeaderProps } from '../../../../components/Atoms/SearchHeader'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the SearchHeader component +const searchHeaderStyleScript = (props: SearchHeaderProps) => { + const variables = props?.theme?.variables; + + return css({ + em: { + fontStyle: 'normal', + }, + '.ss__search-header__title': { + margin: 0, + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__search-header__subtitle': { + margin: `${custom.spacing.x2}px 0 0 0`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: 400, + color: variables?.colors?.text, + a: { + color: variables?.colors?.secondary, + }, + }, + '.ss__search-header__results-query': { + color: variables?.colors?.primary, + }, + }); +}; + +// SearchHeader component props +export const searchHeader: ThemeComponent<'searchHeader', SearchHeaderProps> = { + default: { + searchHeader: { + themeStyleScript: searchHeaderStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/atoms/skeleton.ts b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/skeleton.ts new file mode 100644 index 000000000..62b806141 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/atoms/skeleton.ts @@ -0,0 +1,13 @@ +import type { SkeletonProps } from '../../../../components/Atoms/Skeleton'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// Skeleton component props +export const skeleton: ThemeComponent<'skeleton', SkeletonProps> = { + default: { + skeleton: { + backgroundColor: custom.colors.gray02, + animatedColor: custom.colors.gray01, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/index.ts b/packages/snap-preact/components/src/themes/matterhorn/components/index.ts new file mode 100644 index 000000000..b431ef8ce --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/index.ts @@ -0,0 +1,34 @@ +import { atoms } from './atoms'; +import { molecules } from './molecules'; +import { organisms } from './organisms'; +import { templates } from './templates'; + +import type { ThemeComponentsRestricted } from '../../../providers'; + +export const components: ThemeComponentsRestricted = { + ...atoms.default, + ...molecules.default, + ...organisms.default, + ...templates.default, +}; + +export const mobileComponents: ThemeComponentsRestricted = { + ...atoms.mobile, + ...molecules.mobile, + ...organisms.mobile, + ...templates.mobile, +}; + +export const tabletComponents: ThemeComponentsRestricted = { + ...atoms.tablet, + ...molecules.tablet, + ...organisms.tablet, + ...templates.tablet, +}; + +export const desktopComponents: ThemeComponentsRestricted = { + ...atoms.desktop, + ...molecules.desktop, + ...organisms.desktop, + ...templates.desktop, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/calloutBadge.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/calloutBadge.ts new file mode 100644 index 000000000..367766c73 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/calloutBadge.ts @@ -0,0 +1,31 @@ +import { css } from '@emotion/react'; +import type { CalloutBadgeProps } from '../../../../components/Molecules/CalloutBadge'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const calloutBadgeStyleScript = () => { + return css({ + gap: `${custom.spacing.x2}px`, + '& > div': { + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + lineHeight: 1, + span: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + '.ss__badge-text': { + padding: `0`, + }, + }); +}; + +// CalloutBadge component props +export const calloutBadge: ThemeComponent<'calloutBadge', CalloutBadgeProps> = { + default: { + calloutBadge: { + themeStyleScript: calloutBadgeStyleScript, + limit: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/carousel.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/carousel.ts new file mode 100644 index 000000000..c1b097655 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/carousel.ts @@ -0,0 +1,119 @@ +import { css } from '@emotion/react'; +import type { CarouselProps } from '../../../../components/Molecules/Carousel'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Carousel component +const carouselStyleScript = (props: CarouselProps) => { + const variables = props?.theme?.variables; + + // shared button styles + const disabledStyles = css({ + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }); + + return css({ + position: 'relative', + '.ss__carousel__prev-wrapper--hidden > div, .ss__carousel__next-wrapper--hidden > div': { + ...disabledStyles, + }, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + width: '32px', + height: '32px', + display: 'block', + position: 'absolute', + top: 0, + bottom: '22%', + zIndex: 2, + margin: 'auto', + '& > div': { + display: 'flex', + flexFlow: 'column nowrap', + alignItems: 'center', + justifyContent: 'center', + padding: 0, + width: '100%', + height: '100%', + lineHeight: 1, + backgroundColor: variables?.colors?.primary, + color: custom.colors.white, + }, + '.swiper-button-disabled': { + ...disabledStyles, + }, + }, + '.ss__carousel__prev-wrapper': { + left: 0, + }, + '.ss__carousel__next-wrapper': { + right: 0, + }, + '.swiper-container': { + margin: '0 auto', + '&:has(.swiper-pagination)': { + paddingBottom: `${custom.spacing.x5}px`, + }, + '& > .swiper-wrapper': { + '& > .swiper-slide': { + '& > *, .ss__result': { + padding: 0, + margin: 0, + width: 'auto', + height: '100%', + }, + }, + }, + '& > .swiper-pagination': { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + '.swiper-pagination-bullet': { + margin: `0 ${custom.spacing.x1 / 2}px`, + width: '12px', + height: '12px', + minWidth: '1px', + flex: '0 1 auto', + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + opacity: 1, + }, + '.swiper-pagination-bullet-active': { + backgroundColor: variables?.colors?.primary, + borderColor: variables?.colors?.primary, + }, + }, + }, + '.swiper-grid-column': { + '& > .swiper-wrapper': { + flexFlow: 'row wrap', + '& > .swiper-slide': { + height: 'auto !important', + marginTop: '0 !important', + marginBottom: `${custom.spacing.x4}px`, + }, + }, + }, + }); +}; + +// Carousel component props +export const carousel: ThemeComponent<'carousel', CarouselProps> = { + default: { + carousel: { + themeStyleScript: carouselStyleScript, + }, + 'carousel icon.prev': { + icon: custom.icons.arrowLeft, + size: `${custom.sizes.icon12}px`, + }, + 'carousel icon.next': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/checkbox.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/checkbox.ts new file mode 100644 index 000000000..c195b8fdf --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/checkbox.ts @@ -0,0 +1,81 @@ +import { css } from '@emotion/react'; +import type { CheckboxProps } from '../../../../components/Molecules/Checkbox'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Checkbox component +const checkboxStyleScript = (props: CheckboxProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + // shared checkbox styles + const sharedStyles = css({ + position: 'relative', + top: '-1px', + }); + const sharedDefaultStyles = css({ + border: `1px solid ${custom.colors.gray02}`, + '&, *': { + boxSizing: 'border-box', + }, + '.ss__icon': { + width: '8px', + height: '8px', + }, + '&.ss__checkbox--active': { + borderColor: darkGray, + '.ss__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }); + const disabledStyles = css({ + '&.ss__checkbox--disabled': { + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }, + }); + + // default checkbox styles + const defaultStyles = css([ + sharedStyles, + sharedDefaultStyles, + { + backgroundColor: custom.colors.gray01, + }, + disabledStyles, + ]); + + // native checkbox styles + const nativeStyles = css([ + sharedStyles, + { + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + border: `1px solid ${custom.colors.gray02}`, + cursor: 'pointer', + }, + disabledStyles, + ]); + + // return checkbox styles + if (props?.native) { + return nativeStyles; + } else { + return defaultStyles; + } +}; + +// Checkbox component props +export const checkbox: ThemeComponent<'checkbox', CheckboxProps> = { + default: { + checkbox: { + themeStyleScript: checkboxStyleScript, + icon: custom.icons.check, + size: `${custom.sizes.icon16}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/errorHandler.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/errorHandler.ts new file mode 100644 index 000000000..c66af2df3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/errorHandler.ts @@ -0,0 +1,40 @@ +import { css } from '@emotion/react'; +import type { ErrorHandlerProps } from '../../../../components/Molecules/ErrorHandler'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the ErrorHandler component +const errorHandlerStyleScript = (props: ErrorHandlerProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__error-handler__message': { + display: 'block', + flex: `1 1 0%`, + color: variables?.colors?.text, + '.ss__icon': { + position: 'relative', + top: '2px', + }, + }, + '.ss__error-handler__button': { + gap: 0, + flex: `0 1 auto`, + padding: `0 ${custom.spacing.x1}px`, + height: '25px', + lineHeight: '25px', + }, + }); +}; + +// ErrorHandler component props +export const errorHandler: ThemeComponent<'errorHandler', ErrorHandlerProps> = { + default: { + errorHandler: { + themeStyleScript: errorHandlerStyleScript, + }, + 'errorHandler icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetGridOptions.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetGridOptions.ts new file mode 100644 index 000000000..301f495d5 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetGridOptions.ts @@ -0,0 +1,76 @@ +import { css } from '@emotion/react'; +import type { FacetGridOptionsProps } from '../../../../components/Molecules/FacetGridOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the FacetGridOptions component +const facetGridOptionsStyleScript = (props: FacetGridOptionsProps) => { + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const fontColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#00aeef' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + const gridSize = props?.gridSize ? props.gridSize : '52px'; + + return css({ + gridTemplateColumns: `repeat(auto-fill, minmax(${gridSize}, 1fr))`, + gap: props?.gapSize ? props.gapSize : custom.spacing.x1, + alignItems: 'center', + '.ss__facet-grid-options__option': { + position: 'relative', + height: '100%', + aspectRatio: 1, + border: 0, + color: variables?.colors?.text, + '&, &:after, .ss__facet-grid-options__option__value': { + boxSizing: 'border-box', + }, + '&:after, .ss__facet-grid-options__option__value': { + display: 'block', + }, + '&:after': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 1, + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + }, + '.ss__facet-grid-options__option__value': { + position: 'relative', + zIndex: 2, + maxWidth: `calc(100% - ${custom.spacing.x2}px)`, + maxHeight: `calc(100% - ${custom.spacing.x2}px)`, + overflow: 'hidden', + '&, &.ss__facet-grid-options__option__value--smaller': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1, + }, + }, + }, + '.ss__facet-grid-options__option.ss__facet-grid-options__option--filtered': { + fontWeight: custom.fonts.weight01, + color: fontColor.hex(), + '&:after': { + backgroundColor: activeColor.hex(), + borderColor: activeColor.hex(), + }, + }, + }); +}; + +// FacetGridOptions component props +export const facetGridOptions: ThemeComponent<'facetGridOptions', FacetGridOptionsProps> = { + default: { + facetGridOptions: { + themeStyleScript: facetGridOptionsStyleScript, + gridSize: '52px', + gapSize: `${custom.spacing.x1}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetHierarchyOptions.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetHierarchyOptions.ts new file mode 100644 index 000000000..13419c29d --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetHierarchyOptions.ts @@ -0,0 +1,64 @@ +import { css } from '@emotion/react'; +import type { FacetHierarchyOptionsProps } from '../../../../components/Molecules/FacetHierarchyOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FacetHierarchyOptions component +const facetHierarchyOptionsStyleScript = (props: FacetHierarchyOptionsProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + + return css({ + '.ss__facet-hierarchy-options__option': { + display: 'block', + margin: `0 0 ${custom.spacing.x1}px 0`, + padding: 0, + color: variables?.colors?.text, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__facet-hierarchy-options__option__value': { + margin: 0, + '.ss__facet-hierarchy-options__option__value__count': { + position: 'relative', + top: '-1px', + margin: 0, + padding: `0 ${custom.spacing.x1}px`, + fontSize: custom.utils.convertPxToEm(10), + color: lightGray, + }, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--return': { + '&:before': { + display: 'none', + }, + '.ss__icon': { + position: 'relative', + top: '1px', + margin: `0 ${custom.spacing.x1}px 0 0`, + padding: 0, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--filtered': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '& ~ .ss__facet-hierarchy-options__option:not(.ss__facet-hierarchy-options__option--filtered)': { + paddingLeft: `${custom.spacing.x6}px`, + }, + }, + }); +}; + +// FacetHierarchyOptions component props +export const facetHierarchyOptions: ThemeComponent<'facetHierarchyOptions', FacetHierarchyOptionsProps> = { + default: { + facetHierarchyOptions: { + themeStyleScript: facetHierarchyOptionsStyleScript, + returnIcon: custom.icons.arrowLeft, + }, + 'facetHierarchyOptions icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetListOptions.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetListOptions.ts new file mode 100644 index 000000000..e42c39a96 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetListOptions.ts @@ -0,0 +1,54 @@ +import { css } from '@emotion/react'; +import type { FacetListOptionsProps } from '../../../../components/Molecules/FacetListOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FacetListOptions component +const facetListOptionsStyleScript = (props: FacetListOptionsProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const checkboxSpacing = custom.sizes.icon16 + custom.spacing.x2; + + return css({ + '.ss__facet-list-options__option': { + display: 'block', + position: 'relative', + margin: `0 0 ${custom.spacing.x1}px 0`, + color: variables?.colors?.text, + padding: props?.hideCheckbox ? `` : `0 0 0 ${checkboxSpacing}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__checkbox, .ss__radio': { + position: 'absolute', + top: '1.5px', + left: 0, + }, + '.ss__facet-list-options__option__value': { + margin: 0, + '.ss__facet-list-options__option__value__count': { + position: 'relative', + top: '-1px', + margin: 0, + padding: `0 ${custom.spacing.x1}px`, + fontSize: custom.utils.convertPxToEm(10), + color: lightGray, + }, + }, + }, + '.ss__facet-list-options__option.ss__facet-list-options__option--filtered': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }); +}; + +// FacetListOptions component props +export const facetListOptions: ThemeComponent<'facetListOptions', FacetListOptionsProps> = { + default: { + facetListOptions: { + themeStyleScript: facetListOptionsStyleScript, + respectSingleSelect: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetPaletteOptions.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetPaletteOptions.ts new file mode 100644 index 000000000..405114def --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetPaletteOptions.ts @@ -0,0 +1,211 @@ +import { css } from '@emotion/react'; +import type { FacetPaletteOptionsProps } from '../../../../components/Molecules/FacetPaletteOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FacetPaletteOptions component +const facetPaletteStyleScript = (props: FacetPaletteOptionsProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const hasCheckbox = !props?.hideCheckbox ? true : false; + + // set details for radius + const radius = 0; + const radiusUnit = 'px'; + const paletteRadius = radius ? `${radius}${radiusUnit}` : `0`; + + // determine inner border width + let innerBorder = 5; + if (props?.layout == 'list') { + innerBorder = hasCheckbox ? 2 : 3; + } + + // shared palette styles + const sharedStyles = css({ + '.ss__facet-palette-options__option': { + display: 'block', + color: variables?.colors?.text, + '&, &.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper': { + border: 0, + borderRadius: 0, + padding: 0, + }, + }, + '&.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper .ss__facet-palette-options__option__palette': { + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + }, + }, + '.ss__facet-palette-options__option__wrapper': { + overflow: 'hidden', + '.ss__facet-palette-options__option__palette': { + border: 0, + padding: 0, + '&, &:before, &:after': { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + borderRadius: paletteRadius, + boxSizing: 'border-box', + }, + '&:before, &:after': { + content: '""', + display: 'block', + }, + '&:before': { + border: `${innerBorder}px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + }, + }, + '.ss__facet-palette-options__option__value__count': { + position: 'relative', + top: props?.layout == 'list' ? '-1px' : '', + padding: props?.layout == 'list' ? `0 ${custom.spacing.x1}px` : ``, + fontSize: custom.utils.convertPxToEm(10), + color: lightGray, + }, + }, + }); + + // grid palette styles + const gridStyles = css([ + sharedStyles, + { + gridTemplateColumns: `repeat(auto-fill, minmax(${props?.gridSize ? props.gridSize : '52px'}, 1fr))`, + gap: props?.gapSize ? props.gapSize : custom.spacing.x1, + alignItems: 'center', + '.ss__facet-palette-options__option': { + textAlign: 'center', + '&, &.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper': { + position: 'relative', + height: 0, + padding: '0 0 100% 0', + }, + }, + '.ss__checkbox, .ss__radio': { + display: 'none', + }, + '.ss__facet-palette-options__option__value, .ss__facet-palette-options__option__value__count': { + display: 'block', + lineHeight: '0.85rem', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + '.ss__facet-palette-options__option__value': { + fontSize: custom.utils.convertPxToEm(12), + overflow: 'hidden', + margin: `${custom.spacing.x1}px 0 0 0`, + }, + '.ss__facet-palette-options__option__value__count': { + margin: `${custom.spacing.x1 / 2}px 0 0 0`, + }, + }, + }, + ]); + + // list variables + const listSize = hasCheckbox ? 16 : 22; + const listCheckboxSize = 16; + const listPadding = hasCheckbox ? custom.spacing.x4 + listSize + listCheckboxSize : custom.spacing.x2 + listSize; + + // list palette styles + const listStyles = css([ + sharedStyles, + { + '&.ss__facet-palette-options--list': { + display: 'block', + }, + '.ss__facet-palette-options__option': { + position: 'relative', + padding: `${hasCheckbox ? 0 : '2px'} 0 0 ${listPadding}px`, + margin: `0 0 ${custom.spacing.x1}px 0`, + minHeight: hasCheckbox ? '' : `${listSize + 2}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__checkbox, .ss__radio, .ss__facet-palette-options__option__wrapper': { + position: 'absolute', + top: `${hasCheckbox ? 2 : 0.5}px`, + }, + '.ss__checkbox, .ss__radio': { + left: 0, + }, + '.ss__facet-palette-options__option__wrapper': { + left: hasCheckbox ? `${listCheckboxSize + custom.spacing.x2}px` : 0, + width: `${listSize}px`, + height: `${listSize}px`, + lineHeight: `${listSize}px`, + }, + '.ss__facet-palette-options__option__value, .ss__facet-palette-options__option__value__count': { + display: 'inline', + overflow: 'visible', + textOverflow: 'unset', + textAlign: 'left', + whiteSpace: 'unset', + }, + '.ss__facet-palette-options__option__value__count': { + margin: 0, + }, + }, + }, + ]); + + return props?.layout == 'list' ? listStyles : gridStyles; +}; + +// FacetPaletteOptions component props +export const facetPaletteOptions: ThemeComponent<'facetPaletteOptions', FacetPaletteOptionsProps> = { + default: { + facetPaletteOptions: { + themeStyleScript: facetPaletteStyleScript, + hideIcon: true, + gridSize: '52px', + gapSize: `${custom.spacing.x1}px`, + colorMapping: { + brown: { + background: custom.colors.brown, + }, + multi: { + background: custom.colors.rainbow, + }, + 'multi-color': { + background: custom.colors.rainbow, + }, + purple: { + background: custom.colors.purple, + }, + rainbow: { + background: custom.colors.rainbow, + }, + }, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetSlider.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetSlider.ts new file mode 100644 index 000000000..5c8f9b4f0 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/facetSlider.ts @@ -0,0 +1,200 @@ +import { css } from '@emotion/react'; +import type { FacetSliderProps } from '../../../../components/Molecules/FacetSlider'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the FacetSlider component +const facetSliderStyleScript = (props: FacetSliderProps) => { + // slider options + const slider = { + handles: 20, // handle size + values: 14, // values size + bar: 6, // bar size + ticks: 17, // size of ticks + valuesPosition: 'top', // position of slider values (top or bottom) + valuesAlign: 'sides', // alignment of slider values (sides or center) + }; + + const variables = props?.theme?.variables; + const fontColor = props?.valueTextColor || variables?.colors?.text; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + const valuesTop = slider.valuesPosition == 'top' ? true : false; + const valuesSides = slider.valuesAlign == 'sides' ? true : false; + const hasTicks = props?.showTicks ? true : false; + const hasStickyHandles = props?.stickyHandleLabel ? true : false; + const handleColor = new Color(props?.handleColor || variables?.colors?.primary || undefined); + const handleInnerColor = + handleColor.isDark() || handleColor.hex().toLowerCase() == '#00aeef' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + + // values font styles + const valuesStyles = css({ + fontSize: custom.utils.convertPxToEm(slider.values), + lineHeight: `${slider.values}px`, + color: fontColor, + }); + + // shared slider styles + const sharedStyles = css({ + '&, *': { + boxSizing: 'border-box', + }, + '&, .ss__facet-slider__slider': { + margin: 'auto', + }, + '.ss__facet-slider__slider button, .ss__facet-slider__labels label': { + margin: 0, + padding: 0, + '&:focus': { + outline: 0, + }, + }, + '.ss__facet-slider__slider': { + display: 'block', + top: 0, + width: '100%', + height: `${slider.bar}px`, + '.ss__facet-slider__segment, .ss__facet-slider__rail, .ss__facet-slider__handles': { + height: '100%', + }, + '.ss__facet-slider__tick': { + '&:before, .ss__facet-slider__tick__label': { + transform: 'translate(-50%, 0)', + }, + '&:before': { + top: `${slider.ticks / 2}px`, + backgroundColor: darkGray, + }, + '.ss__facet-slider__tick__label': { + top: `${slider.ticks}px`, + color: props?.tickTextColor || variables?.colors?.text, + lineHeight: 1, + }, + }, + '.ss__facet-slider__segment': { + backgroundColor: props?.trackColor || custom.colors.gray01, + border: `1px solid ${props?.trackColor || custom.colors.gray02}`, + borderRadius: `${slider.bar}px`, + }, + '.ss__facet-slider__rail': { + backgroundColor: props?.railColor || variables?.colors?.secondary, + border: `1px solid ${props?.railColor || variables?.colors?.secondary}`, + }, + '.ss__facet-slider__handles': { + position: 'relative', + margin: `0 ${slider.handles / 2 - 2}px`, + button: { + '.ss__facet-slider__handle': { + transform: 'none', + width: `${slider.handles}px`, + height: `${slider.handles}px`, + lineHeight: `${slider.handles}px`, + backgroundColor: handleColor.hex(), + border: `1px solid ${handleColor.hex()}`, + '&:after': { + width: `${slider.handles / 4}px`, + height: `${slider.handles / 4}px`, + backgroundColor: handleInnerColor.hex(), + border: `1px solid ${handleInnerColor.hex()}`, + }, + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + backgroundColor: 'transparent', + '&': { + ...valuesStyles, + }, + }, + }, + }, + }, + }, + '.ss__facet-slider__labels': { + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + justifyContent: valuesSides ? '' : 'center', + '.ss__facet-slider__label': { + '&': { + ...valuesStyles, + }, + '&:after': { + display: valuesSides ? 'none' : '', + padding: `0 ${custom.spacing.x1}px`, + }, + '& ~ .ss__facet-slider__label': { + marginLeft: valuesSides ? 'auto' : '', + }, + }, + }, + }); + + // spacing and size calculations + const handlesSizeHalf = (slider.handles - slider.bar) / 2; + const handlesSpacing = slider.handles + custom.spacing.x2; + const ticksSpacing = slider.ticks + custom.spacing.x1; + const stickySpacing = slider.values + custom.spacing.x2; + const handlesPlusSticky = handlesSizeHalf + stickySpacing; + const ticksPlusSticky = ticksSpacing + stickySpacing; + + // spacing styles for different configurations + // note: default for facet slider is no ticks, no stick handles, values bottom + let spacingStyles = css({}); + + if (hasTicks && hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${valuesTop ? handlesPlusSticky : handlesSizeHalf}px auto ${valuesTop ? ticksSpacing : ticksPlusSticky}px auto`, + '.ss__facet-slider__handles button .ss__facet-slider__handle': { + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + top: valuesTop ? `auto` : `${handlesSizeHalf + ticksPlusSticky - slider.bar}px`, + bottom: valuesTop ? `${handlesSpacing}px` : ``, + }, + }, + }, + }); + } else if (hasTicks && !hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${handlesSizeHalf}px auto ${ticksSpacing}px auto`, + }, + '.ss__facet-slider__labels': { + order: valuesTop ? -1 : '', + margin: `${valuesTop ? 0 : custom.spacing.x2}px 0 ${valuesTop ? custom.spacing.x2 : 0}px 0`, + }, + }); + } else if (!hasTicks && hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${valuesTop ? handlesPlusSticky : handlesSizeHalf}px auto ${valuesTop ? handlesSizeHalf : handlesPlusSticky}px auto`, + '.ss__facet-slider__handles button .ss__facet-slider__handle': { + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + top: valuesTop ? 'auto' : `${handlesSpacing}px`, + bottom: valuesTop ? `${handlesSpacing}px` : ``, + }, + }, + }, + }); + } else { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${handlesSizeHalf}px auto`, + }, + '.ss__facet-slider__labels': { + order: valuesTop ? -1 : '', + margin: `${valuesTop ? 0 : custom.spacing.x2}px 0 ${valuesTop ? custom.spacing.x2 : 0}px 0`, + }, + }); + } + + return css([sharedStyles, spacingStyles]); +}; + +// FacetSlider component props +export const facetSlider: ThemeComponent<'facetSlider', FacetSliderProps> = { + default: { + facetSlider: { + themeStyleScript: facetSliderStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/filter.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/filter.ts new file mode 100644 index 000000000..15aede8a4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/filter.ts @@ -0,0 +1,44 @@ +import { css } from '@emotion/react'; +import type { FilterProps } from '../../../../components/Molecules/Filter'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Filter component +const filterStyleScript = (props: FilterProps) => { + const variables = props?.theme?.variables; + + return css({ + display: 'block', + padding: 0, + '.ss__filter__button': { + position: 'relative', + height: 'auto', + lineHeight: 1.5, + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + fontWeight: 'normal', + color: variables?.colors?.text, + '&, &:hover, &:not(.ss__button--disabled):hover, &.ss__button--disabled': { + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + }, + '.ss__button__content': { + '.ss__filter__label': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + }); +}; + +// Filter component props +export const filter: ThemeComponent<'filter', FilterProps> = { + default: { + filter: { + themeStyleScript: filterStyleScript, + icon: custom.icons.close, + }, + 'filter icon': { + size: `${custom.sizes.icon10}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/grid.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/grid.ts new file mode 100644 index 000000000..0b5e93f74 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/grid.ts @@ -0,0 +1,188 @@ +import { css } from '@emotion/react'; +import type { GridProps } from '../../../../components/Molecules/Grid'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// grid size +const gridSize = 42; + +// CSS in JS style script for the Grid component +const gridStyleScript = (props: Partial) => { + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const fontColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#00aeef' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + return css({ + '.ss__grid__title': { + margin: `0 0 ${custom.spacing.x1}px 0`, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + lineHeight: 1, + }, + '.ss__grid__options': { + display: 'flex', + flexFlow: 'row wrap', + gap: props?.gapSize ? props.gapSize : custom.spacing.x1, + alignItems: 'center', + '&:before, &:after': { + display: 'none', + }, + '.ss__grid__option': { + flex: '0 1 auto', + minWidth: '1px', + '&, &.ss__grid__option--selected': { + border: 0, + }, + '.ss__grid__option__inner .ss__grid__option__label, .ss__grid__show-more-wrapper': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1, + }, + }, + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + position: 'relative', + width: `${gridSize}px`, + maxHeight: `${gridSize}px`, + aspectRatio: 1, + color: variables?.colors?.text, + overflow: 'hidden', + '&, &:after, *': { + boxSizing: 'border-box', + }, + '&:before': { + display: 'none', + }, + '&:after': { + content: '""', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 1, + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&.ss__grid__option--dark, &:has(.ss__grid__option__inner--grey)': { + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + color: fontColor.hex(), + }, + }, + }, + '&.ss__grid__option--selected': { + '&:after': { + opacity: 0.3, + }, + '&:has(.ss__grid__option__inner:not([style]))': { + backgroundColor: activeColor.hex(), + '&:after': { + borderColor: activeColor.hex(), + opacity: 1, + }, + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + color: fontColor.hex(), + }, + }, + }, + '&:has(.ss__grid__option__inner .ss__image)': { + backgroundColor: 'transparent', + '&:after': { + borderColor: custom.colors.black, + opacity: 0.3, + }, + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + color: variables?.colors?.text, + }, + }, + }, + '.ss__grid__option__inner': { + '.ss__grid__option__label': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + '&.ss__grid__option--disabled, &.ss__grid__option--unavailable': { + opacity: 1, + cursor: 'not-allowed', + pointerEvents: 'none', + '.ss__grid__option__inner:after': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 3, + margin: 'auto', + backgroundColor: darkGray.replace('#', ''), + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center center', + backgroundImage: `url("data:image/svg+xml,%3Csvg style=%27transform: rotate%28-45deg%29%27 xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 56 56%27 preserveAspectRatio=%27xMinYMid%27%3E%3Cpath fill=%27%23${darkGray.replace( + '#', + '' + )}%27 d=%27M0 23.297h56v9.406h-56v-9.406z%27 /%3E%3C/svg%3E")`, + }, + }, + '.ss__grid__option__inner': { + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + '.ss__grid__option__label': { + display: 'block', + position: 'absolute', + zIndex: 2, + maxWidth: `calc(100% - ${custom.spacing.x2}px)`, + maxHeight: `calc(100% - ${custom.spacing.x2}px)`, + overflow: 'hidden', + }, + }, + }, + '.ss__grid__show-more-wrapper': { + maxHeight: 'none', + }, + }, + '.ss__grid__show-more-wrapper': { + '&:not(.ss__grid__option)': { + margin: `${custom.spacing.x2}px 0 0 0`, + }, + '&, .ss__grid__show-more': { + cursor: 'pointer', + }, + '.ss__grid__show-more': { + fontSize: custom.utils.convertPxToEm(12), + fontWeight: custom.fonts.weight01, + lineHeight: 1, + color: variables?.colors?.primary, + }, + }, + }); +}; + +// Grid component props +export const grid: ThemeComponent<'grid', GridProps> = { + default: { + grid: { + themeStyleScript: gridStyleScript, + gapSize: `${custom.spacing.x1}px`, + hideLabels: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/index.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/index.ts new file mode 100644 index 000000000..870baa582 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/index.ts @@ -0,0 +1,144 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// MOLECULES Imports +import { calloutBadge } from './calloutBadge'; +import { carousel } from './carousel'; +import { checkbox } from './checkbox'; +import { errorHandler } from './errorHandler'; +import { facetGridOptions } from './facetGridOptions'; +import { facetHierarchyOptions } from './facetHierarchyOptions'; +import { facetListOptions } from './facetListOptions'; +import { facetPaletteOptions } from './facetPaletteOptions'; +import { facetSlider } from './facetSlider'; +import { filter } from './filter'; +import { grid } from './grid'; +import { layoutSelector } from './layoutSelector'; +import { list } from './list'; +import { loadMore } from './loadMore'; +import { overlayBadge } from './overlayBadge'; +import { pagination } from './pagination'; +import { radio } from './radio'; +import { radioList } from './radioList'; +import { result } from './result'; +import { searchInput } from './searchInput'; +import { select } from './select'; +import { slideout } from './slideout'; +import { rating } from './rating'; +import { swatches } from './swatches'; +import { variantSelection } from './variantSelection'; +import { terms } from './terms'; + +export const molecules: ThemeResponsiveComplete = { + default: { + ...carousel.default, + ...checkbox.default, + ...errorHandler.default, + ...facetGridOptions.default, + ...facetHierarchyOptions.default, + ...facetListOptions.default, + ...facetPaletteOptions.default, + ...facetSlider.default, + ...filter.default, + ...grid.default, + ...layoutSelector.default, + ...list.default, + ...loadMore.default, + ...overlayBadge.default, + ...pagination.default, + ...radio.default, + ...radioList.default, + ...result.default, + ...searchInput.default, + ...select.default, + ...slideout.default, + ...rating.default, + ...swatches.default, + ...variantSelection.default, + ...terms.default, + ...calloutBadge.default, + }, + mobile: { + ...carousel.mobile, + ...checkbox.mobile, + ...errorHandler.mobile, + ...facetGridOptions.mobile, + ...facetHierarchyOptions.mobile, + ...facetListOptions.mobile, + ...facetPaletteOptions.mobile, + ...facetSlider.mobile, + ...filter.mobile, + ...grid.mobile, + ...layoutSelector.mobile, + ...list.mobile, + ...loadMore.mobile, + ...overlayBadge.mobile, + ...pagination.mobile, + ...radio.mobile, + ...radioList.mobile, + ...result.mobile, + ...searchInput.mobile, + ...select.mobile, + ...slideout.mobile, + ...rating.mobile, + ...swatches.mobile, + ...variantSelection.mobile, + ...terms.mobile, + ...calloutBadge.mobile, + }, + tablet: { + ...carousel.tablet, + ...checkbox.tablet, + ...errorHandler.tablet, + ...facetGridOptions.tablet, + ...facetHierarchyOptions.tablet, + ...facetListOptions.tablet, + ...facetPaletteOptions.tablet, + ...facetSlider.tablet, + ...filter.tablet, + ...grid.tablet, + ...layoutSelector.tablet, + ...list.tablet, + ...loadMore.tablet, + ...overlayBadge.tablet, + ...pagination.tablet, + ...radio.tablet, + ...radioList.tablet, + ...result.tablet, + ...searchInput.tablet, + ...select.tablet, + ...slideout.tablet, + ...rating.tablet, + ...swatches.tablet, + ...variantSelection.tablet, + ...terms.tablet, + ...calloutBadge.tablet, + }, + desktop: { + ...carousel.desktop, + ...checkbox.desktop, + ...errorHandler.desktop, + ...facetGridOptions.desktop, + ...facetHierarchyOptions.desktop, + ...facetListOptions.desktop, + ...facetPaletteOptions.desktop, + ...facetSlider.desktop, + ...filter.desktop, + ...grid.desktop, + ...layoutSelector.desktop, + ...list.desktop, + ...loadMore.desktop, + ...overlayBadge.desktop, + ...pagination.desktop, + ...radio.desktop, + ...radioList.desktop, + ...result.desktop, + ...searchInput.desktop, + ...select.desktop, + ...slideout.desktop, + ...rating.desktop, + ...swatches.desktop, + ...variantSelection.desktop, + ...terms.desktop, + ...calloutBadge.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/layoutSelector.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/layoutSelector.ts new file mode 100644 index 000000000..07b7cf775 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/layoutSelector.ts @@ -0,0 +1,76 @@ +import { css } from '@emotion/react'; +import type { LayoutSelectorProps } from '../../../../components/Molecules/LayoutSelector'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the LayoutSelector component +const layoutSelectorStyleScript = (props: LayoutSelectorProps) => { + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const activeIconColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#00aeef' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + + // dropdown styles + const dropdownStyles = css({ + '.ss__dropdown': { + '.ss__dropdown__button .ss__button__content': { + gap: `${custom.spacing.x2}px`, + }, + }, + }); + + // list styles + const listStyles = css({ + '.ss__list__options': { + display: 'flex', + '.ss__list__option': { + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + padding: `0 ${custom.spacing.x2}px`, + margin: 0, + }, + '.ss__list__option--selected': { + borderColor: activeColor.hex(), + backgroundColor: activeColor.hex(), + color: activeIconColor.hex(), + '&, *': { + cursor: 'text', + }, + }, + }, + }); + + if (props?.type == 'dropdown') { + return dropdownStyles; + } else if (props?.type == 'list') { + return listStyles; + } else { + return dropdownStyles; + } +}; + +// LayoutSelector component props +export const layoutSelector: ThemeComponent<'layoutSelector', LayoutSelectorProps> = { + default: { + layoutSelector: { + themeStyleScript: layoutSelectorStyleScript, + type: 'list', + }, + 'layoutSelector select': { + hideSelection: false, + separator: '', + }, + 'layoutSelector list': { + hideTitleText: true, + hideOptionLabels: true, + }, + 'layoutSelector radioList': { + hideTitleText: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/list.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/list.ts new file mode 100644 index 000000000..1ea3e1484 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/list.ts @@ -0,0 +1,45 @@ +import { css } from '@emotion/react'; +import type { ListProps } from '../../../../components/Molecules/List'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the List component +const listStyleScript = (props: ListProps) => { + const variables = props?.theme?.variables; + + return css({ + '&, .ss__list__options': { + display: 'block', + }, + '.ss__list__title, .ss__list__options .ss__list__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + }, + '.ss__list__title': { + display: 'block', + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + lineHeight: 1, + }, + '.ss__list__options': { + '.ss__list__option': { + gap: `${custom.spacing.x2}px`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__list__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }, + }); +}; + +// List component props +export const list: ThemeComponent<'list', ListProps> = { + default: { + list: { + themeStyleScript: listStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/loadMore.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/loadMore.ts new file mode 100644 index 000000000..3da120d93 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/loadMore.ts @@ -0,0 +1,53 @@ +import { css } from '@emotion/react'; +import type { LoadMoreProps } from '../../../../components/Molecules/LoadMore'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// CSS in JS style script for the LoadMore component +const loadMoreStyleScript = (props: LoadMoreProps) => { + const variables = props?.theme?.variables; + const indicatorColor = new Color(props?.backgroundColor || custom.colors.gray01 || undefined); + const indicatorBorderColor = new Color(props?.backgroundColor || custom.colors.gray02 || undefined); + const barColor = new Color(props?.color || variables?.colors?.primary || undefined); + + return css({ + '&.ss__load-more': { + '&, .ss__load-more__progress': { + gap: `${custom.spacing.x2}px`, + }, + '& > .ss__load-more__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + '.ss__button': { + '.ss__button__content': { + display: 'flex', + alignItems: 'center', + }, + }, + '.ss__load-more__progress': { + '.ss__load-more__progress__indicator': { + backgroundColor: indicatorColor.hex(), + border: `1px solid ${indicatorBorderColor}`, + '.ss__load-more__progress__indicator__bar': { + backgroundColor: barColor.hex(), + margin: '-1px', + }, + }, + '.ss__load-more__progress__text': { + color: variables?.colors?.text, + }, + }, + }, + }); +}; + +// LoadMore component props +export const loadMore: ThemeComponent<'loadMore', LoadMoreProps> = { + default: { + loadMore: { + themeStyleScript: loadMoreStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/overlayBadge.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/overlayBadge.ts new file mode 100644 index 000000000..4f5fce065 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/overlayBadge.ts @@ -0,0 +1,34 @@ +import { css } from '@emotion/react'; +import type { OverlayBadgeProps } from '../../../../components/Molecules/OverlayBadge'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const overlayBadgeStyleScript = () => { + return css({ + '.ss__overlay-badge__grid-wrapper': { + gap: `${custom.spacing.x1}px`, + bottom: 'auto', + '.ss__overlay-badge__grid-wrapper__slot': { + gap: 0, + '& > div': { + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + lineHeight: 1, + span: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }); +}; + +// OverlayBadge component props +export const overlayBadge: ThemeComponent<'overlayBadge', OverlayBadgeProps> = { + default: { + overlayBadge: { + themeStyleScript: overlayBadgeStyleScript, + limit: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/pagination.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/pagination.ts new file mode 100644 index 000000000..855be34e3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/pagination.ts @@ -0,0 +1,73 @@ +import { css } from '@emotion/react'; +import type { PaginationProps } from '../../../../components/Molecules/Pagination'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Pagination component +const paginationStyleScript = (props: PaginationProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + nav: { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + justifyContent: 'center', + lineHeight: 1, + '.ss__pagination__page, span': { + padding: `0 ${custom.spacing.x1}px`, + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.text, + }, + '.ss__pagination__page': { + minWidth: '1px', + minHeight: '1px', + }, + '.ss__pagination__page--active': { + color: variables?.colors?.primary, + }, + '.ss__pagination__page--previous, .ss__pagination__page--next': { + lineHeight: `${custom.sizes.icon12}px`, + '.ss__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + nav: { + '.ss__pagination__page, span': { + padding: `0 ${custom.spacing.x2}px`, + fontSize: custom.utils.convertPxToEm(16), + }, + '.ss__pagination__page--previous, .ss__pagination__page--next': { + lineHeight: `${custom.sizes.icon14}px`, + }, + }, + }, + }); +}; + +// Pagination component props +export const pagination: ThemeComponent<'pagination', PaginationProps> = { + default: { + pagination: { + themeStyleScript: paginationStyleScript, + }, + 'pagination icon': { + size: `${custom.sizes.icon12}px`, + }, + 'pagination icon.prev': { + icon: custom.icons.arrowLeft, + }, + 'pagination icon.next': { + icon: custom.icons.arrowRight, + }, + }, + mobile: { + 'pagination icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/radio.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/radio.ts new file mode 100644 index 000000000..46a2b5147 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/radio.ts @@ -0,0 +1,81 @@ +import { css } from '@emotion/react'; +import type { RadioProps } from '../../../../components/Molecules/Radio'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Radio component +const radioStyleScript = (props: RadioProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + // shared radio styles + const sharedDefaultStyles = css({ + border: `1px solid ${custom.colors.gray02}`, + '&, & .ss__icon': { + borderRadius: '50%', + }, + '.ss__icon': { + display: 'none', + }, + '&.ss__radio--active': { + borderColor: darkGray, + '.ss__icon': { + display: 'block', + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }); + const disabledStyles = css({ + '&.ss__radio--disabled': { + opacity: 0.65, + '&, & *': { + cursor: 'not-allowed', + }, + }, + }); + + // default radio styles + const defaultStyles = css([ + sharedDefaultStyles, + { + backgroundColor: custom.colors.gray01, + }, + disabledStyles, + ]); + + // native radio styles + const nativeStyles = css([ + { + lineHeight: 0, + '.ss__radio__input': { + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + border: `1px solid ${custom.colors.gray02}`, + cursor: 'pointer', + }, + }, + disabledStyles, + ]); + + // return radio styles + if (props?.native) { + return nativeStyles; + } else { + return defaultStyles; + } +}; + +// Radio component props +export const radio: ThemeComponent<'radio', RadioProps> = { + default: { + radio: { + themeStyleScript: radioStyleScript, + size: `${custom.sizes.icon14}px`, + }, + 'radio icon': { + icon: 'square', + size: `${custom.sizes.icon10 - 2}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/radioList.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/radioList.ts new file mode 100644 index 000000000..0aa063233 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/radioList.ts @@ -0,0 +1,47 @@ +import { css } from '@emotion/react'; +import type { RadioListProps } from '../../../../components/Molecules/RadioList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RadioList component +const radioListStyleScript = (props: RadioListProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__radio-list__title, .ss__radio-list__options-wrapper .ss__radio-list__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + }, + '.ss__radio-list__title': { + display: 'block', + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + lineHeight: 1, + }, + '.ss__radio-list__options-wrapper': { + '.ss__radio-list__option': { + gap: `${custom.spacing.x2}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__radio-list__option__icon, .ss__radio-list__option__label': { + padding: 0, + }, + }, + '.ss__radio-list__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }, + }); +}; + +// RadioList component props +export const radioList: ThemeComponent<'radioList', RadioListProps> = { + default: { + radioList: { + themeStyleScript: radioListStyleScript, + hideOptionLabels: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/rating.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/rating.ts new file mode 100644 index 000000000..1371653fe --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/rating.ts @@ -0,0 +1,54 @@ +import { css } from '@emotion/react'; +import type { RatingProps } from '../../../../components/Molecules/Rating'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Rating component +const ratingStyleScript = (props: RatingProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + return css({ + flexWrap: 'wrap', + gap: `${custom.spacing.x1}px`, + lineHeight: 1, + '.ss__rating__icons': { + '.ss__rating__stars': { + margin: '0 -1px', + '.ss__rating__stars__star': { + margin: '0 1px', + }, + }, + '.ss__rating__stars--empty': { + '.ss__rating__stars__star .ss__icon': { + fill: darkGray, + stroke: darkGray, + }, + }, + '.ss__rating__stars--full': { + '.ss__rating__stars__star .ss__icon': { + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + }, + '.ss__rating__count, .ss__rating__text': { + fontSize: custom.utils.convertPxToEm(12), + color: variables?.colors?.text, + }, + }); +}; + +// Rating component props +export const rating: ThemeComponent<'rating', RatingProps> = { + default: { + rating: { + themeStyleScript: ratingStyleScript, + emptyIcon: 'star', + fullIcon: 'star', + }, + 'rating icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/result.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/result.ts new file mode 100644 index 000000000..5a4071925 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/result.ts @@ -0,0 +1,123 @@ +import { css } from '@emotion/react'; +import type { ResultProps } from '../../../../components/Molecules/Result'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Result component +const resultStyleScript = (props: ResultProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + + return css({ + '&.ss__result--sale': { + '.ss__result__details': { + '.ss__result__details__pricing': { + '.ss__result__price:not(.ss__price--strike)': { + '&, span': { + color: variables?.colors?.primary, + }, + }, + }, + }, + }, + '&.ss__result--grid': { + display: 'block', + }, + '&.ss__result--list': { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + '.ss__result__image-wrapper, .ss__result__details': { + minWidth: '1px', + }, + '.ss__result__image-wrapper': { + flex: '0 0 33.33%', + margin: `0 ${custom.spacing.x4}px 0 0`, + }, + '.ss__result__details': { + flex: '1 1 0%', + textAlign: 'left', + margin: 0, + '.ss__callout-badge, .ss__result__rating-wrapper': { + justifyContent: 'flex-start', + }, + '.ss__result__details__title': { + flex: '1 1 0%', + a: { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + }, + }, + '.ss__result__details__pricing': { + flex: '0 1 auto', + order: -1, + }, + }, + }, + '.ss__result__image-wrapper': { + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + '.ss__result__details': { + padding: 0, + display: 'flex', + flexFlow: 'row wrap', + gap: `${custom.spacing.x2}px`, + '& > *, .ss__result__details__title, .ss__result__details__title, .ss__result__details__pricing': { + margin: 0, + }, + '& > *': { + minWidth: '1px', + flex: '1 1 100%', + }, + '.ss__result__details__title': { + order: -2, + a: { + color: variables?.colors?.text, + }, + }, + '.ss__result__details__pricing': { + '.ss__result__price': { + fontSize: custom.utils.convertPxToEm(16), + '&:not(.ss__price--strike)': { + fontWeight: custom.fonts.weight01, + }, + }, + '.ss__price--strike': { + fontSize: custom.utils.convertPxToEm(14), + '&, span': { + color: lightGray, + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '&.ss__result--list': { + display: 'block', + '.ss__result__details': { + textAlign: 'center', + '.ss__callout-badge, .ss__result__rating-wrapper': { + justifyContent: 'center', + }, + '.ss__result__details__title, .ss__result__details__pricing': { + flex: '1 1 100%', + }, + '.ss__result__details__pricing': { + order: 0, + }, + }, + '.ss__result__image-wrapper': { + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + }, + }, + }); +}; + +// Result component props +export const result: ThemeComponent<'result', ResultProps> = { + default: { + result: { + themeStyleScript: resultStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/searchInput.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/searchInput.ts new file mode 100644 index 000000000..8ae4ecfd1 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/searchInput.ts @@ -0,0 +1,91 @@ +import { css } from '@emotion/react'; +import type { SearchInputProps } from '../../../../components/Molecules/SearchInput'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the SearchInput component +const searchInputStyleScript = (props: SearchInputProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const darkPrimary = custom.utils.darkenColor(variables?.colors?.primary, 0.15); + + return css({ + '&.ss__search-input': { + margin: `0 0 ${custom.spacing.x2}px`, + border: 0, + height: '35px', + '& > *': { + minWidth: '1px', + }, + '.ss__search-input__input, .ss__search-input__icons, .ss__button': { + height: '100%', + lineHeight: 1, + }, + '.ss__search-input__icons, .ss__search-input__button--close-search-button': { + flex: '0 1 auto', + }, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '35px', + boxSizing: 'border-box', + justifyContent: 'center', + '&, &:hover': { + border: 0, + }, + '&, .ss__icon': { + padding: 0, + }, + '.ss__icon': { + fill: custom.colors.white, + stroke: custom.colors.white, + }, + }, + '.ss__search-input__input': { + flex: '1 1 0%', + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + padding: `0 ${custom.spacing.x2}px`, + minHeight: '1px', + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.text, + '&::-webkit-input-placeholder': { + color: lightGray, + }, + '&::-ms-input-placeholder': { + color: lightGray, + }, + '&::placeholder': { + color: lightGray, + }, + }, + '.ss__search-input__icons': { + gap: '1px', + margin: '0 0 0 -1px', + backgroundColor: darkPrimary, + }, + '.ss__search-input__button--close-search-button': { + margin: '0 -1px 0 0', + }, + }, + }); +}; + +// SearchInput component props +export const searchInput: ThemeComponent<'searchInput', SearchInputProps> = { + default: { + searchInput: { + themeStyleScript: searchInputStyleScript, + }, + 'searchInput icon': { + size: `${custom.sizes.icon14}px`, + }, + 'searchInput button.close-search icon': { + icon: custom.icons.arrowLeft, + }, + 'searchInput button.clear-search icon': { + icon: custom.icons.close, + }, + 'searchInput button.submit-search icon': { + icon: custom.icons.search, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/select.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/select.ts new file mode 100644 index 000000000..96d04d7a1 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/select.ts @@ -0,0 +1,149 @@ +import { css } from '@emotion/react'; +import type { SelectProps } from '../../../../components/Molecules/Select'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Select component +const selectStyleScript = (props: SelectProps) => { + const variables = props?.theme?.variables; + + // shared styles for select menus + const sharedStyles = css({ + border: `1px solid ${custom.colors.gray02}`, + color: variables?.colors?.text, + backgroundColor: custom.colors.gray01, + }); + + // default styles + const defaultStyles = css([ + { + display: 'block', + '.ss__dropdown': { + '.ss__dropdown__button .ss__button, .ss__dropdown__content .ss__select__select': { + ...sharedStyles, + }, + '.ss__dropdown__button': { + '.ss__button': { + display: 'flex', + padding: `0 ${custom.spacing.x2}px`, + textAlign: 'left', + '.ss__button__content': { + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__select__selection__icon': { + margin: 0, + }, + '.ss__select__selection': { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + fontWeight: 'normal', + }, + '.ss__select__dropdown__button__icon': { + transition: 'transform ease 0.5s', + }, + }, + }, + }, + '.ss__dropdown__content': { + marginTop: `${custom.spacing.x2}px`, + '.ss__select__select': { + padding: `${custom.spacing.x2}px`, + margin: 0, + '.ss__select__select__option': { + gap: `${custom.spacing.x2}px`, + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + color: 'inherit', + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + backgroundColor: 'transparent', + }, + }, + '.ss__select__select__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + }, + }, + }, + '.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__button': { + '.ss__select__dropdown__button__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + }, + }, + ]); + + // native styles + const nativeStyles = css([ + sharedStyles, + { + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + padding: `0 ${custom.spacing.x2}px`, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__select__label, .ss__select__select': { + fontSize: custom.utils.convertPxToEm(14), + }, + '.ss__select__label': { + fontWeight: custom.fonts.weight01, + }, + '.ss__select__select': { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + backgroundColor: 'transparent', + border: 'none', + appearance: 'none', + color: 'inherit', + cursor: 'pointer', + '&[disabled]': { + cursor: 'not-allowed', + }, + '&::-ms-expand': { + display: 'none', + }, + }, + '.ss__select__dropdown__button__icon': { + width: `${custom.sizes.icon12}px`, + height: `${custom.sizes.icon12}px`, + }, + }, + ]); + + return props?.native ? nativeStyles : defaultStyles; +}; + +// Select component props +export const select: ThemeComponent<'select', SelectProps> = { + default: { + select: { + themeStyleScript: selectStyleScript, + iconOpen: custom.icons.arrowDown, + iconClose: custom.icons.arrowDown, + }, + 'select icon.open': { + size: `${custom.sizes.icon12}px`, + }, + 'select dropdown button': { + native: false, + }, + 'select dropdown button icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/slideout.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/slideout.ts new file mode 100644 index 000000000..ce31c4a0a --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/slideout.ts @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; +import type { SlideoutProps } from '../../../../components/Molecules/Slideout'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Slideout component +const slideoutStyleScript = (props: SlideoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({}); +}; + +// Slideout component props +export const slideout: ThemeComponent<'slideout', SlideoutProps> = { + default: { + slideout: { + themeStyleScript: slideoutStyleScript, + overlayColor: '', + }, + 'slideout button.slideout': { + icon: custom.icons.filter, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/swatches.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/swatches.ts new file mode 100644 index 000000000..8e7fd1c03 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/swatches.ts @@ -0,0 +1,249 @@ +import { css } from '@emotion/react'; +import type { SwatchesProps } from '../../../../components/Molecules/Swatches'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import Color from 'color'; + +// Swatch carousel sizes and spacing +const swatchSize = 30; +const swatchSpacing = custom.spacing.x1; + +// CSS in JS style script for the Swatches component +const swatchesStyleScript = (props: SwatchesProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const activeColor = new Color(variables?.colors?.primary || undefined); + const fontColor = + activeColor.isDark() || activeColor.hex().toLowerCase() == '#00aeef' + ? Color(custom.colors.white || undefined) + : Color(custom.colors.black || undefined); + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + + // shared styles for swatches + const sharedStyles = css({ + margin: 0, + }); + + // carousel styles + const carouselStyles = css([ + sharedStyles, + { + margin: 0, + '.ss__carousel': { + '& > div': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + position: 'static', + bottom: 0, + width: `${swatchSize}px`, + height: `${swatchSize}px`, + }, + '.ss__carousel__prev-wrapper': { + margin: `0 ${swatchSpacing}px 0 0`, + }, + '.ss__carousel__next-wrapper': { + margin: `0 0 0 ${swatchSpacing}px`, + }, + '.swiper-container': { + maxWidth: `calc(100% - ${swatchSize * 2 + swatchSpacing * 2}px)`, + '& > .swiper-wrapper': { + '& > .swiper-slide': { + overflow: 'hidden', + width: `${swatchSize}px`, + height: `${swatchSize}px`, + '&:has(.ss__swatches__carousel__swatch.ss__swatches__carousel__swatch--unavailable)': { + '&:before': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + margin: 'auto', + width: '100%', + height: '1px', + borderTop: `3px solid ${darkGray}`, + transform: 'rotate(-45deg)', + }, + }, + }, + }, + }, + '.swiper-container > .swiper-wrapper > .swiper-slide > *, .ss__swatches__carousel__swatch': { + height: `${swatchSize}px`, + lineHeight: 0, + border: 0, + }, + '.ss__swatches__carousel__swatch': { + position: 'relative', + aspectRatio: 1, + color: variables?.colors?.text, + overflow: 'hidden', + '&, &:before, &:after, *': { + boxSizing: 'border-box', + }, + '&:before, &:after': { + content: '""', + display: 'block', + width: 'auto', + height: 'auto', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + transform: 'none', + }, + '&:before': { + border: `3px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&.ss__swatches__carousel__swatch--dark, &:has(.ss__swatches__carousel__swatch__inner--grey)': { + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + color: fontColor.hex(), + }, + }, + }, + '&.ss__swatches__carousel__swatch--selected': { + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + '&:has(.ss__swatches__carousel__swatch__inner:not([style]))': { + backgroundColor: activeColor.hex(), + '&:after': { + borderColor: activeColor.hex(), + opacity: 1, + }, + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + color: fontColor.hex(), + }, + }, + }, + '&:has(.ss__swatches__carousel__swatch__inner .ss__image)': { + backgroundColor: 'transparent', + '&:after': { + borderColor: custom.colors.black, + opacity: 0.3, + }, + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + color: variables?.colors?.text, + }, + }, + }, + '.ss__swatches__carousel__swatch__inner': { + '.ss__swatches__carousel__swatch__value': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + '&.ss__swatches__carousel__swatch--disabled, &.ss__swatches__carousel__swatch--unavailable': { + opacity: 1, + cursor: 'not-allowed', + pointerEvents: 'none', + '.ss__swatches__carousel__swatch__inner:after': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 3, + margin: 'auto', + backgroundColor: darkGray.replace('#', ''), + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center center', + backgroundImage: `url("data:image/svg+xml,%3Csvg style=%27transform: rotate%28-45deg%29%27 xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 56 56%27 preserveAspectRatio=%27xMinYMid%27%3E%3Cpath fill=%27%23${darkGray.replace( + '#', + '' + )}%27 d=%27M0 23.297h56v9.406h-56v-9.406z%27 /%3E%3C/svg%3E")`, + }, + }, + '.ss__swatches__carousel__swatch__inner': { + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + '.ss__swatches__carousel__swatch__value': { + display: 'block', + position: 'absolute', + zIndex: 2, + maxWidth: `calc(100% - ${custom.spacing.x2}px)`, + maxHeight: `calc(100% - ${custom.spacing.x2}px)`, + overflow: 'hidden', + textAlign: 'center', + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1, + }, + }, + }, + }, + }, + ]); + + // grid styles + const gridStyles = css([ + sharedStyles, + { + '.ss__grid': { + '.ss__grid__options': { + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + width: `${swatchSize}px`, + maxHeight: `${swatchSize}px`, + }, + }, + }, + }, + ]); + + // return swatch styles + if (props?.type == 'grid') { + return gridStyles; + } else { + return carouselStyles; + } +}; + +// Swatches component props +export const swatches: ThemeComponent<'swatches', SwatchesProps> = { + default: { + swatches: { + themeStyleScript: swatchesStyleScript, + }, + 'swatches carousel': { + autoAdjustSlides: false, + centerInsufficientSlides: false, + slidesPerView: 'auto', + slidesPerGroup: 3, + spaceBetween: `${swatchSpacing}px`, + }, + }, + desktop: { + 'swatches carousel': { + slidesPerView: 'auto', + slidesPerGroup: 2, + spaceBetween: `${swatchSpacing}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/terms.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/terms.ts new file mode 100644 index 000000000..1edc387a2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/terms.ts @@ -0,0 +1,87 @@ +import { css } from '@emotion/react'; +import type { TermsProps } from '../../../../components/Molecules/Terms'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Terms component +const termsStyleScript = (props: TermsProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + return css({ + width: '100%', + textAlign: 'left', + 'ul, ul li': { + padding: 0, + margin: 0, + listStyle: 'none', + }, + '.ss__terms__title': { + '&, h5': { + padding: 0, + }, + h5: { + margin: `0 0 ${custom.spacing.x4}px 0`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + textTransform: custom.fonts.transform ? custom.fonts.transform : 'none', + color: variables?.colors?.secondary, + }, + }, + '.ss__terms__options': { + flexFlow: 'row wrap', + justifyContent: 'flex-start', + gap: `${custom.spacing.x1}px ${custom.spacing.x4}px`, + '&, .ss__terms__option': { + listStyle: 'none', + padding: 0, + }, + '.ss__terms__option': { + flex: '0 1 auto', + minWidth: '1px', + color: variables?.colors?.primary, + a: { + padding: 0, + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.primary, + em: { + color: variables?.colors?.text, + fontStyle: 'normal', + fontSize: 'inherit', + fontWeight: 'inherit', + }, + }, + }, + '.ss__terms__option--active': { + 'a, a em': { + fontWeight: custom?.fonts?.weight01, + color: variables?.colors?.primary, + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__terms__title': { + h5: { + fontSize: custom.utils.convertPxToEm(14), + }, + }, + '.ss__terms__options': { + '.ss__terms__option': { + a: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }); +}; + +// Terms component props +export const terms: ThemeComponent<'terms', TermsProps> = { + default: { + terms: { + themeStyleScript: termsStyleScript, + emIfy: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/molecules/variantSelection.ts b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/variantSelection.ts new file mode 100644 index 000000000..41509c306 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/molecules/variantSelection.ts @@ -0,0 +1,149 @@ +import { css } from '@emotion/react'; +import type { VariantSelectionProps } from '../../../../components/Molecules/VariantSelection'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Swatches component +const variantSelectionStyleScript = (props: VariantSelectionProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + + // shared styles for variant selections + const sharedStyles = css({ + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }); + + // dropdown styles + const dropdownStyles = css([ + sharedStyles, + { + '.ss__dropdown': { + '.ss__dropdown__button, .ss__dropdown__content': { + border: `1px solid ${custom.colors.gray02}`, + color: variables?.colors?.text, + backgroundColor: custom.colors.gray01, + }, + '.ss__dropdown__button': { + width: 'auto', + display: 'flex', + padding: `0 ${custom.spacing.x2}px`, + textAlign: 'left', + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__dropdown__button-wrapper': { + flex: '1 1 0%', + gap: `${custom.spacing.x1}px`, + paddingRight: `${custom.spacing.x1}px`, + fontWeight: 'normal', + '.ss__dropdown__button-wrapper__label': { + fontWeight: custom?.fonts?.weight01, + textTransform: 'capitalize', + }, + }, + '.ss__variant-selection__icon': { + transition: 'transform ease 0.5s', + }, + }, + '.ss__dropdown__content': { + marginTop: `-1px`, + padding: `${custom.spacing.x2}px`, + '.ss__variant-selection__options': { + '&, .ss__variant-selection__option': { + listStyle: 'none', + padding: 0, + margin: 0, + }, + '.ss__variant-selection__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + fontWeight: 'normal', + }, + }, + '.ss__variant-selection__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '.ss__variant-selection__option--unavailable': { + color: lightGray, + cursor: 'not-allowed', + }, + }, + }, + }, + '.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__variant-selection__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + }, + ]); + + // list styles + const listStyles = css([ + sharedStyles, + { + '.ss__list': { + '.ss__list__title, .ss__list__options, .ss__list__options .ss__list__option': { + width: '100%', + color: variables?.colors?.text, + }, + '.ss__list__title': { + textTransform: 'capitalize', + }, + '.ss__list__options': { + '.ss__list__option': { + label: { + color: 'inherit', + }, + }, + '.ss__list__option--selected': { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '.ss__list__option--unavailable': { + color: lightGray, + cursor: 'not-allowed', + textDecoration: 'line-through', + }, + }, + }, + }, + ]); + + // swatches syles + const swatchesStyles = css([sharedStyles]); + + // return variant selection styles + if (props?.type == 'list') { + return listStyles; + } else if (props?.type == 'swatches') { + return swatchesStyles; + } else { + return dropdownStyles; + } +}; + +// VariantSelection component props +export const variantSelection: ThemeComponent<'variantSelection', VariantSelectionProps> = { + default: { + variantSelection: { + themeStyleScript: variantSelectionStyleScript, + }, + 'variantSelection dropdown icon': { + size: `${custom.sizes.icon12}px`, + icon: custom.icons.arrowDown, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/autocomplete.ts new file mode 100644 index 000000000..a37374b5b --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/autocomplete.ts @@ -0,0 +1,392 @@ +import { css } from '@emotion/react'; +import type { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; + +// CSS in JS style script for the Autocomplete component +const autocompleteStyleScript = (props: AutocompleteProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const headerSelectors = + '.ss__autocomplete__terms .ss__autocomplete__title h5, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__header, .ss__autocomplete__content__results .ss__autocomplete__title h5, .ss__autocomplete__content__info a, .ss__no-results__recommendations h3'; + const activeSelectors = + '.ss__autocomplete__terms .ss__autocomplete__terms__options .ss__autocomplete__terms__option--active a, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__options .ss__facet-list-options .ss__facet-list-options__option--filtered, .ss__autocomplete__content__results .ss__results .ss__result:hover .ss__result__details .ss__result__details__title a, .ss__autocomplete__content__info a:hover'; + + return css({ + '&.ss__autocomplete': { + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.white, + width: props?.width, + right: 0, + left: 'auto', + top: 'auto', + margin: `${custom.spacing.x1}px 0 0 0`, + gap: `${custom.spacing.x4}px`, + 'a, div, p': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: 1.5, + color: variables?.colors?.text, + }, + a: { + display: 'block', + }, + '.ss__banner': { + img: { + maxWidth: '100%', + maxHeight: '150px', + height: 'auto', + }, + }, + [headerSelectors]: { + margin: `0 0 ${custom.spacing.x4}px 0`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + lineHeight: 1.2, + color: variables?.colors?.secondary, + }, + [activeSelectors]: { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '& > div': { + minWidth: '1px', + maxWidth: 'none', + flex: '0 1 auto', + padding: `${custom.spacing.x4}px 0`, + order: 0, + '&:first-of-type': { + paddingLeft: `${custom.spacing.x4}px`, + }, + '&:last-of-type': { + paddingRight: `${custom.spacing.x4}px`, + }, + '&.ss__autocomplete__terms': { + padding: 0, + }, + }, + '.ss__autocomplete__terms': { + width: '200px', + backgroundColor: custom.colors.gray01, + textAlign: 'left', + '& > div:first-of-type .ss__autocomplete__title': { + marginTop: `${custom.spacing.x2}px`, + }, + '& > div:last-of-type .ss__autocomplete__terms__options': { + marginBottom: `${custom.spacing.x2}px`, + }, + '& > div': { + '.ss__autocomplete__title': { + padding: 0, + h5: { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + }, + }, + '.ss__autocomplete__terms__options': { + '.ss__autocomplete__terms__option': { + a: { + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + fontSize: custom.utils.convertPxToEm(14), + color: variables?.colors?.primary, + em: { + color: variables?.colors?.text, + fontStyle: 'normal', + fontSize: 'inherit', + fontWeight: 'inherit', + }, + }, + }, + '.ss__autocomplete__terms__option--active': { + 'a, a em': { + fontWeight: custom?.fonts?.weight01, + color: variables?.colors?.primary, + }, + }, + }, + }, + }, + '.ss__autocomplete__facets': { + width: '200px', + textAlign: 'left', + '.ss__facets': { + '.ss__facet': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&.ss__facet--showing-all': { + '.ss__facet__options': { + maxHeight: 'none', + overflow: 'visible', + padding: 0, + }, + }, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__facet__header': { + borderBottom: 0, + padding: 0, + '.ss__facet__header__inner': { + fontSize: 'inherit', + fontWeight: 'inherit', + color: 'inherit', + }, + }, + '.ss__facet__options': { + margin: 0, + maxHeight: 'none', + overflow: 'visible', + '.ss__facet-hierarchy-options .ss__facet-hierarchy-options__option, .ss__facet-list-options .ss__facet-list-options__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__facet-list-options': { + '.ss__facet-list-options__option': {}, + }, + }, + }, + }, + }, + '.ss__autocomplete__content': { + flex: '1 1 0%', + overflow: 'visible', + justifyContent: 'flex-start', + }, + '.ss__autocomplete__content__results': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '.ss__results': { + overflowY: 'auto', + overflowX: 'hidden', + maxHeight: '75vh', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__result': { + '.ss__result__details': { + gap: `${custom.spacing.x1}px`, + '.ss__result__details__pricing': { + '.ss__result__price': { + fontSize: custom.utils.convertPxToEm(14), + }, + '.ss__price--strike': { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + '.ss__inline-banner': { + maxHeight: '250px', + overflow: 'hidden', + }, + }, + }, + '.ss__autocomplete__content__info': { + padding: 0, + a: { + margin: 0, + '.ss__icon': { + fill: 'currentColor', + stroke: 'currentColor', + }, + }, + }, + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + '.ss__no-results__recommendations': { + margin: `${custom.spacing.x4}px 0 0 0`, + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '&.ss__autocomplete': { + flexFlow: 'row wrap', + gap: 0, + width: props?.width, + left: 0, + right: 0, + [headerSelectors]: { + fontSize: custom.utils.convertPxToEm(14), + }, + '& > div': { + flex: '1 1 100%', + borderBottom: `1px solid ${custom.colors.gray02}`, + '&:last-of-type': { + borderBottomWidth: 0, + }, + '&, &.ss__autocomplete__terms': { + padding: `${custom.spacing.x4}px`, + }, + }, + '.ss__autocomplete__terms': { + backgroundColor: 'transparent', + display: 'flex', + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + width: 'auto', + '& > div': { + minWidth: '1px', + flex: '1 1 0%', + '&:first-of-type .ss__autocomplete__title': { + marginTop: 0, + }, + '&:last-of-type .ss__autocomplete__terms__options': { + marginBottom: 0, + }, + '.ss__autocomplete__title h5': { + padding: 0, + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__autocomplete__terms__options': { + gap: `${custom.spacing.x1}px ${custom.spacing.x4}px`, + flexFlow: 'row wrap', + justifyContent: 'flex-start', + '.ss__autocomplete__terms__option': { + flex: '0 1 auto', + a: { + padding: 0, + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }, + '.ss__autocomplete__terms > div .ss__autocomplete__terms__options, .ss__autocomplete__facets .ss__facets': { + display: 'flex', + }, + '.ss__autocomplete__terms > div .ss__autocomplete__terms__options, .ss__autocomplete__facets .ss__facets .ss__facet': { + minWidth: '1px', + }, + '.ss__autocomplete__facets': { + width: 'auto', + '.ss__facets': { + gap: `0 ${custom.spacing.x4}px`, + flexFlow: 'row nowrap', + '.ss__facet': { + flex: '1 1 0%', + '&, &:last-of-type': { + margin: 0, + }, + }, + }, + }, + '.ss__autocomplete__content__info': { + a: { + '.ss__icon': { + position: 'relative', + top: '1px', + }, + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '&.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__recommendation-grid__results': { + gridTemplateColumns: `repeat(2, 1fr)`, + '& > div:nth-of-type(n+3)': { + display: 'none', + }, + }, + }, + }, + }); +}; + +// Autocomplete component props +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + themeStyleScript: autocompleteStyleScript, + width: '900px', + }, + 'autocomplete facet': { + limit: 5, + disableOverflow: true, + disableCollapse: true, + }, + 'autocomplete facets': { + limit: 3, + }, + 'autocomplete facetListOptions': { + hideCheckbox: true, + }, + 'autocomplete facetPaletteOptions': { + gridSize: '38px', + hideLabel: false, + }, + 'autocomplete facetGridOptions': { + gridSize: '38px', + }, + 'autocomplete results': { + rows: 2, + columns: 3, + }, + 'autocomplete recommendationGrid': { + rows: 2, + columns: 4, + }, + 'autocomplete icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteThemeComponentProps.mobile, + autocomplete: { + width: '100%', + }, + 'autocomplete results': { + rows: 1, + columns: 3, + }, + 'autocomplete recommendationGrid': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteThemeComponentProps.tablet, + autocomplete: { + width: '100%', + }, + 'autocomplete results': { + rows: 1, + columns: 4, + }, + 'autocomplete recommendationGrid': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteThemeComponentProps.desktop, + autocomplete: {}, + 'autocomplete results': { + rows: 2, + columns: 3, + }, + 'autocomplete recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/autocompleteLayout.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/autocompleteLayout.ts new file mode 100644 index 000000000..c45578d69 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/autocompleteLayout.ts @@ -0,0 +1,451 @@ +import { css } from '@emotion/react'; +import type { AutocompleteLayoutProps } from '../../../../components/Organisms/AutocompleteLayout'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Autocomplete Layout component +const autocompleteLayoutStyleScript = (props: AutocompleteLayoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const textSelectors = 'a, div, p'; + const headerSelectors = + '.ss__terms-list .ss__terms .ss__terms__title h5, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__header, .ss__autocomplete__content .ss__autocomplete__content__results .ss__autocomplete__title h5, .ss__autocomplete__button--see-more .ss__button__content, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__title'; + const activeSelectors = + '.ss__terms-list .ss__terms .ss__terms__options .ss__terms__option.ss__terms__option--active a, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__options .ss__facet-list-options .ss__facet-list-options__option--filtered, .ss__autocomplete__content .ss__autocomplete__content__results .ss__results .ss__result:hover .ss__result__details .ss__result__details__title a, .ss__autocomplete__button--see-more:hover .ss__button__content'; + + // get autocomplete layout + const acLayout = props?.layout ? props.layout : 'standard'; + + // shared autocomplete styles + const sharedStyles = css({ + alignContent: acLayout == 'standard' ? 'normal' : 'flex-start', + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.white, + [textSelectors]: { + fontSize: custom.utils.convertPxToEm(acLayout == 'terms' ? 15 : 12), + lineHeight: 1.5, + color: variables?.colors?.text, + }, + a: { + display: 'block', + }, + 'ul, ul li': { + padding: 0, + margin: 0, + listStyle: 'none', + }, + '.ss__banner': { + img: { + maxWidth: '100%', + maxHeight: '150px', + height: 'auto', + }, + }, + [headerSelectors]: { + margin: `0 0 ${custom.spacing.x4}px 0`, + padding: 0, + fontSize: custom.utils.convertPxToEm(acLayout == 'terms' ? 17 : 16), + fontWeight: custom.fonts.weight02, + lineHeight: 1.2, + color: variables?.colors?.secondary, + }, + [activeSelectors]: { + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + }, + '.ss__autocomplete__row, .ss__autocomplete__column': { + '.ss__search-input': { + background: 'transparent', + width: 'auto', + height: '30px', + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + }, + '.ss__autocomplete__column': { + alignContent: 'flex-start', + minWidth: '1px', + }, + }); + const sharedTabletStyles = css({ + alignContent: 'flex-start', + [textSelectors]: { + fontSize: acLayout == 'terms' ? custom.utils.convertPxToEm(12) : '', + }, + [headerSelectors]: { + fontSize: custom.utils.convertPxToEm(14), + }, + }); + + // terms wrapper styles + const termsWrapperStyles = css({ + '.ss__autocomplete__terms-wrapper': { + backgroundColor: 'transparent', + padding: `${custom.spacing.x4}px`, + }, + }); + + // facets styles + const facetsStyles = css({ + '.ss__autocomplete__facets-wrapper': { + padding: `${custom.spacing.x4}px`, + }, + '.ss__autocomplete__facets': { + padding: 0, + '.ss__facets': { + '.ss__facet': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + '&.ss__facet--showing-all': { + '.ss__facet__options': { + maxHeight: 'none', + overflow: 'visible', + padding: 0, + }, + }, + '.ss__facet__header': { + borderBottom: 0, + '.ss__facet__header__inner': { + fontSize: 'inherit', + fontWeight: 'inherit', + color: 'inherit', + }, + }, + '.ss__facet__options': { + '.ss__facet-hierarchy-options .ss__facet-hierarchy-options__option, .ss__facet-list-options .ss__facet-list-options__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + }, + }, + }, + }); + + // content styles + const contentStyles = css({ + '.ss__autocomplete__column:has(.ss__autocomplete__content)': { + alignContent: 'flex-start', + }, + '.ss__autocomplete__content': { + overflow: 'visible', + justifyContent: 'flex-start', + padding: `${custom.spacing.x4}px`, + borderTop: `1px solid ${custom.colors.gray02}`, + '.ss__autocomplete__content-inner': { + padding: 0, + }, + }, + }); + + // results layout styles + const resultsLayoutStyles = css({ + gap: `${custom.spacing.x4}px`, + overflowY: 'auto', + overflowX: 'hidden', + maxHeight: '75vh', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__result': { + '.ss__result__details': { + gap: `${custom.spacing.x1}px`, + '.ss__result__details__pricing': { + '.ss__result__price': { + fontSize: custom.utils.convertPxToEm(14), + }, + '.ss__price--strike': { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + }, + }); + + // results styles + const resultsStyles = css({ + '.ss__autocomplete__content__results': { + '.ss__results': { + ...resultsLayoutStyles, + }, + }, + }); + + // no results styles + const noResultsStyles = css({ + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + '.ss__autocomplete__content__no-results__recommendations': { + '.ss__recommendation-grid': { + margin: `${custom.spacing.x4}px 0 0 0`, + }, + '.ss__recommendation-grid__title': { + textAlign: 'left', + }, + '.ss__recommendation-grid__results': { + ...resultsLayoutStyles, + }, + }, + }, + }); + + // see more styles + const seeMoreStyles = css({ + '.ss__autocomplete__button--see-more': { + padding: `${custom.spacing.x4}px`, + paddingTop: 0, + height: 'auto', + '&, &:hover': { + backgroundColor: 'transparent', + border: 0, + }, + '.ss__button__content': { + margin: 0, + '.ss__icon': { + position: 'relative', + top: '0.5px', + margin: `0 0 0 ${custom.spacing.x1}px`, + }, + }, + }, + }); + const seeMoreTabletStyles = css({ + order: -1, + textAlign: 'left', + '.ss__button__content': { + '.ss__icon': { + top: '1.5px', + }, + }, + }); + + // standard styles + const standardStyles = css([ + sharedStyles, + { + '.ss__autocomplete__column': { + '&:has(.ss__autocomplete__terms-wrapper)': { + flex: '1 0 200px', + maxWidth: '200px', + }, + '&:has(.ss__autocomplete__facets-wrapper)': { + flex: '1 0 200px', + maxWidth: '200px', + marginRight: `-${custom.spacing.x4}px`, + }, + }, + '.ss__autocomplete__terms-wrapper': { + backgroundColor: custom.colors.gray01, + height: '100%', + }, + '.ss__terms-list': { + display: 'block', + '.ss__terms-list__row': { + '&:first-of-type .ss__terms .ss__terms__title': { + marginTop: `${custom.spacing.x2}px`, + }, + '&:last-of-type .ss__terms .ss__terms__options': { + marginBottom: `${custom.spacing.x2}px`, + }, + }, + '.ss__terms': { + '.ss__terms__title': { + h5: { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + }, + }, + '.ss__terms__options': { + display: 'block', + margin: 0, + '.ss__terms__option': { + a: { + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + }, + }, + '.ss__terms__option--active': { + backgroundColor: custom.colors.white, + }, + }, + }, + }, + }, + facetsStyles, + contentStyles, + resultsStyles, + noResultsStyles, + seeMoreStyles, + { + [`@media (max-width: ${tabletBp}px)`]: { + '&': sharedTabletStyles, + '.ss__autocomplete__row:has(.ss__autocomplete__column)': { + display: 'block', + '.ss__autocomplete__column': { + width: '100%', + maxWidth: 'none', + }, + }, + '.ss__autocomplete__column': { + '&:has(.ss__autocomplete__facets-wrapper)': { + marginRight: 0, + }, + }, + '.ss__autocomplete__terms-wrapper': { + backgroundColor: 'transparent', + padding: `${custom.spacing.x4}px`, + }, + '.ss__terms-list': { + display: 'flex', + '.ss__terms-list__row': { + '&:first-of-type .ss__terms .ss__terms__title': { + marginTop: 0, + }, + '&:last-of-type .ss__terms .ss__terms__options': { + marginBottom: 0, + }, + }, + '.ss__terms': { + '.ss__terms__title': { + h5: { + padding: 0, + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + }, + '.ss__terms__options': { + display: 'flex', + '.ss__terms__option': { + a: { + padding: 0, + }, + }, + }, + }, + }, + '.ss__autocomplete__facets-wrapper': { + borderTop: `1px solid ${custom.colors.gray02}`, + }, + '.ss__autocomplete__facets': { + '.ss__facets': { + gap: `0 ${custom.spacing.x4}px`, + flexFlow: 'row nowrap', + minWidth: '1px', + '.ss__facet': { + flex: '1 1 0%', + minWidth: '1px', + '&, &:last-of-type': { + margin: 0, + }, + }, + }, + }, + '.ss__autocomplete__button--see-more': { + ...seeMoreTabletStyles, + }, + }, + }, + ]); + + // mini styles + const miniStyles = css([ + sharedStyles, + termsWrapperStyles, + contentStyles, + resultsStyles, + noResultsStyles, + seeMoreStyles, + { + [`@media (max-width: ${tabletBp}px)`]: { + '&': sharedTabletStyles, + '.ss__autocomplete__button--see-more': { + ...seeMoreTabletStyles, + }, + }, + }, + { + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + gridTemplateColumns: `repeat(2, 1fr)`, + }, + }, + }, + ]); + + // terms styles + const termsStyles = css([ + sharedStyles, + termsWrapperStyles, + contentStyles, + { + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + fontSize: custom.utils.convertPxToEm(14), + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + }, + }, + seeMoreStyles, + { + [`@media (max-width: ${tabletBp}px)`]: { + '&': sharedTabletStyles, + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + fontSize: custom.utils.convertPxToEm(12), + }, + }, + }, + '.ss__autocomplete__button--see-more': { + ...seeMoreTabletStyles, + }, + }, + }, + ]); + + // return autocomplete styles + if (acLayout == 'terms') { + return termsStyles; + } else if (acLayout == 'mini') { + return miniStyles; + } else { + return standardStyles; + } +}; + +// Autocomplete Layout component props +export const autocompleteLayout: ThemeComponent<'autocompleteLayout', AutocompleteLayoutProps> = { + default: { + autocompleteLayout: { + themeStyleScript: autocompleteLayoutStyleScript, + contentTitle: 'Product Suggestions', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facet.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facet.ts new file mode 100644 index 000000000..3108a816a --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facet.ts @@ -0,0 +1,80 @@ +import { css } from '@emotion/react'; +import type { FacetProps } from '../../../../components/Organisms/Facet'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Facet component +const facetStyleScript = (props: FacetProps) => { + const variables = props?.theme?.variables; + + return css({ + '&.ss__facet--collapsed': { + '.ss__facet__header': { + '.ss__icon': { + transform: 'rotate(0deg)', + }, + }, + }, + '&.ss__facet--showing-all': { + '.ss__facet__options': { + maxHeight: `490px`, + overflowY: 'auto', + overflowX: 'hidden', + paddingRight: `${custom.spacing.x2}px`, + }, + }, + '.ss__facet__header': { + gap: `${custom.spacing.x2}px`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + '.ss__icon': { + transition: 'transform ease 0.5s', + transform: 'rotate(180deg)', + width: `${custom.sizes.icon12}px`, + height: `${custom.sizes.icon12}px`, + fill: variables?.colors?.primary, + stroke: variables?.colors?.primary, + }, + }, + '.ss__facet__options': { + marginTop: 0, + maxHeight: 'none', + overflow: 'visible', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + }, + '.ss__facet__show-more-less': { + margin: `${custom.spacing.x2}px 0 0 0`, + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '.ss__icon': { + position: 'relative', + top: '-0.5px', + marginRight: `${custom.spacing.x1}px`, + width: `${custom.sizes.icon10}px`, + height: `${custom.sizes.icon10}px`, + }, + }, + }); +}; + +// Facet component props +export const facet: ThemeComponent<'facet', FacetProps> = { + default: { + facet: { + themeStyleScript: facetStyleScript, + iconCollapse: custom.icons.arrowDown, + iconExpand: custom.icons.arrowDown, + iconOverflowMore: custom.icons.plus, + iconOverflowLess: custom.icons.minus, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facets.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facets.ts new file mode 100644 index 000000000..ff933eb03 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facets.ts @@ -0,0 +1,25 @@ +import { css } from '@emotion/react'; +import type { FacetsProps } from '../../../../components/Organisms/Facets'; +import { ThemeComponent } from '../../../../providers'; + +// CSS in JS style script for the Facets component +const facetsStyleScript = (props: FacetsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '&.ss__facets': { + display: 'block', + width: 'auto', + }, + }); +}; + +// Facets component props +export const facets: ThemeComponent<'facets', FacetsProps> = { + default: { + facets: { + themeStyleScript: facetsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facetsHorizontal.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facetsHorizontal.ts new file mode 100644 index 000000000..ea6f24945 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/facetsHorizontal.ts @@ -0,0 +1,239 @@ +import { css } from '@emotion/react'; +import type { FacetsHorizontalProps } from '../../../../components/Organisms/FacetsHorizontal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Facets component +const facetsHorizontalStyleScript = (props: FacetsHorizontalProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const columnsSelector = `.ss__facet-hierarchy-options, .ss__facet-list-options, .ss__facet-palette-options.ss__facet-palette-options--list`; + + return css({ + margin: 0, + '.ss__facets-horizontal__header': { + gap: 0, + margin: `0 -${custom.spacing.x1}px -${custom.spacing.x2}px -${custom.spacing.x1}px `, + position: 'relative', + '& > *': { + boxSizing: 'border-box', + minWidth: '1px', + width: `${100 / 6}%`, + flex: '0 1 auto', + padding: `0 ${custom.spacing.x1}px`, + }, + '& > *, .ss__facets-horizontal__header__dropdown, .ss__mobile-sidebar': { + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + '.ss__facets-horizontal__header__dropdown': { + position: 'static', + '&.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__dropdown__button__heading': { + '.ss__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + '.ss__dropdown__content': { + width: 'auto', + minWidth: '1px', + maxHeight: 'none', + overflowY: 'visible', + padding: `${custom.spacing.x2}px`, + marginTop: `${custom.spacing.x2}px`, + left: `${custom.spacing.x1}px`, + right: `${custom.spacing.x1}px`, + }, + }, + '.ss__dropdown__button, .ss__dropdown__content': { + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.gray01, + }, + '.ss__dropdown__button': { + display: 'block', + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + padding: `0 ${custom.spacing.x2}px`, + textAlign: 'left', + color: variables?.colors?.text, + '.ss__dropdown__button__heading': { + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + gap: `${custom.spacing.x1}px`, + padding: 0, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + span: { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + fontWeight: custom.fonts.weight01, + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + '.ss__icon': { + transition: 'transform ease 0.5s', + }, + }, + }, + '.ss__dropdown__content': { + width: 'auto', + padding: `${custom.spacing.x2}px`, + [columnsSelector]: { + display: 'flex', + flexFlow: 'row wrap', + gap: `0 ${custom.spacing.x2}px`, + '& > *': { + flex: '0 1 auto', + width: `${100 / 4 - 2}%`, + minWidth: '1px', + boxSizing: 'border-box', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + }, + '.ss__checkbox, .ss__radio, .ss__search-input .ss__search-input__input': { + backgroundColor: custom.colors.white, + }, + '.ss__facet': { + margin: 0, + }, + '.ss__facet.ss__facet--showing-all .ss__facet__options': { + maxHeight: '360px', + }, + '.ss__facet-list-options': { + marginBottom: `-${custom.spacing.x1}px`, + '.ss__facet-list-options__option:last-of-type': { + marginBottom: `${custom.spacing.x1}px`, + }, + }, + '.ss__facet-hierarchy-options': { + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--filtered': { + '& ~ .ss__facet-hierarchy-options__option:not(.ss__facet-hierarchy-options__option--filtered)': { + paddingLeft: 0, + }, + }, + }, + '.ss__facet-grid-options': { + '.ss__facet-grid-options__option:not(.ss__facet-grid-options__option--filtered)': { + '&:after': { + backgroundColor: custom.colors.white, + }, + }, + }, + '.ss__facet--slider': { + '.ss__facet__options': { + display: 'flex', + minHeight: '100px', + '.ss__facet-slider': { + width: '100%', + }, + }, + }, + '.ss__facet__show-more-less': { + textAlign: 'center', + }, + }, + }, + '.ss__mobile-sidebar': { + '.ss__slideout__button .ss__button': { + display: 'flex', + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__facets-horizontal__header': { + '& > *': { + width: `${100 / 4}%`, + }, + '.ss__facets-horizontal__header__dropdown .ss__dropdown__content': { + [columnsSelector]: { + '& > *': { + width: `${100 / 3 - 2}%`, + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__facets-horizontal__header': { + '& > *': { + width: `${100 / 2}%`, + }, + '.ss__facets-horizontal__header__dropdown .ss__dropdown__content': { + [columnsSelector]: { + '& > *': { + width: `${100 / 2 - 2}%`, + }, + }, + }, + }, + }, + }); +}; + +// FacetsHorizontal component props +export const facetsHorizontal: ThemeComponent<'facetsHorizontal', FacetsHorizontalProps> = { + default: { + facetsHorizontal: { + themeStyleScript: facetsHorizontalStyleScript, + iconExpand: custom.icons.arrowDown, + iconCollapse: custom.icons.arrowDown, + alwaysShowFiltersButton: true, + }, + 'facetsHorizontal dropdown button icon': { + size: `${custom.sizes.icon12}px`, + }, + 'facetsHorizontal dropdown facet': { + statefulOverflow: true, + display: { + list: { + limit: 32, + }, + hierarchy: { + limit: 32, + }, + grid: { + limit: 34, + }, + palette: { + limit: 34, + }, + }, + }, + 'facetsHorizontal mobileSidebar facet': { + statefulOverflow: true, + display: { + list: { + limit: 10, + }, + hierarchy: { + limit: 10, + }, + grid: { + limit: 12, + }, + palette: { + limit: 12, + }, + }, + }, + 'facetsHorizontal facetGridOptions': { + gridSize: '62px', + }, + 'facetsHorizontal mobileSidebar facetGridOptions': { + gridSize: '52px', + }, + 'facetsHorizontal facetPaletteOptions': { + gridSize: '62px', + }, + 'facetsHorizontal mobileSidebar facetPaletteOptions': { + gridSize: '52px', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/filterSummary.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/filterSummary.ts new file mode 100644 index 000000000..7c60576c1 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/filterSummary.ts @@ -0,0 +1,90 @@ +import { css } from '@emotion/react'; +import type { FilterSummaryProps } from '../../../../components/Organisms/FilterSummary'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FilterSummary component +const filterSummaryStyleScript = (props: FilterSummaryProps) => { + const variables = props?.theme?.variables; + const darkGray = custom.utils.darkenColor(custom.colors.gray02, 0.075); + const listSpacing = custom.sizes.icon16 + custom.spacing.x2; + + // shared palette styles + const sharedStyles = css({ + '.ss__filter-summary__title': { + padding: 0, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__filter-summary__filters': { + margin: 0, + }, + }); + + // inline filter summary styles + const inlineStyles = css([ + sharedStyles, + { + '&.ss__filter-summary--inline': { + '.ss__filter-summary__filters': { + gap: `${custom.spacing.x1}px`, + }, + }, + }, + ]); + + // list filter summary styles + const listStyles = css([ + sharedStyles, + { + '&.ss__filter-summary--list': { + '.ss__filter-summary__filters': { + '.ss__filter': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__filter__button': { + '.ss__button__content': { + position: 'relative', + padding: `0 0 0 ${listSpacing}px`, + '.ss__filter__button__icon': { + position: 'absolute', + top: '1.5px', + left: 0, + padding: '3px', + backgroundColor: custom.colors.gray01, + border: `1px solid ${darkGray}`, + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + boxSizing: 'border-box', + }, + '.ss__filter__label, .ss__filter__value': { + margin: 0, + }, + '.ss__filter__label': { + padding: '0 4px 0 0', + }, + }, + }, + }, + }, + }, + }, + ]); + + return props?.type == 'list' ? listStyles : inlineStyles; +}; + +// FilterSummary component props +export const filterSummary: ThemeComponent<'filterSummary', FilterSummaryProps> = { + default: { + filterSummary: { + themeStyleScript: filterSummaryStyleScript, + clearAllIcon: custom.icons.close, + filterIcon: custom.icons.close, + hideTitle: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/index.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/index.ts new file mode 100644 index 000000000..11cfc74d3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/index.ts @@ -0,0 +1,74 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// ORGANISMS Imports +import { autocomplete } from './autocomplete'; +import { autocompleteLayout } from './autocompleteLayout'; +import { facet } from './facet'; +import { facets } from './facets'; +import { facetsHorizontal } from './facetsHorizontal'; +import { filterSummary } from './filterSummary'; +import { mobileSidebar } from './mobileSidebar'; +import { noResults } from './noResults'; +import { results } from './results'; +import { sidebar } from './sidebar'; +import { termsList } from './termsList'; +import { toolbar } from './toolbar'; + +export const organisms: ThemeResponsiveComplete = { + default: { + ...autocomplete.default, + ...autocompleteLayout.default, + ...facet.default, + ...facets.default, + ...facetsHorizontal.default, + ...filterSummary.default, + ...mobileSidebar.default, + ...noResults.default, + ...results.default, + ...sidebar.default, + ...toolbar.default, + ...termsList.default, + }, + mobile: { + ...autocomplete.mobile, + ...autocompleteLayout.mobile, + ...facet.mobile, + ...facets.mobile, + ...facetsHorizontal.mobile, + ...filterSummary.mobile, + ...mobileSidebar.mobile, + ...noResults.mobile, + ...results.mobile, + ...sidebar.mobile, + ...toolbar.mobile, + ...termsList.mobile, + }, + tablet: { + ...autocomplete.tablet, + ...autocompleteLayout.tablet, + ...facet.tablet, + ...facets.tablet, + ...facetsHorizontal.tablet, + ...filterSummary.tablet, + ...mobileSidebar.tablet, + ...noResults.tablet, + ...results.tablet, + ...sidebar.tablet, + ...toolbar.tablet, + ...termsList.tablet, + }, + desktop: { + ...autocomplete.desktop, + ...autocompleteLayout.desktop, + ...facet.desktop, + ...facets.desktop, + ...facetsHorizontal.desktop, + ...filterSummary.desktop, + ...mobileSidebar.desktop, + ...noResults.desktop, + ...results.desktop, + ...sidebar.desktop, + ...toolbar.desktop, + ...termsList.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/mobileSidebar.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/mobileSidebar.ts new file mode 100644 index 000000000..5ffe75c68 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/mobileSidebar.ts @@ -0,0 +1,130 @@ +import { css } from '@emotion/react'; +import type { MobileSidebarProps } from '../../../../components/Organisms/MobileSidebar'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the MobileSidebar component +const mobileSidebarStyleScript = (props: MobileSidebarProps) => { + const variables = props?.theme?.variables; + const headerHeight = 60; + const footerHeight = 75; + + return css({ + '.ss__mobile-sidebar__slideout': { + overflowY: 'hidden', + padding: 0, + width: '100%', + '.ss__mobile-sidebar__content': { + height: '100%', + '.ss__mobile-sidebar__header, .ss__mobile-sidebar__footer': { + padding: `0 ${custom.spacing.x4}px`, + gap: `${custom.spacing.x2}px`, + alignItems: 'center', + }, + '.ss__mobile-sidebar__header': { + height: `${headerHeight}px`, + backgroundColor: variables?.colors?.primary, + color: custom.colors.white, + '.ss__mobile-sidebar__header__title': { + margin: 0, + fontSize: custom.utils.convertPxToEm(18), + }, + '.ss__mobile-sidebar__header__close-button': { + padding: 0, + width: '16px', + height: '16px', + lineHeight: '16px', + '.ss__icon': { + width: '100%', + height: '100%', + lineHeight: 1, + }, + }, + }, + '.ss__mobile-sidebar__footer': { + height: `${footerHeight}px`, + backgroundColor: custom.colors.white, + borderTop: `1px solid ${custom.colors.gray02}`, + '.ss__button': { + flex: `1 1 0%`, + }, + }, + '.ss__mobile-sidebar__inner': { + height: `calc(100% - ${headerHeight + footerHeight}px)`, + overflowY: 'auto', + overflowX: 'hidden', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__layout': { + overflow: 'hidden', + display: 'block', + '& > *': { + borderBottom: `1px solid ${custom.colors.gray02}`, + padding: `${custom.spacing.x4}px`, + '&:last-of-type': { + borderBottomWidth: 0, + }, + }, + }, + '.ss__select--native': { + padding: `0 ${custom.spacing.x4}px`, + borderTop: 0, + height: '40px', + lineHeight: '40px', + }, + '.ss__filter-summary, .ss__facets': { + padding: 0, + }, + '.ss__filter-summary .ss__filter-summary__title, .ss__facets .ss__facet .ss__facet__header': { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: 0, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.text, + }, + '.ss__filter-summary .ss__filter-summary__filters, .ss__facets .ss__facet .ss__dropdown__content': { + padding: `${custom.spacing.x4}px`, + }, + '.ss__facets .ss__facet': { + margin: 0, + width: 'auto', + '&.ss__facet--collapsed': { + borderBottom: `1px solid ${custom.colors.gray02}`, + }, + '.ss__facet__header': { + '.ss__icon': { + fill: 'currentColor', + stroke: 'currentColor', + }, + }, + }, + }, + }, + }, + }); +}; + +// MobileSidebar component props +export const mobileSidebar: ThemeComponent<'mobileSidebar', MobileSidebarProps> = { + default: { + mobileSidebar: { + themeStyleScript: mobileSidebarStyleScript, + }, + 'mobileSidebar button.close': { + icon: custom.icons.close, + }, + 'mobileSidebar toolbar filterSummary': { + title: 'Current Filters', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/noResults.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/noResults.ts new file mode 100644 index 000000000..c7a685676 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/noResults.ts @@ -0,0 +1,61 @@ +import { css } from '@emotion/react'; +import type { NoResultsProps } from '../../../../components/Organisms/NoResults'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the NoResults component +const noResultsStyleScript = (props: NoResultsProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + 'h1, h2, h3, h4, h5, h6, ul': { + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + 'h1, h2, h3, h4, h5, h6, .ss__no-results__recommendations .ss__recommendation .ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(20), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + 'ul li, p': { + color: variables?.colors?.text, + }, + a: { + color: variables?.colors?.primary, + '&:hover': { + color: variables?.colors?.secondary, + }, + }, + ul: { + padding: 0, + marginLeft: `${custom.spacing.x8}px`, + listStyle: 'none', + li: { + listStyle: 'disc', + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + '.ss__no-results__recommendations': { + '.ss__recommendation': { + margin: `${custom.spacing.x4}px 0`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + 'h1, h2, h3, h4, h5, h6, .ss__no-results__recommendations .ss__recommendation .ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(18), + }, + }, + }); +}; + +// NoResults component props +export const noResults: ThemeComponent<'noResults', NoResultsProps> = { + default: { + noResults: { + themeStyleScript: noResultsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/results.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/results.ts new file mode 100644 index 000000000..fabe87ac2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/results.ts @@ -0,0 +1,39 @@ +import { css } from '@emotion/react'; +import type { ResultsProps } from '../../../../components/Organisms/Results'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Results component +const resultsStyleScript = (props: ResultsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '& > *': { + minWidth: '1px', + }, + }); +}; + +// Results component props +export const results: ThemeComponent<'results', ResultsProps> = { + default: { + results: { + themeStyleScript: resultsStyleScript, + gapSize: `${custom.spacing.x6}px ${custom.spacing.x4}px`, + columns: 4, + }, + }, + mobile: { + results: { + gapSize: `${custom.spacing.x6}px ${custom.spacing.x2}px`, + columns: 2, + }, + }, + tablet: { + results: { + columns: 3, + }, + }, + desktop: {}, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/sidebar.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/sidebar.ts new file mode 100644 index 000000000..60ef58fa2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/sidebar.ts @@ -0,0 +1,57 @@ +import { css } from '@emotion/react'; +import type { SidebarProps } from '../../../../components/Organisms/Sidebar'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Sidebar component +const sidebarStyleScript = (props: SidebarProps) => { + const variables = props?.theme?.variables; + + return css({ + '.ss__sidebar__title': { + margin: `0 0 ${custom.spacing.x6}px 0`, + fontSize: custom.utils.convertPxToEm(20), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__sidebar__inner': { + '.ss__layout': { + '&, .ss__layout__row': { + display: 'block', + }, + '.ss__layout__row': { + minWidth: '1px', + '& > div:only-child': { + width: 'auto', + }, + }, + }, + '.ss__layout .ss__layout__row, .ss__facets .ss__facet': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__filter-summary .ss__filter-summary__title, .ss__facets .ss__facet .ss__facet__header': { + margin: ` 0 0 ${custom.spacing.x4}px 0`, + padding: ` 0 0 ${custom.spacing.x2}px 0`, + borderBottom: `2px solid ${variables?.colors?.primary}`, + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + }, + }); +}; + +// Sidebar component props +export const sidebar: ThemeComponent<'sidebar', SidebarProps> = { + default: { + sidebar: { + themeStyleScript: sidebarStyleScript, + }, + 'sidebar toolbar filterSummary': { + title: 'Current Filters', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/termsList.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/termsList.ts new file mode 100644 index 000000000..82e5dcc2c --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/termsList.ts @@ -0,0 +1,29 @@ +import { css } from '@emotion/react'; +import type { TermsListProps } from '../../../../components/Organisms/TermsList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the TermsList component +const termsListStyleScript = (props: TermsListProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + backgroundColor: 'transparent', + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + '.ss__terms-list-row': { + flex: '1 1 0%', + minWidth: '1px', + }, + }); +}; + +// TermsList component props +export const termsList: ThemeComponent<'termsList', TermsListProps> = { + default: { + termsList: { + themeStyleScript: termsListStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/organisms/toolbar.ts b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/toolbar.ts new file mode 100644 index 000000000..8370fe5ee --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/organisms/toolbar.ts @@ -0,0 +1,73 @@ +import { css } from '@emotion/react'; +import { ThemeComponent } from '../../../../providers'; +import { ToolbarProps } from '../../../../components/Organisms/Toolbar'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Toolbar component +const toolbarStyleScript = (props: ToolbarProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '.ss__layout': { + gap: `${custom.spacing.x2}px`, + margin: 0, + }, + '&[class*="bottom"]': { + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(14), + }, + }, + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(16), + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(18), + }, + }, + '& > .ss__layout > .ss__layout__row > .ss__filter-summary': { + display: 'flex', + flexFlow: 'row wrap', + '.ss__filter-summary__title, .ss__filter-summary__filters': { + minWidth: '1px', + }, + '.ss__filter-summary__title': { + flex: '0 1 auto', + padding: `0 ${custom.spacing.x2}px 0 0`, + }, + '.ss__filter-summary__filters': { + flex: '1 1 0%', + }, + '&.ss__filter-summary--inline': { + '.ss__filter-summary__title': { + paddingTop: `${custom.spacing.x1}px`, + paddingBottom: `${custom.spacing.x1}px`, + }, + }, + '&.ss__filter-summary--list': { + '.ss__filter-summary__filters': { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + gap: `${custom.spacing.x2}px`, + '.ss__filter': { + margin: 0, + }, + }, + }, + }, + }); +}; + +// Toolbar component props +export const toolbar: ThemeComponent<'toolbar', ToolbarProps> = { + default: { + toolbar: { + themeStyleScript: toolbarStyleScript, + }, + 'toolbar filterSummary': { + title: `Current Filters:`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteFixed.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteFixed.ts new file mode 100644 index 000000000..7e1248d02 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteFixed.ts @@ -0,0 +1,187 @@ +import { css } from '@emotion/react'; +import { autocompleteFixedThemeComponentProps } from '../../../themeComponents/autocompleteFixed'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteFixedProps } from '../../../../components/Templates/AutocompleteFixed'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const autocompleteFixedStyleScript = (props: AutocompleteFixedProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + return css({ + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '& > .ss__search-input.autocomplete-fixed__search-input': { + height: '40px', + margin: `0 0 ${custom.spacing.x2}px 0`, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '40px', + }, + }, + '.ss__autocomplete-fixed__inner__layout-wrapper': { + maxHeight: 'none', + width: 'auto', + '&, .ss__autocomplete': { + overflowY: 'visible', + }, + '.ss__autocomplete': { + maxWidth: 'none', + width: props?.width, + right: 0, + left: '-102px', + top: 'auto', + margin: 'auto', + }, + }, + }, + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '.ss__autocomplete-fixed__inner__layout-wrapper': { + '.ss__autocomplete': { + maxWidth: '100%', + width: props?.width, + left: 0, + right: 0, + }, + }, + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '.ss__autocomplete-fixed__inner__layout-wrapper': { + '.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + '& > *:nth-of-type(n+3)': { + display: 'none', + }, + }, + }, + }, + }, + }, + }, + }, + }); +}; + +export const autocompleteFixed: ThemeComponent<'autocompleteFixed', AutocompleteFixedProps> = { + default: { + ...autocompleteFixedThemeComponentProps.default, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.default?.['autocompleteFixed'] || {}), + themeStyleScript: autocompleteFixedStyleScript, + width: '900px', + layout: 'standard', + }, + 'autocompleteFixed facetPaletteOptions': { + gridSize: '38px', + hideLabel: false, + }, + 'autocompleteFixed facetGridOptions': { + gridSize: '38px', + }, + 'autocompleteFixed facet': { + ...(autocompleteFixedThemeComponentProps.default?.['autocompleteFixed facet'] || {}), + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocompleteFixed results': { + rows: 2, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 2, + columns: 4, + }, + 'autocompleteFixed button.see-more icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteFixedThemeComponentProps.mobile, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.mobile?.['autocompleteFixed'] || {}), + width: 'auto', + layout: 'mini', + }, + 'autocompleteFixed results': { + rows: 1, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteFixedThemeComponentProps.tablet, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.tablet?.['autocompleteFixed'] || {}), + width: 'auto', + layout: 'standard', + }, + 'autocompleteFixed facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocompleteFixed results': { + rows: 1, + columns: 4, + }, + 'autocompleteFixed recommendationGrid': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteFixedThemeComponentProps.desktop, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.desktop?.['autocompleteFixed'] || {}), + layout: 'standard', + }, + 'autocompleteFixed results': { + rows: 2, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteModal.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteModal.ts new file mode 100644 index 000000000..6c01ac334 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteModal.ts @@ -0,0 +1,204 @@ +import { css } from '@emotion/react'; +import { autocompleteModalThemeComponentProps } from '../../../themeComponents/autocompleteModal'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteModalProps } from '../../../../components/Templates/AutocompleteModal'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const autocompleteModalStyleScript = (props: AutocompleteModalProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '.ss__modal': { + '&, .ss__modal__content': { + height: '100%', + }, + '.ss__modal__content': { + backgroundColor: 'transparent', + justifyContent: 'center', + '&, .ss__autocomplete-modal__inner': { + position: 'static', + display: 'flex', + flexFlow: 'column nowrap', + }, + '.ss__autocomplete-modal__inner': { + width: props?.width, + maxHeight: 'none', + height: '80vh', + overflow: 'hidden', + '& > .ss__search-input.autocomplete-modal__search-input, .ss__autocomplete': { + minHeight: '1px', + minWidth: '1px', + }, + '& > .ss__search-input.autocomplete-modal__search-input': { + flex: '0 1 auto', + height: '40px', + margin: 0, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '40px', + }, + }, + '.ss__autocomplete': { + flex: '1 1 0%', + borderWidth: 0, + overflowY: 'auto', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + maxHeight: 'none', + overflow: 'visible', + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + width: props?.width, + height: '100%', + }, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + '.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + '& > *:nth-of-type(n+5)': { + display: 'none', + }, + }, + }, + }, + }, + }, + }, + }); +}; + +export const autocompleteModal: ThemeComponent<'autocompleteModal', AutocompleteModalProps> = { + default: { + ...autocompleteModalThemeComponentProps.default, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.default?.['autocompleteModal'] || {}), + themeStyleScript: autocompleteModalStyleScript, + width: '70vw', + layout: 'standard', + }, + 'autocompleteModal facetPaletteOptions': { + gridSize: '38px', + hideLabel: false, + }, + 'autocompleteModal facetGridOptions': { + gridSize: '38px', + }, + 'autocompleteModal facet': { + ...(autocompleteModalThemeComponentProps.default?.['autocompleteModal facet'] || {}), + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + 'autocompleteModal button.see-more icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteModalThemeComponentProps.mobile, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.mobile?.['autocompleteModal'] || {}), + width: '100%', + layout: 'mini', + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 3, + }, + }, + tablet: { + ...autocompleteModalThemeComponentProps.tablet, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.tablet?.['autocompleteModal'] || {}), + width: '80vw', + layout: 'standard', + }, + 'autocompleteModal facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocompleteModal results': { + rows: 2, + columns: 4, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + }, + desktop: { + ...autocompleteModalThemeComponentProps.desktop, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.desktop?.['autocompleteModal'] || {}), + width: '80vw', + layout: 'standard', + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteSlideout.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteSlideout.ts new file mode 100644 index 000000000..580ff67d0 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/autocompleteSlideout.ts @@ -0,0 +1,129 @@ +import { css } from '@emotion/react'; +import { autocompleteSlideoutThemeComponentProps } from '../../../themeComponents/autocompleteSlideout'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteSlideoutProps } from '../../../../components/Templates/AutocompleteSlideout'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const autocompleteSlideoutStyleScript = (props: AutocompleteSlideoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + border: 0, + padding: `${custom.spacing.x4}px`, + '.ss__autocomplete-slideout__inner': { + display: 'flex', + flexFlow: 'column nowrap', + height: '100%', + '& > .ss__search-input.autocomplete-slideout__search-input, .ss__autocomplete': { + minHeight: '1px', + minWidth: '1px', + }, + '& > .ss__search-input.autocomplete-slideout__search-input': { + flex: '0 1 auto', + height: '40px', + margin: `0 0 ${custom.spacing.x2}px 0`, + '.ss__button, .ss__search-input__button--close-search-button': { + width: '40px', + }, + }, + '.ss__autocomplete': { + flex: '1 1 0%', + alignContent: 'flex-start', + borderWidth: 0, + overflowY: 'auto', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + '& > .ss__autocomplete__row .ss__autocomplete__column': { + padding: `${custom.spacing.x4}px 0`, + }, + '.ss__autocomplete__terms-wrapper, .ss__autocomplete__content, .ss__autocomplete__button--see-more': { + paddingLeft: 0, + paddingRight: 0, + }, + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + maxHeight: 'none', + overflow: 'visible', + }, + }, + }, + }); +}; + +export const autocompleteSlideout: ThemeComponent<'autocompleteSlideout', AutocompleteSlideoutProps> = { + default: { + ...autocompleteSlideoutThemeComponentProps.default, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.default?.['autocompleteSlideout'] || {}), + themeStyleScript: autocompleteSlideoutStyleScript, + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout button.see-more icon': { + icon: custom.icons.arrowRight, + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteSlideoutThemeComponentProps.mobile, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.mobile?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 2, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 2, + }, + }, + tablet: { + ...autocompleteSlideoutThemeComponentProps.tablet, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.tablet?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, + desktop: { + ...autocompleteSlideoutThemeComponentProps.desktop, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.desktop?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/index.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/index.ts new file mode 100644 index 000000000..e6bef36ce --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/index.ts @@ -0,0 +1,79 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// TEMPLATES +import { autocompleteFixed } from './autocompleteFixed'; +import { autocompleteModal } from './autocompleteModal'; +import { autocompleteSlideout } from './autocompleteSlideout'; +import { recommendation } from './recommendation'; +import { recommendationBundle } from './recommendationBundle'; +import { recommendationBundleEasyAdd } from './recommendationBundleEasyAdd'; +import { recommendationBundleList } from './recommendationBundleList'; +import { recommendationBundleVertical } from './recommendationBundleVertical'; +import { recommendationGrid } from './recommendationGrid'; +import { recommendationEmail } from './recommendationEmail'; +import { search } from './search'; +import { searchHorizontal } from './searchHorizontal'; +import { searchCollapsible } from './searchCollapsible'; + +export const templates: ThemeResponsiveComplete = { + default: { + ...autocompleteFixed.default, + ...autocompleteModal.default, + ...autocompleteSlideout.default, + ...recommendation.default, + ...recommendationBundle.default, + ...recommendationBundleEasyAdd.default, + ...recommendationBundleList.default, + ...recommendationBundleVertical.default, + ...recommendationGrid.default, + ...recommendationEmail.default, + ...search.default, + ...searchCollapsible.default, + ...searchHorizontal.default, + }, + mobile: { + ...autocompleteFixed.mobile, + ...autocompleteModal.mobile, + ...autocompleteSlideout.mobile, + ...recommendation.mobile, + ...recommendationBundle.mobile, + ...recommendationBundleEasyAdd.mobile, + ...recommendationBundleList.mobile, + ...recommendationBundleVertical.mobile, + ...recommendationGrid.mobile, + ...recommendationEmail.mobile, + ...search.mobile, + ...searchCollapsible.mobile, + ...searchHorizontal.mobile, + }, + tablet: { + ...autocompleteFixed.tablet, + ...autocompleteModal.tablet, + ...autocompleteSlideout.tablet, + ...recommendation.tablet, + ...recommendationBundle.tablet, + ...recommendationBundleEasyAdd.tablet, + ...recommendationBundleList.tablet, + ...recommendationBundleVertical.tablet, + ...recommendationGrid.tablet, + ...recommendationEmail.tablet, + ...search.tablet, + ...searchCollapsible.tablet, + ...searchHorizontal.tablet, + }, + desktop: { + ...autocompleteFixed.desktop, + ...autocompleteModal.desktop, + ...autocompleteSlideout.desktop, + ...recommendation.desktop, + ...recommendationBundle.desktop, + ...recommendationBundleEasyAdd.desktop, + ...recommendationBundleList.desktop, + ...recommendationBundleVertical.desktop, + ...recommendationGrid.desktop, + ...recommendationEmail.desktop, + ...search.desktop, + ...searchCollapsible.desktop, + ...searchHorizontal.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendation.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendation.ts new file mode 100644 index 000000000..5765da87c --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendation.ts @@ -0,0 +1,122 @@ +import { css } from '@emotion/react'; +import type { RecommendationProps } from '../../../../components/Templates/Recommendation'; +import { recommendationThemeComponentProps } from '../../../themeComponents/recommendation'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Recommendation component +const recommendationStyleScript = (props: RecommendationProps) => { + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const arrowSizes = { + default: 32, + tablet: 28, + mobile: 24, + }; + + return css({ + margin: `${custom.spacing.x8}px 0`, + '.ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + textAlign: 'center', + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__carousel': { + padding: `0 ${custom.spacing.x4 + arrowSizes.default}px`, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__carousel': { + padding: `0 ${custom.spacing.x4 + arrowSizes.tablet}px`, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + width: `${arrowSizes.tablet}px`, + height: `${arrowSizes.tablet}px`, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + position: 'relative', + '.ss__recommendation__title': { + textAlign: 'left', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + overflow: 'hidden', + paddingRight: `${arrowSizes.mobile * 2 + custom.spacing.x1 + custom.spacing.x4}px`, + }, + '.ss__carousel': { + padding: 0, + position: 'static', + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: '4.5px', + bottom: 'auto', + left: 'auto', + width: `${arrowSizes.mobile}px`, + height: `${arrowSizes.mobile}px`, + }, + '.ss__carousel__prev-wrapper': { + right: `${arrowSizes.mobile + custom.spacing.x1}px`, + }, + '.ss__carousel__next-wrapper': { + right: 0, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__recommendation__title': { + fontSize: custom.utils.convertPxToEm(18), + }, + '.ss__carousel': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: 0, + }, + }, + }, + }); +}; + +// Recommendation component props come from Template export +export const recommendation: ThemeComponent<'recommendation', RecommendationProps> = { + default: { + ...recommendationThemeComponentProps.default, + recommendation: { + ...(recommendationThemeComponentProps.default?.['recommendation'] || {}), + themeStyleScript: recommendationStyleScript, + spaceBetween: custom.spacing.x4, + }, + }, + mobile: { + ...recommendationThemeComponentProps.mobile, + recommendation: { + ...(recommendationThemeComponentProps.mobile?.['recommendation'] || {}), + spaceBetween: custom.spacing.x2, + }, + 'recommendation icon.prev': { + size: `${custom.sizes.icon08}px`, + }, + 'recommendation icon.next': { + size: `${custom.sizes.icon08}px`, + }, + }, + tablet: { + ...recommendationThemeComponentProps.tablet, + recommendation: { + ...(recommendationThemeComponentProps.tablet?.['recommendation'] || {}), + spaceBetween: custom.spacing.x4, + }, + 'recommendation icon.prev': { + size: `${custom.sizes.icon10}px`, + }, + 'recommendation icon.next': { + size: `${custom.sizes.icon10}px`, + }, + }, + desktop: { + ...recommendationThemeComponentProps.desktop, + recommendation: { + ...(recommendationThemeComponentProps.desktop?.['recommendation'] || {}), + spaceBetween: custom.spacing.x4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundle.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundle.ts new file mode 100644 index 000000000..471791147 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundle.ts @@ -0,0 +1,250 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleProps } from '../../../../components/Templates/RecommendationBundle'; +import { recommendationBundleThemeComponentProps } from '../../../themeComponents/recommendationBundle'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundle component +const recommendationBundleStyleScript = (props: RecommendationBundleProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x8}px 0`, + '.ss__recommendation-bundle__title': { + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__recommendation-bundle__wrapper': { + flexFlow: `row nowrap`, + margin: `0 -${custom.spacing.x2}px`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + padding: `0 ${custom.spacing.x2}px`, + boxSizing: 'border-box', + }, + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__cta': { + width: `20%`, + }, + '.ss__recommendation-bundle__wrapper__carousel': { + width: `60%`, + }, + }, + '.ss__recommendation-result-tracker, .ss__recommendation-bundle__wrapper__selector, .ss__recommendation-bundle__wrapper .ss__recommendation-bundle__wrapper__selector__result-wrapper': + { + height: '100%', + margin: 0, + }, + '.ss__recommendation-bundle__wrapper__seed-container': { + '.ss__recommendation-bundle__wrapper__selector__result-wrapper__seed-badge': { + top: '5px', + left: '5px', + backgroundColor: variables?.colors?.primary, + fontSize: custom.utils.convertPxToEm(12), + fontWeight: custom.fonts.weight01, + lineHeight: `20px`, + color: custom.colors.white, + padding: `0 ${custom.spacing.x2}px`, + }, + }, + '.ss__recommendation-bundle__wrapper__selector': { + width: 'auto !important', + }, + '.ss__recommendation-bundle__wrapper__selector__result-wrapper, .ss__carousel .swiper-container > .swiper-wrapper > .swiper-slide': { + '.ss__result': { + width: '100%', + flex: '1 1 0%', + }, + }, + '.ss__recommendation-bundle__wrapper__selector__result-wrapper': { + display: 'flex', + flexFlow: `column wrap`, + '&, .ss__result': { + position: 'relative', + }, + '&:has(.ss__overlay-badge)': { + '.ss__result': { + '.ss__overlay-badge .ss__overlay-badge__grid-wrapper': { + top: '25px', + }, + }, + }, + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + }, + '.ss__icon--plus': { + display: 'none', + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + margin: 'auto 0', + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle__wrapper__cta': { + position: 'relative', + paddingTop: `${custom.spacing.x4}px`, + paddingBottom: `${custom.spacing.x4}px`, + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'center', + alignItems: 'center', + gap: `${custom.spacing.x4}px`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + margin: `0 ${custom.spacing.x2}px 0 ${custom.spacing.x4}px`, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal, .ss__recommendation-bundle__wrapper__cta__button': { + position: 'relative', + zIndex: 2, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal': { + color: variables?.colors?.text, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__prices': { + margin: `${custom.spacing.x1}px 0 0 0`, + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + '&:after': { + content: '""', + display: 'block', + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + boxSizing: 'border-box', + position: 'absolute', + top: 0, + left: '10px', + right: 0, + bottom: 0, + zIndex: 1, + margin: 'auto', + }, + }, + [`@media (max-width: ${tabletBp}px)`]: { + '.ss__recommendation-bundle__wrapper': { + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__cta': { + width: `25%`, + }, + '.ss__recommendation-bundle__wrapper__carousel': { + width: `50%`, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle__wrapper': { + flexFlow: 'row wrap', + width: 'auto', + maxWidth: 'none', + margin: `0 -${custom.spacing.x1}px`, + '& > *': { + padding: `0 ${custom.spacing.x1}px`, + }, + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__carousel': { + width: `50%`, + }, + }, + '.ss__recommendation-bundle__wrapper__cta': { + width: 'auto', + margin: `${custom.spacing.x4}px 0 0 0`, + padding: `${custom.spacing.x4}px`, + '& > *': { + margin: 0, + }, + '&:after': { + left: 0, + }, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__recommendation-bundle__title': { + fontSize: custom.utils.convertPxToEm(18), + }, + }, + }); +}; + +// RecommendationBundle component props come from Template export +export const recommendationBundle: ThemeComponent<'recommendationBundle', RecommendationBundleProps> = { + default: { + ...recommendationBundleThemeComponentProps.default, + recommendationBundle: { + ...(recommendationBundleThemeComponentProps.default?.['recommendationBundle'] || {}), + themeStyleScript: recommendationBundleStyleScript, + }, + 'recommendationBundle icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + 'recommendationBundle icon.bundle-selector': { + icon: custom.icons.plus, + size: `${custom.sizes.icon14}px`, + }, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, + mobile: { + ...recommendationBundleThemeComponentProps.mobile, + 'recommendationBundle carousel': { + spaceBetween: 0, + }, + }, + tablet: { + ...recommendationBundleThemeComponentProps.tablet, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, + desktop: { + ...recommendationBundleThemeComponentProps.desktop, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleEasyAdd.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleEasyAdd.ts new file mode 100644 index 000000000..0a4272b23 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleEasyAdd.ts @@ -0,0 +1,134 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleEasyAddProps } from '../../../../components/Templates/RecommendationBundleEasyAdd'; +import { recommendationBundleEasyAddThemeComponentProps } from '../../../themeComponents/recommendationBundleEasyAdd'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleEasyAdd component +const recommendationBundleEasyAddStyleScript = (props: RecommendationBundleEasyAddProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-easy-add__title': { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle-easy-add__wrapper': { + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + '& > div': { + width: '50%', + minWidth: '1px', + flex: '0 1 auto', + boxSizing: 'border-box', + }, + '.ss__recommendation-bundle-easy-add__wrapper__selector__result-wrapper, .ss__recommendation-bundle-easy-add__wrapper__cta': { + margin: 0, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta': { + padding: `${custom.spacing.x4}px`, + width: 'auto', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'center', + alignItems: 'center', + gap: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal': { + color: variables?.colors?.text, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__prices': { + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle-easy-add__wrapper': { + flexFlow: 'row wrap', + '& > div': { + width: 'auto', + flex: '1 1 100%', + }, + }, + }, + }); +}; + +// RecommendationBundleEasyAdd component props come from Template export +export const recommendationBundleEasyAdd: ThemeComponent<'recommendationBundleEasyAdd', RecommendationBundleEasyAddProps> = { + default: { + ...recommendationBundleEasyAddThemeComponentProps.default, + recommendationBundleEasyAdd: { + ...(recommendationBundleEasyAddThemeComponentProps.default?.['recommendationBundleEasyAdd'] || {}), + themeStyleScript: recommendationBundleEasyAddStyleScript, + ctaInline: true, + }, + 'recommendationBundleEasyAdd icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + }, + mobile: { + ...recommendationBundleEasyAddThemeComponentProps.mobile, + }, + tablet: { + ...recommendationBundleEasyAddThemeComponentProps.tablet, + }, + desktop: { + ...recommendationBundleEasyAddThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleList.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleList.ts new file mode 100644 index 000000000..d66f9abdf --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleList.ts @@ -0,0 +1,177 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleListProps } from '../../../../components/Templates/RecommendationBundleList'; +import { recommendationBundleListThemeComponentProps } from '../../../themeComponents/recommendationBundleList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleEasyAdd component +const recommendationBundleListStyleScript = (props: RecommendationBundleListProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-list__title': { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle-list__wrapper': { + flexFlow: 'row wrap', + margin: `0 -${custom.spacing.x1}px`, + '&, & > div': { + boxSizing: 'border-box', + }, + '& > div': { + width: '50%', + minWidth: '1px', + flex: '0 1 auto', + padding: `0 ${custom.spacing.x1}px`, + margin: `0 0 ${custom.spacing.x2}px 0`, + }, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper': { + margin: 0, + gap: `${custom.spacing.x2}px`, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper__checkbox, .ss__result': { + minWidth: '1px', + }, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper__checkbox': { + flex: '0 1 auto', + }, + '.ss__result': { + flex: '1 1 0%', + '.ss__result__image-wrapper': { + display: 'none', + }, + '.ss__result__details': { + gap: 0, + }, + }, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta': { + '.ss__recommendation-bundle-list__wrapper__cta__inner': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + lineHeight: 1, + }, + '.ss__recommendation-bundle-list__wrapper__cta__inner__images': { + flexFlow: 'row nowrap', + gap: `${custom.spacing.x2 + custom.sizes.icon12}px`, + '.ss__recommendation-bundle-list__wrapper__cta__inner__image-wrapper': { + flex: '1 1 0%', + minWidth: '1px', + padding: 0, + '.ss__icon': { + top: 0, + bottom: 0, + right: `-${custom.spacing.x2 / 2 + custom.sizes.icon12}px`, + margin: 'auto 0', + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal': { + padding: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__prices': { + margin: `${custom.spacing.x1}px 0 0 0`, + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + }, + '.ss__recommendation-bundle-list__cta__button__wrapper': { + margin: `${custom.spacing.x4}px 0`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle-list__wrapper': { + '& > div': { + width: 'auto', + flex: '1 1 100%', + }, + }, + }, + }); +}; + +// RecommendationBundleList component props come from Template export +export const recommendationBundleList: ThemeComponent<'recommendationBundleList', RecommendationBundleListProps> = { + default: { + ...recommendationBundleListThemeComponentProps.default, + recommendationBundleList: { + ...(recommendationBundleListThemeComponentProps.default?.['recommendationBundleList'] || {}), + themeStyleScript: recommendationBundleListStyleScript, + separatorIconSeedOnly: false, + }, + 'recommendationBundleList icon.bundle-cart-separator': { + icon: custom.icons.plus, + size: `${custom.sizes.icon12}px`, + }, + 'recommendationBundleList icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + 'recommendationBundleList result': { + hideImage: true, + hideBadge: true, + }, + }, + mobile: { + ...recommendationBundleListThemeComponentProps.mobile, + }, + tablet: { + ...recommendationBundleListThemeComponentProps.tablet, + }, + desktop: { + ...recommendationBundleListThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleVertical.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleVertical.ts new file mode 100644 index 000000000..dba4de860 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationBundleVertical.ts @@ -0,0 +1,159 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleVerticalProps } from '../../../../components/Templates/RecommendationBundleVertical'; +import { recommendationBundleVerticalThemeComponentProps } from '../../../themeComponents/recommendationBundleVertical'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleVertical component +const recommendationBundleVerticalStyleScript = (props: RecommendationBundleVerticalProps) => { + const variables = props?.theme?.variables; + const lightGray = custom.utils.lightenColor(variables?.colors?.text, 0.65); + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-vertical__title': { + fontSize: custom.utils.convertPxToEm(18), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + }, + '.ss__recommendation-bundle-vertical__wrapper': { + gap: `${custom.spacing.x4}px`, + '& > div': { + minWidth: '1px', + flex: '1 1 100%', + }, + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper': { + margin: 0, + '&, .ss__result': { + position: 'relative', + }, + '&:has(.ss__overlay-badge)': { + '.ss__result': { + '.ss__overlay-badge .ss__overlay-badge__grid-wrapper': { + top: '25px', + }, + }, + }, + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper__seed-badge': { + top: '5px', + left: '5px', + backgroundColor: variables?.colors?.primary, + fontSize: custom.utils.convertPxToEm(14), + fontWeight: custom.fonts.weight01, + lineHeight: `24px`, + color: custom.colors.white, + padding: `0 ${custom.spacing.x2}px`, + }, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta': { + padding: `${custom.spacing.x4}px`, + width: 'auto', + display: 'flex', + flexFlow: 'column nowrap', + justifyContent: 'center', + alignItems: 'center', + gap: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + border: `1px solid ${custom.colors.gray02}`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal': { + color: variables?.colors?.text, + '& > *': { + lineHeight: 1, + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__icon__wrapper': { + '.ss__icon': { + fill: variables?.colors?.secondary, + stroke: variables?.colors?.secondary, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__title': { + display: 'block', + fontWeight: custom.fonts.weight02, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__prices': { + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__strike': { + color: lightGray, + '*': { + color: 'inherit', + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__price': { + fontSize: custom.utils.convertPxToEm(16), + fontWeight: custom.fonts.weight01, + color: variables?.colors?.primary, + '*': { + color: 'inherit', + }, + }, + }, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-bundle-vertical__wrapper': { + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper': { + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper__seed-badge': { + fontSize: custom.utils.convertPxToEm(12), + lineHeight: `20px`, + }, + }, + }, + }, + }); +}; + +// RecommendationBundleVertical component props come from Template export +export const recommendationBundleVertical: ThemeComponent<'recommendationBundleVertical', RecommendationBundleVerticalProps> = { + default: { + ...recommendationBundleVerticalThemeComponentProps.default, + recommendationBundleVertical: { + ...(recommendationBundleVerticalThemeComponentProps.default?.['recommendationBundleVertical'] || {}), + themeStyleScript: recommendationBundleVerticalStyleScript, + }, + 'recommendationBundleVertical icon.bundle-cart': { + icon: custom.icons.bag, + size: `${custom.sizes.icon16 * 2}px`, + }, + 'recommendationBundleVertical icon.bundle-selector': { + icon: custom.icons.plus, + size: `${custom.sizes.icon14}px`, + }, + }, + mobile: { + ...recommendationBundleVerticalThemeComponentProps.mobile, + }, + tablet: { + ...recommendationBundleVerticalThemeComponentProps.tablet, + }, + desktop: { + ...recommendationBundleVerticalThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationEmail.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationEmail.ts new file mode 100644 index 000000000..c87c85f65 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationEmail.ts @@ -0,0 +1,52 @@ +import { css } from '@emotion/react'; +import type { RecommendationEmailProps } from '../../../../components/Templates/RecommendationEmail'; +import { recommendationEmailThemeComponentProps } from '../../../themeComponents/recommendationEmail'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationEmail component +const recommendationEmailStyleScript = (props: RecommendationEmailProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + width: '400px !important', + height: '680px', + margin: `0 0 ${custom.spacing.x6}px 0`, + padding: `0 ${custom.spacing.x2}px`, + overflow: 'hidden', + '.ss__result': { + fontSize: '16px', + '.ss__result__details .ss__result__details__title a': { + display: 'block', + height: '26px', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }, + }, + }); +}; + +// RecommendationEmail component props come from Template export +export const recommendationEmail: ThemeComponent<'recommendationEmail', RecommendationEmailProps> = { + default: { + ...recommendationEmailThemeComponentProps.default, + recommendationEmail: { + ...(recommendationEmailThemeComponentProps.default?.['recommendationEmail'] || {}), + themeStyleScript: recommendationEmailStyleScript, + }, + 'recommendationEmail image': { + lazy: false, + }, + }, + mobile: { + ...recommendationEmailThemeComponentProps.mobile, + }, + tablet: { + ...recommendationEmailThemeComponentProps.tablet, + }, + desktop: { + ...recommendationEmailThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationGrid.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationGrid.ts new file mode 100644 index 000000000..d14e34a46 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/recommendationGrid.ts @@ -0,0 +1,72 @@ +import { css } from '@emotion/react'; +import type { RecommendationGridProps } from '../../../../components/Templates/RecommendationGrid'; +import { recommendationGridThemeComponentProps } from '../../../themeComponents/recommendationGrid'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundle component +const recommendationGridStyleScript = (props: RecommendationGridProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + margin: `${custom.spacing.x8}px 0`, + maxHeight: 'none', + '.ss__recommendation-grid__title': { + fontSize: custom.utils.convertPxToEm(22), + fontWeight: custom.fonts.weight02, + color: variables?.colors?.secondary, + textAlign: 'center', + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__recommendation-grid__results': { + overflowX: 'auto', + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__recommendation-grid__title': { + textAlign: 'left', + }, + }, + }); +}; + +// RecommendationGrid component props come from Template export +export const recommendationGrid: ThemeComponent<'recommendationGrid', RecommendationGridProps> = { + default: { + ...recommendationGridThemeComponentProps.default, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.default?.['recommendationGrid'] || {}), + themeStyleScript: recommendationGridStyleScript, + gapSize: `${custom.spacing.x6}px ${custom.spacing.x4}px`, + columns: 4, + }, + }, + mobile: { + ...recommendationGridThemeComponentProps.mobile, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.mobile?.['recommendationGrid'] || {}), + gapSize: `${custom.spacing.x6}px ${custom.spacing.x2}px`, + columns: 2, + }, + }, + tablet: { + ...recommendationGridThemeComponentProps.tablet, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.tablet?.['recommendationGrid'] || {}), + columns: 3, + }, + }, + desktop: { + ...recommendationGridThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/search.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/search.ts new file mode 100644 index 000000000..3e2a9488e --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/search.ts @@ -0,0 +1,80 @@ +import { css } from '@emotion/react'; +import type { SearchProps } from '../../../../components/Templates/Search'; +import { searchThemeComponentProps } from '../../../themeComponents/search'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchStyleScript = (props: SearchProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '&.ss__search--sidebar-open': { + '.ss__button': { + '.ss__icon--filter': { + transform: 'rotate(-180deg)', + }, + '.ss__icon--filters': { + circle: { + '&:last-child': { + transform: 'translateX(-35%)', + }, + transform: 'translateX(35%)', + }, + }, + }, + }, + '.ss__search__header-section, .ss__search__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '.ss__toolbar .ss__layout': { + gap: `${custom.spacing.x4}px`, + }, + }, + '.ss__search__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search__sidebar, .ss__search__content': { + minWidth: '1px', + }, + '.ss__search__sidebar': { + flex: '0 1 auto', + }, + '.ss__search__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__search__main-section': { + '.ss__toolbar': { + '.ss__select': { + flex: '1 1 0%', + }, + }, + }, + }, + }); +}; + +// Search component props come from Template export +export const search: ThemeComponent<'search', SearchProps> = { + default: { + ...searchThemeComponentProps.default, + search: { + ...(searchThemeComponentProps.default?.['search'] || {}), + themeStyleScript: searchStyleScript, + }, + 'search filterSummary': { + type: 'list', + }, + }, + mobile: { + ...searchThemeComponentProps.mobile, + }, + tablet: { + ...searchThemeComponentProps.tablet, + }, + desktop: { + ...searchThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/searchCollapsible.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/searchCollapsible.ts new file mode 100644 index 000000000..bff1a4fc4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/searchCollapsible.ts @@ -0,0 +1,88 @@ +import { css } from '@emotion/react'; +import type { SearchCollapsibleProps } from '../../../../components/Templates/SearchCollapsible'; +import { searchCollapsibleThemeComponentProps } from '../../../themeComponents/searchCollapsible'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchCollapsibleStyleScript = (props: SearchCollapsibleProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + return css({ + '&.ss__search-collapsible--sidebar-open': { + '.ss__button': { + '.ss__icon--filter': { + transform: 'rotate(-180deg)', + }, + '.ss__icon--filters': { + circle: { + '&:last-child': { + transform: 'translateX(-35%)', + }, + transform: 'translateX(35%)', + }, + }, + }, + }, + '.ss__search-collapsible__header-section, .ss__search-collapsible__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '.ss__toolbar .ss__layout': { + gap: `${custom.spacing.x4}px`, + }, + }, + '.ss__search-collapsible__header-section': { + '.ss__search-header': { + textAlign: 'center', + }, + }, + '.ss__search-collapsible__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search-collapsible__sidebar, .ss__search-collapsible__content': { + minWidth: '1px', + }, + '.ss__search-collapsible__sidebar': { + flex: '0 1 auto', + }, + '.ss__search-collapsible__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`@media (max-width: ${custom.breakpoints.small}px)`]: { + '.ss__toolbar': { + '.ss__pagination-info': { + fontSize: custom.utils.convertPxToEm(16), + }, + }, + }, + }); +}; + +export const searchCollapsible: ThemeComponent<'searchCollapsible', SearchCollapsibleProps> = { + default: { + ...searchCollapsibleThemeComponentProps.default, + searchCollapsible: { + ...(searchCollapsibleThemeComponentProps.default?.['searchCollapsible'] || {}), + themeStyleScript: searchCollapsibleStyleScript, + }, + 'searchCollapsible sidebar': { + hideTitleText: true, + }, + 'searchCollapsible button.sidebar-toggle': { + icon: custom.icons.filter, + }, + 'searchCollapsible filterSummary': { + type: 'list', + }, + }, + mobile: { + ...searchCollapsibleThemeComponentProps.mobile, + }, + tablet: { + ...searchCollapsibleThemeComponentProps.tablet, + }, + desktop: { + ...searchCollapsibleThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/components/templates/searchHorizontal.ts b/packages/snap-preact/components/src/themes/matterhorn/components/templates/searchHorizontal.ts new file mode 100644 index 000000000..3501da121 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/components/templates/searchHorizontal.ts @@ -0,0 +1,78 @@ +import { css } from '@emotion/react'; +import type { SearchHorizontalProps } from '../../../../components/Templates/SearchHorizontal'; +import { searchHorizontalThemeComponentProps } from '../../../themeComponents/searchHorizontal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchHorizontalStyleScript = (props: SearchHorizontalProps) => { + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + return css({ + '.ss__search-horizontal__header-section, .ss__search-horizontal__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '.ss__toolbar .ss__layout': { + gap: `${custom.spacing.x4}px`, + '.ss__layout__row': { + '&:has(.ss__facets-horizontal)': { + alignItems: 'flex-start', + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__facets-horizontal': { + flex: '1 1 0%', + }, + }, + }, + }, + }, + '.ss__search-horizontal__header-section': { + '.ss__search-header': { + textAlign: 'center', + }, + }, + '.ss__search-horizontal__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search-horizontal__sidebar, .ss__search-horizontal__content': { + minWidth: '1px', + }, + '.ss__search-horizontal__sidebar': { + flex: '0 1 auto', + }, + '.ss__search-horizontal__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`@media (max-width: ${mobileBp}px)`]: { + '.ss__search-horizontal__main-section': { + '.ss__toolbar': { + '.ss__select': { + flex: '1 1 0%', + }, + }, + }, + }, + }); +}; + +export const searchHorizontal: ThemeComponent<'searchHorizontal', SearchHorizontalProps> = { + default: { + ...searchHorizontalThemeComponentProps.default, + searchHorizontal: { + ...(searchHorizontalThemeComponentProps.default?.['searchHorizontal'] || {}), + themeStyleScript: searchHorizontalStyleScript, + }, + }, + mobile: { + ...searchHorizontalThemeComponentProps.mobile, + }, + tablet: { + ...searchHorizontalThemeComponentProps.tablet, + }, + desktop: { + ...searchHorizontalThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/custom.ts b/packages/snap-preact/components/src/themes/matterhorn/custom.ts new file mode 100644 index 000000000..0c61729e4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/custom.ts @@ -0,0 +1,108 @@ +import { IconType } from '../../components/Atoms/Icon'; +import Color from 'color'; + +// calculate spacing +const spacing = 5; +const spacingCalc = (value: number) => { + return spacing * value; +}; + +export const custom: { + breakpoints: { + [key: string]: number; + }; + colors: { + [key: string]: string; + }; + fonts: { + [key: string]: any; + }; + icons: { + [key: string]: IconType; + }; + sizes: { + [key: string]: number; + }; + spacing: { + [key: string]: number; + }; + utils: { + convertPxToEm: (value: number) => string; + lightenColor: (color: string | undefined, amount: number) => string; + darkenColor: (color: string | undefined, amount: number) => string; + }; +} = { + breakpoints: { + small: 540, + mobile: 767, + tablet: 1024, + desktop: 1280, + }, + colors: { + white: '#ffffff', + black: '#000000', + gray01: '#f8f8f8', // lighter gray: bg color under terms, dropdown, checkboxes + gray02: '#ebebeb', // light gray: borders for autocomplete, dropdown, checkboxes + brown: '#845329', // for color palette + purple: '#7c368e', // for color palette + rainbow: + 'linear-gradient(rgb(40, 87, 218) 20%, rgb(40, 218, 70) 20%, rgb(40, 218, 70) 40%, rgb(245, 228, 24) 40%, rgb(245, 228, 24) 60%, rgb(242, 133, 0) 60%, rgb(242, 133, 0) 80%, rgb(218, 40, 72) 80%, rgb(218, 40, 72))', // for color palette + }, + fonts: { + weight01: 700, // main font weight + weight02: 700, // header font weight + style: false, + transform: false, + }, + icons: { + arrowLeft: 'chevron-left', + arrowRight: 'chevron-right', + arrowDown: 'chevron-down', + arrowUp: 'chevron-up', + bag: 'bag', + check: 'square', + close: 'close', + minus: 'minus', + plus: 'plus', + filter: 'filter', + filters: 'filters', + search: 'search', + sort: 'sort', + }, + sizes: { + font: 16, // base font size + height: 35, // refers to height for button and dropdown sizes + icon08: 8, + icon10: 10, + icon12: 12, + icon14: 14, + icon16: 16, + radius: 0, // global border radius value + }, + spacing: { + x1: spacing, + x2: spacingCalc(2), + x3: spacingCalc(3), + x4: spacingCalc(4), + x5: spacingCalc(5), + x6: spacingCalc(6), + x7: spacingCalc(7), + x8: spacingCalc(8), + }, + utils: { + convertPxToEm: (value: number) => { + // translates px to rem + return `${value / custom.sizes.font}rem`; + }, + lightenColor: (color: string | undefined, amount: number) => { + // lighten a color + const lightColor = new Color(color || '#515151').lighten(amount).hex().toLowerCase(); + return lightColor; + }, + darkenColor: (color: string | undefined, amount: number) => { + // darken a color + const darkColor = new Color(color || '#515151').darken(amount).hex().toLowerCase(); + return darkColor; + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/matterhorn.ts b/packages/snap-preact/components/src/themes/matterhorn/matterhorn.ts new file mode 100644 index 000000000..92be27d14 --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/matterhorn.ts @@ -0,0 +1,24 @@ +import { ThemeComplete, ThemeVariables } from '../../providers'; +import { components } from './components'; +import { responsive } from './responsive'; + +const matterhornVariables: ThemeVariables = { + breakpoints: { + mobile: 767, + tablet: 991, + desktop: 1199, + }, + colors: { + text: '#515151', + primary: '#00aeef', + secondary: '#1d4990', + accent: '#2154a5', + }, +}; + +export const matterhorn: ThemeComplete = { + name: 'matterhorn', + variables: matterhornVariables, + components, + responsive, +}; diff --git a/packages/snap-preact/components/src/themes/matterhorn/responsive.ts b/packages/snap-preact/components/src/themes/matterhorn/responsive.ts new file mode 100644 index 000000000..61ae08bfe --- /dev/null +++ b/packages/snap-preact/components/src/themes/matterhorn/responsive.ts @@ -0,0 +1,8 @@ +import { ThemeResponsive } from '../../providers/theme'; +import { mobileComponents, tabletComponents, desktopComponents } from './components'; + +export const responsive: ThemeResponsive = { + mobile: mobileComponents, + tablet: tabletComponents, + desktop: desktopComponents, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/badgeImage.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/badgeImage.ts new file mode 100644 index 000000000..36a085368 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/badgeImage.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { BadgeImageProps } from '../../../../components/Atoms/BadgeImage'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the BadgeImage component +const badgeImageStyleScript = (props: BadgeImageProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // badge image styles + const badgeImageStyles = css({ + lineHeight: 0, + ...custom.styles.boxSizing('badgeImage', props?.treePath, props?.name), + }); + + return badgeImageStyles; +}; + +// BadgeImage component props +export const badgeImage: ThemeComponent<'badgeImage', BadgeImageProps> = { + default: { + badgeImage: { + themeStyleScript: badgeImageStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/badgePill.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/badgePill.ts new file mode 100644 index 000000000..641ee0670 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/badgePill.ts @@ -0,0 +1,30 @@ +import { css } from '@emotion/react'; +import type { BadgePillProps } from '../../../../components/Atoms/BadgePill'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the BadgePill component +const badgePillStyleScript = (props: BadgePillProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // badge pill styles + const badgePillStyles = css({ + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + ...custom.styles.boxSizing('badgePill', props?.treePath, props?.name), + span: { + ...custom.styles.badgeText(12), + }, + }); + + return badgePillStyles; +}; + +// BadgePill component props +export const badgePill: ThemeComponent<'badgePill', BadgePillProps> = { + default: { + badgePill: { + themeStyleScript: badgePillStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/badgeRectangle.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/badgeRectangle.ts new file mode 100644 index 000000000..7a6f15d26 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/badgeRectangle.ts @@ -0,0 +1,30 @@ +import { css } from '@emotion/react'; +import type { BadgeRectangleProps } from '../../../../components/Atoms/BadgeRectangle'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the BadgeRectangle component +const badgeRectangleStyleScript = (props: BadgeRectangleProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // badge rectangle styles + const badgeRectangleStyles = css({ + padding: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + ...custom.styles.boxSizing('badgeRectangle', props?.treePath, props?.name), + span: { + ...custom.styles.badgeText(12), + }, + }); + + return badgeRectangleStyles; +}; + +// BadgeRectangle component props +export const badgeRectangle: ThemeComponent<'badgeRectangle', BadgeRectangleProps> = { + default: { + badgeRectangle: { + themeStyleScript: badgeRectangleStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/badgeText.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/badgeText.ts new file mode 100644 index 000000000..80ea779d8 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/badgeText.ts @@ -0,0 +1,30 @@ +import { css } from '@emotion/react'; +import type { BadgeTextProps } from '../../../../components/Atoms/BadgeText'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the BadgeText component +const badgeTextStyleScript = (props: BadgeTextProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // badge text styles + const badgeTextStyles = css({ + padding: 0, + ...custom.styles.boxSizing('badgeText', props?.treePath, props?.name), + span: { + ...custom.styles.badgeText(12), + }, + }); + + return badgeTextStyles; +}; + +// BadgeText component props +export const badgeText: ThemeComponent<'badgeText', BadgeTextProps> = { + default: { + badgeText: { + themeStyleScript: badgeTextStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/banner.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/banner.ts new file mode 100644 index 000000000..3fcd7c6d3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/banner.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { BannerProps } from '../../../../components/Atoms/Banner'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Banner component +const bannerStyleScript = (props: BannerProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // banner styles + const bannerStyles = css({ + color: variables?.colors?.text, + ...custom.styles.boxSizing('banner', props?.treePath, props?.name), + }); + + return bannerStyles; +}; + +// Banner component props +export const banner: ThemeComponent<'banner', BannerProps> = { + default: { + banner: { + themeStyleScript: bannerStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/breadcrumbs.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/breadcrumbs.ts new file mode 100644 index 000000000..171a933d0 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/breadcrumbs.ts @@ -0,0 +1,47 @@ +import { css } from '@emotion/react'; +import type { BreadcrumbsProps } from '../../../../components/Atoms/Breadcrumbs'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Breadcrumbs component +const breadcrumbsStyleScript = (props: BreadcrumbsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // breadcrumbs styles + const breadcrumbsStyles = css({ + ...custom.styles.boxSizing('breadcrumbs', props?.treePath, props?.name), + '.ss__breadcrumbs__crumbs': { + gap: `${custom.spacing.x2}px`, + '&, li': { + listStyle: 'none', + }, + '&, a': { + color: variables?.colors?.text, + }, + li: { + display: 'block', + padding: 0, + '&:last-of-type': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }, + }); + + return breadcrumbsStyles; +}; + +// Breadcrumbs component props +export const breadcrumbs: ThemeComponent<'breadcrumbs', BreadcrumbsProps> = { + default: { + breadcrumbs: { + themeStyleScript: breadcrumbsStyleScript, + separator: false, + separatorIcon: custom.icons.arrowRight, + }, + 'breadcrumbs icon': { + size: `${custom.sizes.icon10}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/button.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/button.ts new file mode 100644 index 000000000..d3575fc07 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/button.ts @@ -0,0 +1,106 @@ +import { css } from '@emotion/react'; +import type { ButtonProps } from '../../../../components/Atoms/Button'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const buttonDisabledSelectors = '&.ss__button--disabled'; + +// CSS in JS style script for the Button component +const buttonStyleScript = (props: ButtonProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const activeColors = custom.utils.activeColors(props?.backgroundColor); + const buttonColor = activeColors[0]; + const borderColor = props?.borderColor ? props.borderColor : activeColors[0]; + const fontColor = props?.color ? props.color : activeColors[1]; + + // shared styles + const sharedStyles = css([ + { + cursor: 'pointer', + padding: `0 ${custom.spacing.x4}px`, + justifyContent: 'center', + fontSize: '14px', + fontWeight: custom.fonts.weight01, + textAlign: 'center', + textTransform: custom.fonts.transform, + color: fontColor, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + ...custom.styles.borderRadius(), + ...custom.styles.boxSizing('button', props?.treePath, props?.name), + '&[active="true"], &:has([active="true"])': { + '.ss__icon': { + '&.ss__icon--filter': { + transform: 'rotate(-180deg)', + }, + '&.ss__icon--filters': { + circle: { + '&:last-child': { + transform: 'translateX(-35%)', + }, + transform: 'translateX(35%)', + }, + }, + }, + }, + [buttonDisabledSelectors]: { + ...custom.styles.disabled(), + }, + '.ss__button__content': { + '&:has(span)': { + display: 'inline-flex', + flexFlow: 'row nowrap', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + span: { + ...custom.styles.textOverflow(), + }, + }, + '&:not(:has(span))': { + ...custom.styles.textOverflow(), + }, + '&, *': { + minWidth: '1px', + }, + }, + [`&, &:hover, &:not(.ss__button--disabled):hover, ${buttonDisabledSelectors}`]: { + border: `1px solid ${borderColor}`, + backgroundColor: buttonColor, + }, + '.ss__icon.ss__icon--filters': { + fill: buttonColor, + }, + }, + ]); + + // default button styles + const defaultButtonStyles = sharedStyles; + + // native button styles + const nativeButtonStyles = css([ + { + display: 'inline-flex', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + position: 'relative', + outline: 0, + }, + sharedStyles, + ]); + + return props?.native ? nativeButtonStyles : defaultButtonStyles; +}; + +// Button component props +export const button: ThemeComponent<'button', ButtonProps> = { + default: { + button: { + themeStyleScript: buttonStyleScript, + }, + 'button icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/dropdown.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/dropdown.ts new file mode 100644 index 000000000..2136b242b --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/dropdown.ts @@ -0,0 +1,85 @@ +import { css } from '@emotion/react'; +import type { DropdownProps } from '../../../../components/Atoms/Dropdown'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Dropdown component +const dropdownStyleScript = (props: DropdownProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // disabled styles + const disabled = props?.disabled + ? { + ...custom.styles.disabled(), + } + : {}; + + // dropdown styles + const dropdownStyles = css({ + width: 'auto', + ...disabled, + ...custom.styles.boxSizing('dropdown', props?.treePath, props?.name), + '.ss__dropdown__button, .ss__dropdown__content': { + color: variables?.colors?.text, + }, + '&.ss__dropdown__portal': { + '.ss__dropdown__content': { + marginTop: `${custom.spacing.x1}px`, + ...custom.styles.box(), + '.ss__select__select, .ss__variant-selection__options': { + margin: 0, + padding: 0, + border: 0, + backgroundColor: 'transparent', + }, + '.ss__select__select .ss__select__select__option, .ss__variant-selection__options .ss__variant-selection__option': { + color: 'inherit', + gap: `${custom.spacing.x2}px`, + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + backgroundColor: 'transparent', + fontWeight: 'normal', + }, + 'a, span': { + cursor: 'pointer', + }, + }, + '.ss__select__select .ss__select__select__option--selected, .ss__variant-selection__options .ss__variant-selection__option--selected': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + '.ss__select__select .ss__select__select__option----unavailable, .ss__select__select .ss__select__select__option--disabled, .ss__variant-selection__options .ss__variant-selection__option--unavailable, .ss__variant-selection__options .ss__variant-selection__option--disabled': + { + color: 'inherit', + ...custom.styles.disabled(), + }, + }, + }, + '&.ss__dropdown--open': { + '.ss__dropdown__content': { + zIndex: 5, + }, + }, + '.ss__dropdown__content': { + minWidth: '1px', + left: 0, + right: 0, + zIndex: -1, + }, + }); + + return dropdownStyles; +}; + +// Dropdown component props +export const dropdown: ThemeComponent<'dropdown', DropdownProps> = { + default: { + dropdown: { + themeStyleScript: dropdownStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/formattedNumber.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/formattedNumber.ts new file mode 100644 index 000000000..f18e94495 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/formattedNumber.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { FormattedNumberProps } from '../../../../components/Atoms/FormattedNumber'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FormattedNumber component +const formattedNumberStyleScript = (props: FormattedNumberProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // formatted number styles + const formattedNumberStyles = css({ + color: variables?.colors?.text, + ...custom.styles.boxSizing('formattedNumber', props?.treePath, props?.name), + }); + + return formattedNumberStyles; +}; + +// FormattedNumber component props +export const formattedNumber: ThemeComponent<'formattedNumber', FormattedNumberProps> = { + default: { + formattedNumber: { + themeStyleScript: formattedNumberStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/icon.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/icon.ts new file mode 100644 index 000000000..5ed321e2c --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/icon.ts @@ -0,0 +1,47 @@ +import { css } from '@emotion/react'; +import type { IconProps } from '../../../../components/Atoms/Icon'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Icon component +const iconStyleScript = (props: IconProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // set flex size for icons that are flex children + let flexSize = ''; + if (props?.width) { + flexSize = `0 0 ${props.width}`; + } else if (props?.size) { + flexSize = `0 0 ${props.size}`; + } + + // icon styles + const iconStyles = css({ + minWidth: '1px', + flex: flexSize, + lineHeight: 1, + color: props?.treePath == 'storybook icon' ? variables?.colors?.text : '', + ...custom.styles.boxSizing('icon', props?.treePath, props?.name), + '&.ss__icon--filters': { + fill: custom.colors.white, + stroke: 'currentColor', + circle: { + fill: 'inherit', + }, + }, + }); + + return iconStyles; +}; + +// Icon component props +export const icon: ThemeComponent<'icon', IconProps> = { + default: { + icon: { + themeStyleScript: iconStyleScript, + size: `${custom.sizes.icon16}px`, + color: 'currentColor', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/image.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/image.ts new file mode 100644 index 000000000..644a50f57 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/image.ts @@ -0,0 +1,32 @@ +import { css } from '@emotion/react'; +import type { ImageProps } from '../../../../components/Atoms/Image'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Image component +const imageStyleScript = (props: ImageProps & { visibility: React.CSSProperties['visibility'] }) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // image styles + const imageStyles = css({ + ...custom.styles.boxSizing('image', props?.treePath, props?.name), + '&, img': { + lineHeight: 0, + }, + img: { + border: 0, + }, + }); + + return imageStyles; +}; + +// Image component props +export const image: ThemeComponent<'image', ImageProps> = { + default: { + image: { + themeStyleScript: imageStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/index.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/index.ts new file mode 100644 index 000000000..126b3601d --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/index.ts @@ -0,0 +1,104 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// ATOMS Imports +import { badgeImage } from './badgeImage'; +import { badgePill } from './badgePill'; +import { badgeRectangle } from './badgeRectangle'; +import { badgeText } from './badgeText'; +import { banner } from './banner'; +import { breadcrumbs } from './breadcrumbs'; +import { button } from './button'; +import { dropdown } from './dropdown'; +import { formattedNumber } from './formattedNumber'; +import { icon } from './icon'; +import { image } from './image'; +import { inlineBanner } from './inlineBanner'; +import { loadingBar } from './loadingBar'; +import { overlay } from './overlay'; +import { paginationInfo } from './paginationInfo'; +import { price } from './price'; +import { searchHeader } from './searchHeader'; +import { skeleton } from './skeleton'; + +export const atoms: ThemeResponsiveComplete = { + default: { + ...badgeImage.default, + ...badgePill.default, + ...badgeRectangle.default, + ...badgeText.default, + ...banner.default, + ...breadcrumbs.default, + ...button.default, + ...dropdown.default, + ...formattedNumber.default, + ...icon.default, + ...image.default, + ...inlineBanner.default, + ...loadingBar.default, + ...overlay.default, + ...paginationInfo.default, + ...price.default, + ...searchHeader.default, + ...skeleton.default, + }, + mobile: { + ...badgeImage.mobile, + ...badgePill.mobile, + ...badgeRectangle.mobile, + ...badgeText.mobile, + ...banner.mobile, + ...breadcrumbs.mobile, + ...button.mobile, + ...dropdown.mobile, + ...formattedNumber.mobile, + ...icon.mobile, + ...image.mobile, + ...inlineBanner.mobile, + ...loadingBar.mobile, + ...overlay.mobile, + ...paginationInfo.mobile, + ...price.mobile, + ...searchHeader.mobile, + ...skeleton.mobile, + }, + tablet: { + ...badgeImage.tablet, + ...badgePill.tablet, + ...badgeRectangle.tablet, + ...badgeText.tablet, + ...banner.tablet, + ...breadcrumbs.tablet, + ...button.tablet, + ...dropdown.tablet, + ...formattedNumber.tablet, + ...icon.tablet, + ...image.tablet, + ...inlineBanner.tablet, + ...loadingBar.tablet, + ...overlay.tablet, + ...paginationInfo.tablet, + ...price.tablet, + ...searchHeader.tablet, + ...skeleton.tablet, + }, + desktop: { + ...badgeImage.desktop, + ...badgePill.desktop, + ...badgeRectangle.desktop, + ...badgeText.desktop, + ...banner.desktop, + ...breadcrumbs.desktop, + ...button.desktop, + ...dropdown.desktop, + ...formattedNumber.desktop, + ...icon.desktop, + ...image.desktop, + ...inlineBanner.desktop, + ...loadingBar.desktop, + ...overlay.desktop, + ...paginationInfo.desktop, + ...price.desktop, + ...searchHeader.desktop, + ...skeleton.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/inlineBanner.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/inlineBanner.ts new file mode 100644 index 000000000..5f7c4a4af --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/inlineBanner.ts @@ -0,0 +1,34 @@ +import { css } from '@emotion/react'; +import type { InlineBannerProps } from '../../../../components/Atoms/InlineBanner'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the InlineBanner component +const inlineBannerStyleScript = (props: InlineBannerProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const isAutocomplete = props?.treePath?.includes('autocomplete') ? true : false; + + // inline banner styles + const inlineBannerStyles = css({ + overflow: isAutocomplete ? 'hidden' : '', + ...custom.styles.boxSizing('inlineBanner', props?.treePath, props?.name), + '&.ss__inline-banner--grid': { + maxHeight: isAutocomplete ? '212px' : '', + }, + '&.ss__inline-banner--list': { + maxHeight: isAutocomplete ? '100px' : '', + }, + }); + + return inlineBannerStyles; +}; + +// InlineBanner component props +export const inlineBanner: ThemeComponent<'inlineBanner', InlineBannerProps> = { + default: { + inlineBanner: { + themeStyleScript: inlineBannerStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/loadingBar.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/loadingBar.ts new file mode 100644 index 000000000..dc428cd04 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/loadingBar.ts @@ -0,0 +1,26 @@ +import { css } from '@emotion/react'; +import type { LoadingBarProps } from '../../../../components/Atoms/Loading'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the LoadingBar component +const loadingBarStyleScript = (props: LoadingBarProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // loading bar styles + const loadingBarStyles = css({ + ...custom.styles.boxSizing('loadingBar', props?.treePath, props?.name), + }); + + return loadingBarStyles; +}; + +// LoadingBar component props +export const loadingBar: ThemeComponent<'loadingBar', LoadingBarProps> = { + default: { + loadingBar: { + themeStyleScript: loadingBarStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/overlay.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/overlay.ts new file mode 100644 index 000000000..b5cea5d34 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/overlay.ts @@ -0,0 +1,28 @@ +import { css } from '@emotion/react'; +import type { OverlayProps } from '../../../../components/Atoms/Overlay'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Overlay component +const overlayStyleScript = (props: OverlayProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // overlay styles + const overlayStyles = css({ + cursor: 'pointer', + ...custom.styles.boxSizing('overlay', props?.treePath, props?.name), + }); + + return overlayStyles; +}; + +// Overlay component props +export const overlay: ThemeComponent<'overlay', OverlayProps> = { + default: { + overlay: { + themeStyleScript: overlayStyleScript, + color: 'rgba(0, 0, 0, 0.80)', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/paginationInfo.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/paginationInfo.ts new file mode 100644 index 000000000..e93fdf311 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/paginationInfo.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { PaginationInfoProps } from '../../../../components/Atoms/PaginationInfo'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Pagination component +const paginationInfoStyleScript = (props: PaginationInfoProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // pagination info styles + const paginationInfoStyles = css({ + ...custom.styles.headerText(variables?.colors?.secondary, '16px'), + ...custom.styles.boxSizing('paginationInfo', props?.treePath, props?.name), + }); + + return paginationInfoStyles; +}; + +// PaginationInfo component props +export const paginationInfo: ThemeComponent<'paginationInfo', PaginationInfoProps> = { + default: { + paginationInfo: { + themeStyleScript: paginationInfoStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/price.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/price.ts new file mode 100644 index 000000000..f4af14a52 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/price.ts @@ -0,0 +1,32 @@ +import { css } from '@emotion/react'; +import type { PriceProps } from '../../../../components/Atoms/Price'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Price component +const priceStyleScript = (props: PriceProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // price styles + const priceStyles = css({ + ...custom.styles.boxSizing('price', props?.treePath, props?.name), + '&, span, &.ss__price, &.ss__price--strike': { + color: variables?.colors?.text, + }, + '& ~ .ss__result__price': { + paddingLeft: `${custom.spacing.x1 / 2}px`, + }, + }); + + return priceStyles; +}; + +// Price component props +export const price: ThemeComponent<'price', PriceProps> = { + default: { + price: { + themeStyleScript: priceStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/searchHeader.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/searchHeader.ts new file mode 100644 index 000000000..5814d7ce9 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/searchHeader.ts @@ -0,0 +1,48 @@ +import { css } from '@emotion/react'; +import type { SearchHeaderProps } from '../../../../components/Atoms/SearchHeader'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the SearchHeader component +const searchHeaderStyleScript = (props: SearchHeaderProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // search header styles + const searchHeaderStyles = css({ + ...custom.styles.boxSizing('searchHeader', props?.treePath, props?.name), + em: { + fontStyle: 'normal', + }, + '.ss__search-header__title': { + margin: 0, + ...custom.styles.headerText(variables?.colors?.secondary, '22px'), + '& ~ .ss__search-header__subtitle': { + marginTop: `${custom.spacing.x2}px`, + }, + }, + '.ss__search-header__subtitle': { + margin: 0, + fontSize: '16px', + fontWeight: 400, + color: variables?.colors?.text, + a: { + color: variables?.colors?.primary, + }, + }, + '.ss__search-header__results-query': { + color: variables?.colors?.primary, + }, + }); + + return searchHeaderStyles; +}; + +// SearchHeader component props +export const searchHeader: ThemeComponent<'searchHeader', SearchHeaderProps> = { + default: { + searchHeader: { + themeStyleScript: searchHeaderStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/atoms/skeleton.ts b/packages/snap-preact/components/src/themes/pike/components/atoms/skeleton.ts new file mode 100644 index 000000000..859da1195 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/atoms/skeleton.ts @@ -0,0 +1,28 @@ +import { css } from '@emotion/react'; +import type { SkeletonProps } from '../../../../components/Atoms/Skeleton'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Skeleton component +const skeletonStyleScript = (props: SkeletonProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // skeleton styles + const skeletonStyles = css({ + ...custom.styles.boxSizing('skeleton', props?.treePath, props?.name), + }); + + return skeletonStyles; +}; + +// Skeleton component props +export const skeleton: ThemeComponent<'skeleton', SkeletonProps> = { + default: { + skeleton: { + themeStyleScript: skeletonStyleScript, + backgroundColor: custom.colors.gray01, + animatedColor: custom.colors.gray02, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/index.ts b/packages/snap-preact/components/src/themes/pike/components/index.ts new file mode 100644 index 000000000..b431ef8ce --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/index.ts @@ -0,0 +1,34 @@ +import { atoms } from './atoms'; +import { molecules } from './molecules'; +import { organisms } from './organisms'; +import { templates } from './templates'; + +import type { ThemeComponentsRestricted } from '../../../providers'; + +export const components: ThemeComponentsRestricted = { + ...atoms.default, + ...molecules.default, + ...organisms.default, + ...templates.default, +}; + +export const mobileComponents: ThemeComponentsRestricted = { + ...atoms.mobile, + ...molecules.mobile, + ...organisms.mobile, + ...templates.mobile, +}; + +export const tabletComponents: ThemeComponentsRestricted = { + ...atoms.tablet, + ...molecules.tablet, + ...organisms.tablet, + ...templates.tablet, +}; + +export const desktopComponents: ThemeComponentsRestricted = { + ...atoms.desktop, + ...molecules.desktop, + ...organisms.desktop, + ...templates.desktop, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/calloutBadge.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/calloutBadge.ts new file mode 100644 index 000000000..5c824aefc --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/calloutBadge.ts @@ -0,0 +1,27 @@ +import { css } from '@emotion/react'; +import type { CalloutBadgeProps } from '../../../../components/Molecules/CalloutBadge'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const calloutBadgeStyleScript = (props: CalloutBadgeProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // callout badge styles + const calloutBadgeStyles = css({ + gap: `${custom.spacing.x2}px`, + ...custom.styles.boxSizing('calloutBadge', props?.treePath, props?.name), + }); + + return calloutBadgeStyles; +}; + +// CalloutBadge component props +export const calloutBadge: ThemeComponent<'calloutBadge', CalloutBadgeProps> = { + default: { + calloutBadge: { + themeStyleScript: calloutBadgeStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/carousel.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/carousel.ts new file mode 100644 index 000000000..1ce85ee5e --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/carousel.ts @@ -0,0 +1,144 @@ +import { css } from '@emotion/react'; +import type { CarouselProps } from '../../../../components/Molecules/Carousel'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const carouselSpacing = custom.spacing.x2; +const carouselButtonSize = 32; +const carouselPaginationSize = 12; +const carouselPaginationSpacing = carouselSpacing + carouselPaginationSize; +const activeColors = custom.utils.activeColors(); +const buttonColor = activeColors[0]; +const fontColor = activeColors[1]; + +// CSS in JS style script for the Carousel component +const carouselStyleScript = (props: CarouselProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // carousel styles + const carouselStyles = css({ + position: 'relative', + width: '100%', + minWidth: '1px', + ...custom.styles.boxSizing('carousel', props?.treePath, props?.name), + '&:has(.swiper-pagination)': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + bottom: `${carouselPaginationSpacing}px`, + }, + '.swiper-container': { + paddingBottom: `${carouselPaginationSpacing}px`, + }, + }, + '.ss__carousel__prev-wrapper--hidden > div, .ss__carousel__next-wrapper--hidden > div': { + ...custom.styles.disabled(), + }, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + width: `${carouselButtonSize}px`, + height: `${carouselButtonSize}px`, + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + zIndex: 2, + margin: 'auto', + '& > div': { + display: 'flex', + flexFlow: 'column nowrap', + alignItems: 'center', + justifyContent: 'center', + padding: 0, + width: '100%', + height: '100%', + lineHeight: 1, + backgroundColor: buttonColor, + color: fontColor, + }, + '.swiper-button-disabled': { + ...custom.styles.disabled(), + }, + }, + '.ss__carousel__prev-wrapper': { + left: 0, + '& > div .ss__icon': { + left: '-1.5px', + }, + }, + '.ss__carousel__next-wrapper': { + right: 0, + '& > div .ss__icon': { + right: '-1.5px', + }, + }, + '.swiper-container': { + margin: '0 auto', + '& > .swiper-wrapper': { + '& > .swiper-slide': { + '& > *, .ss__result': { + padding: 0, + margin: 0, + width: 'auto', + height: '100%', + }, + }, + }, + '& > .swiper-pagination': { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + gap: `${custom.spacing.x1}px`, + '.swiper-pagination-bullet': { + opacity: 1, + flex: '0 1 auto', + width: `${carouselPaginationSize}px`, + height: `${carouselPaginationSize}px`, + lineHeight: `${carouselPaginationSize}px`, + minWidth: '1px', + margin: 0, + ...custom.styles.box('', 0, false), + }, + '.swiper-pagination-bullet-active': { + backgroundColor: variables?.colors?.primary, + borderColor: variables?.colors?.primary, + }, + }, + }, + '.swiper-grid-column': { + '& > .swiper-wrapper': { + flexFlow: 'row wrap', + '& > .swiper-slide': { + height: 'auto !important', + marginTop: '0 !important', + marginBottom: `${custom.spacing.x4}px`, + }, + }, + }, + }); + + return carouselStyles; +}; + +// Carousel component props +export const carousel: ThemeComponent<'carousel', CarouselProps> = { + default: { + carousel: { + themeStyleScript: carouselStyleScript, + speed: 600, + spaceBetween: carouselSpacing, + autoAdjustSlides: false, + centerInsufficientSlides: false, + }, + 'carousel icon': { + size: `${custom.sizes.icon08}px`, + }, + 'carousel icon.prev': { + icon: custom.icons.arrowLeft, + }, + 'carousel icon.next': { + icon: custom.icons.arrowRight, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/checkbox.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/checkbox.ts new file mode 100644 index 000000000..9945499bb --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/checkbox.ts @@ -0,0 +1,69 @@ +import { css } from '@emotion/react'; +import type { CheckboxProps } from '../../../../components/Molecules/Checkbox'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const darkGray = custom.utils.darkenColor(); + +// CSS in JS style script for the Checkbox component +const checkboxStyleScript = (props: CheckboxProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // shared styles + const sharedStyles = css({ + position: 'relative', + top: '-1px', + }); + + // default checkbox styles + const defaultCheckboxStyles = css([ + sharedStyles, + { + ...custom.styles.box('', 0), + ...custom.styles.boxSizing('checkbox', props?.treePath, props?.name), + '&.ss__checkbox--active': { + borderColor: darkGray, + }, + '&.ss__checkbox--disabled': { + ...custom.styles.disabled(), + }, + }, + ]); + + // native checkbox styles + const nativeCheckboxStyles = css([ + sharedStyles, + { + margin: 0, + padding: 0, + width: props?.size ? props.size : `${custom.sizes.icon16}px`, + height: props?.size ? props.size : `${custom.sizes.icon16}px`, + lineHeight: 1, + cursor: 'pointer', + ...custom.styles.boxSizing('checkbox', props?.treePath, props?.name), + '&.ss__checkbox--disabled': { + ...custom.styles.disabled(), + }, + }, + ]); + + return props?.native ? nativeCheckboxStyles : defaultCheckboxStyles; +}; + +// Checkbox component props +export const checkbox: ThemeComponent<'checkbox', CheckboxProps> = { + default: { + checkbox: { + themeStyleScript: checkboxStyleScript, + icon: custom.icons.check, + size: `${custom.sizes.icon16}px`, + color: custom.colors.primary, + }, + 'checkbox icon': { + width: `calc(50% + 1px)`, + height: `calc(50% + 1px)`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/errorHandler.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/errorHandler.ts new file mode 100644 index 000000000..5f89542d8 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/errorHandler.ts @@ -0,0 +1,58 @@ +import { css } from '@emotion/react'; +import type { ErrorHandlerProps } from '../../../../components/Molecules/ErrorHandler'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the ErrorHandler component +const errorHandlerStyleScript = (props: ErrorHandlerProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // error handler styles + const errorHandlerStyles = css({ + gap: `${custom.spacing.x2}px`, + padding: `${custom.spacing.x2}px`, + ...custom.styles.boxSizing('errorHandler', props?.treePath, props?.name), + '.ss__error-handler__message, .ss__error-handler__button': { + gap: `${custom.spacing.x1}px`, + }, + '.ss__error-handler__message': { + padding: 0, + flexFlow: 'row wrap', + flex: `1 1 0%`, + color: variables?.colors?.text, + 'span, .ss__icon, .ss__error-handler__message__type': { + margin: 0, + }, + '.ss__icon': { + top: '-0.5px', + stroke: 'transparent', + }, + }, + '.ss__error-handler__button': { + flex: `0 1 auto`, + margin: 0, + padding: `0 ${custom.spacing.x2}px`, + height: '28px', + lineHeight: '28px', + '.ss__button__content, .ss__icon': { + margin: 0, + }, + }, + }); + + return errorHandlerStyles; +}; + +// ErrorHandler component props +export const errorHandler: ThemeComponent<'errorHandler', ErrorHandlerProps> = { + default: { + errorHandler: { + themeStyleScript: errorHandlerStyleScript, + }, + 'errorHandler icon': { + width: `${custom.sizes.icon14}px`, + height: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/facetGridOptions.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/facetGridOptions.ts new file mode 100644 index 000000000..1560906f9 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/facetGridOptions.ts @@ -0,0 +1,61 @@ +import { css } from '@emotion/react'; +import type { FacetGridOptionsProps } from '../../../../components/Molecules/FacetGridOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const fontColor = activeColors[1]; + +// CSS in JS style script for the FacetGridOptions component +const facetGridOptionsStyleScript = (props: FacetGridOptionsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // facet grid styles + const facetGridStyles = css({ + alignItems: 'center', + ...custom.styles.boxSizing('facetGridOptions', props?.treePath, props?.name), + '.ss__facet-grid-options__option': { + height: '100%', + aspectRatio: 1, + padding: `${custom.spacing.x2}px`, + '&, .ss__facet-grid-options__option__value': { + overflow: 'hidden', + }, + '.ss__facet-grid-options__option__value': { + display: 'block', + maxWidth: '100%', + maxHeight: '100%', + color: 'inherit', + '&, &.ss__facet-grid-options__option__value--smaller': { + fontSize: '12px', + lineHeight: 1, + }, + }, + '&, &:hover:not(.ss__facet-grid-options__option--filtered)': { + ...custom.styles.box(variables?.colors?.text, 0), + }, + '&.ss__facet-grid-options__option--filtered': { + backgroundColor: activeColor, + borderColor: activeColor, + ...custom.styles.activeText(fontColor), + }, + }, + }); + + return facetGridStyles; +}; + +// FacetGridOptions component props +export const facetGridOptions: ThemeComponent<'facetGridOptions', FacetGridOptionsProps> = { + default: { + facetGridOptions: { + themeStyleScript: facetGridOptionsStyleScript, + columns: 0, + gridSize: '52px', + gapSize: `${custom.spacing.x1}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/facetHierarchyOptions.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/facetHierarchyOptions.ts new file mode 100644 index 000000000..db7bad7d8 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/facetHierarchyOptions.ts @@ -0,0 +1,118 @@ +import { css } from '@emotion/react'; +import type { FacetHierarchyOptionsProps } from '../../../../components/Molecules/FacetHierarchyOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const lightGray = custom.utils.lightenColor(); + +// CSS in JS style script for the FacetHierarchyOptions component +const facetHierarchyOptionsStyleScript = (props: FacetHierarchyOptionsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('facetHierarchyOptions', props?.treePath, props?.name), + '.ss__facet-hierarchy-options__option': { + lineHeight: 1.5, + color: variables?.colors?.text, + gap: `${custom.spacing.x1}px`, + padding: 0, + '.ss__facet-hierarchy-options__option__value': { + margin: 0, + '.ss__facet-hierarchy-options__option__value__count': { + position: 'relative', + top: '-1px', + margin: 0, + padding: `0 ${custom.spacing.x1}px`, + fontSize: '10px', + color: lightGray, + }, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--return': { + '.ss__icon': { + padding: 0, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--filtered': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }); + + // facet hierarchy list styles + const facetHierarchyListStyles = css([ + sharedStyles, + { + '.ss__facet-hierarchy-options__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__facet-hierarchy-options__option.ss__facet-hierarchy-options__option--filtered': { + '& ~ .ss__facet-hierarchy-options__option:not(.ss__facet-hierarchy-options__option--filtered)': { + paddingLeft: `${custom.spacing.x6}px`, + }, + }, + }, + ]); + + // facet hierarchy horizontal styles + const facetHierarchyHorizontalStyles = css([ + sharedStyles, + { + flexFlow: 'row wrap', + gap: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + '.ss__facet-hierarchy-options__option': { + flex: '0 1 auto', + width: `calc((100% - ${custom.spacing.x2}px) / 2)`, + minWidth: '1px', + margin: 0, + '&.ss__facet-hierarchy-options__option--return, &.ss__facet-hierarchy-options__option--filtered': { + width: '100%', + }, + '&.ss__facet-hierarchy-options__option--return': { + display: 'flex', + alignItems: 'center', + }, + '.ss__facet-hierarchy-options__option__value': { + display: 'block', + ...custom.styles.textOverflow(), + }, + }, + }, + { + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__facet-hierarchy-options__option': { + width: `calc((100% - ${custom.spacing.x2 * 2}px) / 3)`, + }, + }, + }, + { + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__facet-hierarchy-options__option': { + width: `calc((100% - ${custom.spacing.x2 * 3}px) / 4)`, + }, + }, + }, + ]); + + return props?.horizontal ? facetHierarchyHorizontalStyles : facetHierarchyListStyles; +}; + +// FacetHierarchyOptions component props +export const facetHierarchyOptions: ThemeComponent<'facetHierarchyOptions', FacetHierarchyOptionsProps> = { + default: { + facetHierarchyOptions: { + themeStyleScript: facetHierarchyOptionsStyleScript, + returnIcon: custom.icons.arrowLeft, + }, + 'facetHierarchyOptions icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/facetListOptions.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/facetListOptions.ts new file mode 100644 index 000000000..8606f426e --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/facetListOptions.ts @@ -0,0 +1,107 @@ +import { css } from '@emotion/react'; +import type { FacetListOptionsProps } from '../../../../components/Molecules/FacetListOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const lightGray = custom.utils.lightenColor(); +const checkboxSpacing = custom.sizes.icon16 + custom.spacing.x2; + +// CSS in JS style script for the FacetListOptions component +const facetListOptionsStyleScript = (props: FacetListOptionsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('facetListOptions', props?.treePath, props?.name), + '.ss__facet-list-options__option': { + lineHeight: 1.5, + color: variables?.colors?.text, + position: 'relative', + gap: `${custom.spacing.x1}px`, + padding: props?.hideCheckbox ? 0 : `0 0 0 ${checkboxSpacing}px`, + '.ss__checkbox, .ss__radio': { + position: 'absolute', + top: '1.5px', + left: 0, + }, + '.ss__facet-list-options__option__value': { + margin: 0, + '.ss__facet-list-options__option__value__count': { + position: 'relative', + top: `${props?.horizontal && props?.treePath?.includes('storybook') ? 0.5 : -1}px`, + margin: 0, + padding: `0 ${custom.spacing.x1}px`, + fontSize: '10px', + color: lightGray, + }, + }, + }, + '.ss__facet-list-options__option.ss__facet-list-options__option--filtered': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }); + + // facet list styles + const facetListStyles = css([ + sharedStyles, + { + '.ss__facet-list-options__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + ]); + + // facet horizontal styles + const facetListHorizontalStyles = css([ + sharedStyles, + { + flexFlow: 'row wrap', + gap: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + '.ss__facet-list-options__option': { + flex: '0 1 auto', + width: `calc((100% - ${custom.spacing.x2}px) / 2)`, + minWidth: '1px', + margin: 0, + '.ss__facet-list-options__option__value': { + display: 'flex', + alignItems: 'center', + '.ss__facet-list-options__option__value__label': { + ...custom.styles.textOverflow(), + }, + }, + }, + }, + { + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__facet-list-options__option': { + width: `calc((100% - ${custom.spacing.x2 * 2}px) / 3)`, + }, + }, + }, + { + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__facet-list-options__option': { + width: `calc((100% - ${custom.spacing.x2 * 3}px) / 4)`, + }, + }, + }, + ]); + + return props?.horizontal ? facetListHorizontalStyles : facetListStyles; +}; + +// FacetListOptions component props +export const facetListOptions: ThemeComponent<'facetListOptions', FacetListOptionsProps> = { + default: { + facetListOptions: { + themeStyleScript: facetListOptionsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/facetPaletteOptions.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/facetPaletteOptions.ts new file mode 100644 index 000000000..45364e1be --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/facetPaletteOptions.ts @@ -0,0 +1,259 @@ +import { css } from '@emotion/react'; +import type { FacetPaletteOptionsProps } from '../../../../components/Molecules/FacetPaletteOptions'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const lightGray = custom.utils.lightenColor(); +const paletteColors = { + brown: '#845329', + purple: '#7c368e', + rainbow: + 'linear-gradient(rgb(40, 87, 218) 20%, rgb(40, 218, 70) 20%, rgb(40, 218, 70) 40%, rgb(245, 228, 24) 40%, rgb(245, 228, 24) 60%, rgb(242, 133, 0) 60%, rgb(242, 133, 0) 80%, rgb(218, 40, 72) 80%, rgb(218, 40, 72))', +}; + +// CSS in JS style script for the FacetPaletteOptions component +const facetPaletteStyleScript = (props: FacetPaletteOptionsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const hasCheckbox = !props?.hideCheckbox ? true : false; + const isList = props?.layout == 'list' ? true : false; + const innerBorder = isList ? 3 : 5; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('facetPaletteOptions', props?.treePath, props?.name), + '.ss__facet-palette-options__option': { + color: variables?.colors?.text, + '&.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper .ss__facet-palette-options__option__palette': { + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + }, + '.ss__facet-palette-options__option__value': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + '.ss__facet-palette-options__option__wrapper': { + border: 0, + ...custom.styles.borderRadius(0), + '.ss__facet-palette-options__option__palette': { + overflow: 'hidden', + border: 0, + padding: 0, + '&, &:before, &:after': { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + ...custom.styles.borderRadius(0), + }, + '&:before, &:after': { + content: '""', + display: 'block', + }, + '&:before': { + border: `${innerBorder}px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '&[style*="url"]': { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + '.ss__image': { + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + }, + }, + '.ss__facet-palette-options__option__value__count': { + fontSize: '10px', + color: lightGray, + }, + }, + }); + + // facet palette grid styles + const facetPaletteGridStyles = css([ + sharedStyles, + { + alignItems: 'center', + '.ss__facet-palette-options__option': { + display: 'block', + textAlign: 'center', + '&, &.ss__facet-palette-options__option--filtered': { + '.ss__facet-palette-options__option__wrapper': { + position: 'relative', + height: 0, + padding: '0 0 100% 0', + }, + }, + '.ss__checkbox, .ss__radio': { + display: 'none', + }, + '.ss__facet-palette-options__option__value, .ss__facet-palette-options__option__value__count': { + display: 'block', + lineHeight: '0.85rem', + }, + '.ss__facet-palette-options__option__value': { + fontSize: '12px', + overflow: 'hidden', + margin: `${custom.spacing.x1}px 0 0 0`, + }, + '.ss__facet-palette-options__option__value__count': { + margin: `${custom.spacing.x1 / 2}px 0 0 0`, + }, + }, + }, + ]); + + // list variables + const listSize = hasCheckbox ? 16 : 22; + const listCheckboxSize = 16; + const listPadding = hasCheckbox ? custom.spacing.x4 + listSize + listCheckboxSize : custom.spacing.x2 + listSize; + + // facet palette shared list styles + const sharedListStyles = css({ + '.ss__facet-palette-options__option': { + lineHeight: 1.5, + minHeight: hasCheckbox ? '' : `${listSize + 2}px`, + position: 'relative', + gap: `${custom.spacing.x1}px`, + padding: `${hasCheckbox ? 0 : '2px'} 0 0 ${listPadding}px`, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__checkbox, .ss__radio, .ss__facet-palette-options__option__wrapper': { + position: 'absolute', + top: `${hasCheckbox ? 2 : 0.5}px`, + }, + '.ss__checkbox, .ss__radio': { + left: 0, + }, + '.ss__facet-palette-options__option__wrapper': { + left: hasCheckbox ? `${listCheckboxSize + custom.spacing.x2}px` : 0, + width: `${listSize}px`, + height: `${listSize}px`, + lineHeight: `${listSize}px`, + }, + '.ss__facet-palette-options__option__value, .ss__facet-palette-options__option__value__count': { + overflow: 'visible', + textOverflow: 'unset', + textAlign: 'left', + whiteSpace: 'unset', + }, + '.ss__facet-palette-options__option__value__count': { + position: 'relative', + top: props?.treePath == 'storybook facetPaletteOptions' ? '1px' : '', + margin: 0, + }, + }, + }); + + // facet palette list styles + const facetPaletteListStyles = css([ + sharedStyles, + sharedListStyles, + { + '&.ss__facet-palette-options--list': { + display: 'block', + }, + '.ss__facet-palette-options__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + ]); + + // facet palette list styles + const facetPaletteListHorizontalStyles = css([ + sharedStyles, + sharedListStyles, + { + flexFlow: 'row wrap', + gap: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + '.ss__facet-palette-options__option': { + flex: '0 1 auto', + width: `calc((100% - ${custom.spacing.x2}px) / 2)`, + minWidth: '1px', + margin: 0, + '.ss__facet-palette-options__option__value': { + ...custom.styles.textOverflow(), + }, + }, + }, + { + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__facet-palette-options__option': { + width: `calc((100% - ${custom.spacing.x2 * 2}px) / 3)`, + }, + }, + }, + { + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__facet-palette-options__option': { + width: `calc((100% - ${custom.spacing.x2 * 3}px) / 4)`, + }, + }, + }, + ]); + + if (isList) { + return props?.horizontal ? facetPaletteListHorizontalStyles : facetPaletteListStyles; + } else { + return facetPaletteGridStyles; + } +}; + +// FacetPaletteOptions component props +export const facetPaletteOptions: ThemeComponent<'facetPaletteOptions', FacetPaletteOptionsProps> = { + default: { + facetPaletteOptions: { + themeStyleScript: facetPaletteStyleScript, + hideIcon: true, + columns: 0, + gridSize: '52px', + gapSize: `${custom.spacing.x1}px`, + colorMapping: { + brown: { + background: paletteColors.brown, + }, + multi: { + background: paletteColors.rainbow, + }, + 'multi-color': { + background: paletteColors.rainbow, + }, + purple: { + background: paletteColors.purple, + }, + rainbow: { + background: paletteColors.rainbow, + }, + }, + }, + 'facetPaletteOptions checkbox icon': { + color: custom.colors.primary, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/facetSlider.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/facetSlider.ts new file mode 100644 index 000000000..f51544ea2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/facetSlider.ts @@ -0,0 +1,196 @@ +import { css } from '@emotion/react'; +import type { FacetSliderProps } from '../../../../components/Molecules/FacetSlider'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// slider options +const slider = { + handles: 20, // handle size + handleInner: 7, // handle inner size, + values: 14, // values size + bar: 6, // bar size + ticks: 17, // size of ticks + valuesPosition: 'top', // position of slider values (top or bottom) + valuesAlign: 'sides', // alignment of slider values (sides or center) +}; + +// value settings +const valuesTop = slider.valuesPosition == 'top' ? true : false; +const valuesSides = slider.valuesAlign == 'sides' ? true : false; + +// spacing and size calculations +const handlesSizeHalf = (slider.handles - slider.bar) / 2; +const handlesSpacing = slider.handles + custom.spacing.x2; +const ticksSpacing = slider.ticks + custom.spacing.x1; +const stickySpacing = slider.values + custom.spacing.x2; +const handlesPlusSticky = handlesSizeHalf + stickySpacing; +const ticksPlusSticky = ticksSpacing + stickySpacing; + +// CSS in JS style script for the FacetSlider component +const facetSliderStyleScript = (props: FacetSliderProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const hasTicks = props?.showTicks ? true : false; + const hasStickyHandles = props?.stickyHandleLabel ? true : false; + const trackBorderColor = props?.trackColor != custom.colors.gray01 ? custom.utils.darkenColor(props.trackColor, 0.25) : custom.colors.gray02; + const activeColors = custom.utils.activeColors(props?.handleColor); + + // values font styles + const valuesStyles = css({ + fontSize: `${slider.values}px`, + lineHeight: `${slider.values}px`, + }); + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('facetSlider', props?.treePath, props?.name), + '&, .ss__facet-slider__slider': { + margin: 'auto', + }, + '.ss__facet-slider__slider button, .ss__facet-slider__labels label': { + margin: 0, + padding: 0, + '&:focus': { + outline: 0, + }, + }, + '.ss__facet-slider__slider': { + display: 'block', + top: 0, + width: '100%', + height: `${slider.bar}px`, + '.ss__facet-slider__segment, .ss__facet-slider__rail, .ss__facet-slider__handles': { + height: '100%', + }, + '.ss__facet-slider__tick': { + '&:before, .ss__facet-slider__tick__label': { + transform: 'translate(-50%, 0)', + }, + '&:before': { + top: `${slider.ticks / 2}px`, + backgroundColor: custom.colors.gray02, + }, + '.ss__facet-slider__tick__label': { + top: `${slider.ticks}px`, + lineHeight: 1, + }, + }, + '.ss__facet-slider__segment': { + border: `1px solid ${trackBorderColor}`, + ...custom.styles.borderRadius(slider.bar), + }, + '.ss__facet-slider__rail': {}, + '.ss__facet-slider__handles': { + position: 'relative', + margin: `0 ${slider.handles / 2 - 2}px`, + button: { + '.ss__facet-slider__handle': { + transform: 'none', + width: `${slider.handles}px`, + height: `${slider.handles}px`, + lineHeight: `${slider.handles}px`, + '&:after': { + width: `${slider.handleInner}px`, + height: `${slider.handleInner}px`, + backgroundColor: activeColors[1], + }, + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + backgroundColor: 'transparent', + '&': { + ...valuesStyles, + }, + }, + }, + }, + }, + }, + '.ss__facet-slider__labels': { + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + justifyContent: valuesSides ? '' : 'center', + '.ss__facet-slider__label': { + '&': { + ...valuesStyles, + }, + '&:after': { + display: valuesSides ? 'none' : '', + padding: `0 ${custom.spacing.x1}px`, + }, + '& ~ .ss__facet-slider__label': { + marginLeft: valuesSides ? 'auto' : '', + }, + }, + }, + }); + + // spacing styles for different configurations + // note: default for facet slider is no ticks, no stick handles, values bottom + let spacingStyles = css({}); + + if (hasTicks && hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${valuesTop ? handlesPlusSticky : handlesSizeHalf}px auto ${valuesTop ? ticksSpacing : ticksPlusSticky}px auto`, + '.ss__facet-slider__handles button .ss__facet-slider__handle': { + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + top: valuesTop ? `auto` : `${handlesSizeHalf + ticksPlusSticky - slider.bar}px`, + bottom: valuesTop ? `${handlesSpacing}px` : ``, + }, + }, + }, + }); + } else if (hasTicks && !hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${handlesSizeHalf}px auto ${ticksSpacing}px auto`, + }, + '.ss__facet-slider__labels': { + order: valuesTop ? -1 : '', + margin: `${valuesTop ? 0 : custom.spacing.x2}px 0 ${valuesTop ? custom.spacing.x2 : 0}px 0`, + }, + }); + } else if (!hasTicks && hasStickyHandles) { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${valuesTop ? handlesPlusSticky : handlesSizeHalf}px auto ${valuesTop ? handlesSizeHalf : handlesPlusSticky}px auto`, + '.ss__facet-slider__handles button .ss__facet-slider__handle': { + '.ss__facet-slider__handle__label.ss__facet-slider__handle__label--sticky': { + top: valuesTop ? 'auto' : `${handlesSpacing}px`, + bottom: valuesTop ? `${handlesSpacing}px` : ``, + }, + }, + }, + }); + } else { + spacingStyles = css({ + '.ss__facet-slider__slider': { + margin: `${handlesSizeHalf}px auto`, + }, + '.ss__facet-slider__labels': { + order: valuesTop ? -1 : '', + margin: `${valuesTop ? 0 : custom.spacing.x2}px 0 ${valuesTop ? custom.spacing.x2 : 0}px 0`, + }, + }); + } + + // facet slider styles + const facetSliderStyles = css([sharedStyles, spacingStyles]); + + return facetSliderStyles; +}; + +// FacetSlider component props +export const facetSlider: ThemeComponent<'facetSlider', FacetSliderProps> = { + default: { + facetSlider: { + themeStyleScript: facetSliderStyleScript, + handleColor: custom.colors.primary, + handleDraggingColor: custom.colors.primary, + trackColor: custom.colors.gray01, + railColor: custom.colors.secondary, + tickTextColor: custom.colors.text, + valueTextColor: custom.colors.text, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/filter.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/filter.ts new file mode 100644 index 000000000..08ec80c8a --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/filter.ts @@ -0,0 +1,56 @@ +import { css } from '@emotion/react'; +import type { FilterProps } from '../../../../components/Molecules/Filter'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Filter component +const filterStyleScript = (props: FilterProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // filter styles + const filterStyles = css({ + ...custom.styles.boxSizing('filter', props?.treePath, props?.name), + '&, .ss__filter__button': { + padding: 0, + }, + '&.ss__filter-summary__clear-all .ss__filter__button .ss__button__content .ss__filter__value': { + margin: 0, + }, + '.ss__filter__button': { + position: 'relative', + height: 'auto', + lineHeight: 1.5, + fontWeight: 'normal', + color: variables?.colors?.text, + '&, &:hover, &:not(.ss__button--disabled):hover, &.ss__button--disabled': { + backgroundColor: 'transparent', + borderColor: 'transparent', + }, + '.ss__button__content': { + position: 'relative', + '.ss__filter__button__icon, .ss__filter__label, .ss__filter__value': { + margin: 0, + }, + '.ss__filter__label': { + fontWeight: custom.fonts.weight01, + }, + }, + }, + }); + + return filterStyles; +}; + +// Filter component props +export const filter: ThemeComponent<'filter', FilterProps> = { + default: { + filter: { + themeStyleScript: filterStyleScript, + icon: custom.icons.close, + }, + 'filter icon': { + size: `${custom.sizes.icon10}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/grid.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/grid.ts new file mode 100644 index 000000000..ee397017b --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/grid.ts @@ -0,0 +1,221 @@ +import { css } from '@emotion/react'; +import type { GridProps } from '../../../../components/Molecules/Grid'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const gridSize = 42; +const gridSelector = 'ss__grid__option'; +const darkSelector = `&.${gridSelector}--dark, &:has(.${gridSelector}__inner--grey), &:has(.${gridSelector}__inner--gray)`; +const imageSelector = '&:has(.ss__image)'; +const urlSelector = '&[style*="url"]'; +const styleSelector = '&[style], &:has(.ss__image)'; +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const fontColor = activeColors[1]; + +// CSS in JS style script for the Grid component +const gridStyleScript = (props: Partial) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('grid', props?.treePath, props?.name), + '.ss__grid__title': { + margin: `0 0 ${custom.spacing.x2}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + }, + '.ss__grid__options .ss__grid__option .ss__grid__option__inner .ss__grid__option__label, .ss__grid__show-more-wrapper': { + fontSize: '12px', + lineHeight: 1, + }, + '.ss__grid__options': { + '.ss__grid__option': { + '&, &.ss__grid__option--selected': { + border: 0, + }, + }, + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + position: 'relative', + '.ss__grid__option__inner': { + position: 'relative', + width: '100%', + ...custom.styles.box(variables?.colors?.text, `${custom.spacing.x1}px`), + '&, .ss__grid__option__label': { + overflow: 'hidden', + }, + '.ss__grid__option__label': { + maxWidth: '100%', + maxHeight: '100%', + }, + [styleSelector]: { + border: 0, + backgroundColor: 'transparent', + '&:before, &:after': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + ...custom.styles.borderRadius(), + }, + '&:before': { + border: `3px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '.ss__grid__option__label': { + ...custom.styles.srOnly(), + }, + }, + [`${urlSelector}, ${imageSelector}`]: { + '&:before': { + margin: 0, + borderWidth: '4px', + }, + }, + [urlSelector]: { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + [imageSelector]: { + '&:before, &:after': { + zIndex: 3, + }, + '.ss__image, .ss__grid__option__label': { + position: 'absolute', + }, + '.ss__image': { + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 1, + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + '.ss__grid__option__label': { + zIndex: 2, + }, + }, + }, + [darkSelector]: { + '.ss__grid__option__inner': { + color: fontColor, + }, + }, + '&.ss__grid__option--disabled, &.ss__grid__option--unavailable': { + opacity: 1, + '&, &:before, &:after, *': { + pointerEvents: 'unset', + cursor: 'not-allowed !important', + }, + '&:before': { + maxWidth: `${gridSize - 4}px`, + top: 0, + bottom: 0, + zIndex: 3, + margin: 'auto 0', + borderTop: `2px solid ${custom.colors.white}`, + outlineColor: custom.colors.gray02, + ...custom.styles.borderRadius(3), + }, + '.ss__grid__option__inner': { + opacity: 0.65, + }, + }, + '&.ss__grid__option--selected': { + '.ss__grid__option__inner': { + borderColor: activeColor, + backgroundColor: activeColor, + color: fontColor, + [styleSelector]: { + border: 0, + backgroundColor: 'transparent', + color: variables?.colors?.text, + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + }, + '.ss__grid__option__label': { + fontWeight: custom.fonts.weight01, + }, + }, + [darkSelector]: { + '.ss__grid__option__inner': { + color: fontColor, + }, + }, + }, + }, + }, + '.ss__grid__show-more-wrapper': { + '&:not(.ss__grid__option)': { + margin: `${custom.spacing.x1}px 0 0 0`, + }, + '&, .ss__grid__show-more': { + cursor: 'pointer', + }, + '.ss__grid__show-more': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }); + + // grid styles + const gridStyles = css([ + sharedStyles, + { + '.ss__grid__options': { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + '&:before, &:after': { + display: 'none', + }, + '.ss__grid__option': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + width: `${gridSize}px`, + maxHeight: `${gridSize}px`, + height: '100%', + aspectRatio: 1, + }, + }, + }, + ]); + + // grid column styles + const gridColumnStyles = css([sharedStyles]); + + return props?.columns ? gridColumnStyles : gridStyles; +}; + +// Grid component props +export const grid: ThemeComponent<'grid', GridProps> = { + default: { + grid: { + themeStyleScript: gridStyleScript, + columns: 0, + gapSize: `${custom.spacing.x1}px`, + hideLabels: false, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/index.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/index.ts new file mode 100644 index 000000000..ec794bac9 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/index.ts @@ -0,0 +1,164 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// MOLECULES Imports +import { calloutBadge } from './calloutBadge'; +import { carousel } from './carousel'; +import { checkbox } from './checkbox'; +import { errorHandler } from './errorHandler'; +import { facetGridOptions } from './facetGridOptions'; +import { facetHierarchyOptions } from './facetHierarchyOptions'; +import { facetListOptions } from './facetListOptions'; +import { facetPaletteOptions } from './facetPaletteOptions'; +import { facetSlider } from './facetSlider'; +import { filter } from './filter'; +import { grid } from './grid'; +import { layoutSelector } from './layoutSelector'; +import { list } from './list'; +import { loadMore } from './loadMore'; +import { modal } from './modal'; +import { overlayBadge } from './overlayBadge'; +import { pagination } from './pagination'; +import { perPage } from './perPage'; +import { radio } from './radio'; +import { radioList } from './radioList'; +import { result } from './result'; +import { searchInput } from './searchInput'; +import { select } from './select'; +import { slideshow } from './slideshow'; +import { slideout } from './slideout'; +import { sortBy } from './sortBy'; +import { rating } from './rating'; +import { swatches } from './swatches'; +import { variantSelection } from './variantSelection'; +import { terms } from './terms'; + +export const molecules: ThemeResponsiveComplete = { + default: { + ...calloutBadge.default, + ...carousel.default, + ...checkbox.default, + ...errorHandler.default, + ...facetGridOptions.default, + ...facetHierarchyOptions.default, + ...facetListOptions.default, + ...facetPaletteOptions.default, + ...facetSlider.default, + ...filter.default, + ...grid.default, + ...layoutSelector.default, + ...list.default, + ...loadMore.default, + ...modal.default, + ...overlayBadge.default, + ...pagination.default, + ...perPage.default, + ...radio.default, + ...radioList.default, + ...rating.default, + ...result.default, + ...searchInput.default, + ...select.default, + ...slideshow.default, + ...slideout.default, + ...sortBy.default, + ...swatches.default, + ...terms.default, + ...variantSelection.default, + }, + mobile: { + ...calloutBadge.mobile, + ...carousel.mobile, + ...checkbox.mobile, + ...errorHandler.mobile, + ...facetGridOptions.mobile, + ...facetHierarchyOptions.mobile, + ...facetListOptions.mobile, + ...facetPaletteOptions.mobile, + ...facetSlider.mobile, + ...filter.mobile, + ...grid.mobile, + ...layoutSelector.mobile, + ...list.mobile, + ...loadMore.mobile, + ...modal.mobile, + ...overlayBadge.mobile, + ...pagination.mobile, + ...perPage.mobile, + ...radio.mobile, + ...radioList.mobile, + ...rating.mobile, + ...result.mobile, + ...searchInput.mobile, + ...select.mobile, + ...slideshow.mobile, + ...slideout.mobile, + ...sortBy.mobile, + ...swatches.mobile, + ...terms.mobile, + ...variantSelection.mobile, + }, + tablet: { + ...calloutBadge.tablet, + ...carousel.tablet, + ...checkbox.tablet, + ...errorHandler.tablet, + ...facetGridOptions.tablet, + ...facetHierarchyOptions.tablet, + ...facetListOptions.tablet, + ...facetPaletteOptions.tablet, + ...facetSlider.tablet, + ...filter.tablet, + ...grid.tablet, + ...layoutSelector.tablet, + ...list.tablet, + ...loadMore.tablet, + ...modal.tablet, + ...overlayBadge.tablet, + ...pagination.tablet, + ...perPage.tablet, + ...radio.tablet, + ...radioList.tablet, + ...rating.tablet, + ...result.tablet, + ...searchInput.tablet, + ...select.tablet, + ...slideshow.tablet, + ...slideout.tablet, + ...sortBy.tablet, + ...swatches.tablet, + ...terms.tablet, + ...variantSelection.tablet, + }, + desktop: { + ...calloutBadge.desktop, + ...carousel.desktop, + ...checkbox.desktop, + ...errorHandler.desktop, + ...facetGridOptions.desktop, + ...facetHierarchyOptions.desktop, + ...facetListOptions.desktop, + ...facetPaletteOptions.desktop, + ...facetSlider.desktop, + ...filter.desktop, + ...grid.desktop, + ...layoutSelector.desktop, + ...list.desktop, + ...loadMore.desktop, + ...modal.desktop, + ...overlayBadge.desktop, + ...pagination.desktop, + ...perPage.desktop, + ...radio.desktop, + ...radioList.desktop, + ...rating.desktop, + ...result.desktop, + ...searchInput.desktop, + ...select.desktop, + ...slideshow.desktop, + ...slideout.desktop, + ...sortBy.desktop, + ...swatches.desktop, + ...terms.desktop, + ...variantSelection.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/layoutSelector.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/layoutSelector.ts new file mode 100644 index 000000000..56b7cfd5b --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/layoutSelector.ts @@ -0,0 +1,88 @@ +import { css } from '@emotion/react'; +import type { LayoutSelectorProps } from '../../../../components/Molecules/LayoutSelector'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const activeIconColor = activeColors[1]; + +// CSS in JS style script for the LayoutSelector component +const layoutSelectorStyleScript = (props: LayoutSelectorProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('layoutSelector', props?.treePath, props?.name), + }); + + // dropdown styles + const dropdownStyles = css([ + sharedStyles, + { + '.ss__dropdown': { + '.ss__dropdown__button .ss__button__content .ss__select__label': { + paddingRight: `${custom.spacing.x1 / 2}px`, + }, + }, + }, + ]); + + // radio styles + const radioStyles = css([sharedStyles]); + + // list styles + const listStyles = css([ + sharedStyles, + { + '.ss__list__options': { + display: 'flex', + '.ss__list__option': { + ...custom.styles.box(variables?.colors?.text, `0 ${custom.spacing.x2}px`), + margin: 0, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + }, + '.ss__list__option--selected': { + '&, &:hover': { + borderColor: activeColor, + backgroundColor: activeColor, + color: activeIconColor, + }, + '&, *': { + cursor: 'text', + }, + }, + }, + }, + ]); + + if (props?.type == 'list') { + return listStyles; + } else if (props?.type == 'radio') { + return radioStyles; + } else { + return dropdownStyles; + } +}; + +// LayoutSelector component props +export const layoutSelector: ThemeComponent<'layoutSelector', LayoutSelectorProps> = { + default: { + layoutSelector: { + themeStyleScript: layoutSelectorStyleScript, + }, + 'layoutSelector select': { + hideSelection: false, + }, + 'layoutSelector list': { + hideTitleText: true, + hideOptionLabels: true, + }, + 'layoutSelector radioList': { + hideTitleText: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/list.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/list.ts new file mode 100644 index 000000000..0ebcfb1c4 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/list.ts @@ -0,0 +1,123 @@ +import { css } from '@emotion/react'; +import type { ListProps } from '../../../../components/Molecules/List'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const checkboxSpacing = custom.sizes.icon16 + custom.spacing.x2; + +// CSS in JS style script for the List component +const listStyleScript = (props: ListProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('list', props?.treePath, props?.name), + '.ss__list__title, .ss__list__options': { + width: '100%', + }, + '.ss__list__title, .ss__list__options .ss__list__option': { + padding: 0, + }, + '.ss__list__title': { + margin: `0 0 ${custom.spacing.x2}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + }, + '.ss__list__options': { + '.ss__list__option': { + position: 'relative', + lineHeight: 1.5, + color: variables?.colors?.text, + gap: `${custom.spacing.x2}px`, + padding: props?.hideOptionCheckboxes ? `` : `0 0 0 ${checkboxSpacing}px`, + '.ss__list__option__label, .ss__list__option__icon': { + padding: 0, + }, + '.ss__checkbox': { + position: 'absolute', + top: '1.5px', + left: 0, + }, + '.ss__list__option__icon': { + position: 'relative', + top: '-1px', + }, + }, + '.ss__list__option--disabled': { + ...custom.styles.disabled(), + }, + '.ss__list__option--selected': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }); + + // list styles + const listStyles = css([ + sharedStyles, + { + '&, .ss__list__options, .ss__list__title': { + display: 'block', + }, + '.ss__list__options': { + '.ss__list__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + }, + ]); + + // list horizontal styles + const listHorizontalStyles = css([ + sharedStyles, + { + '&, .ss__list__title': { + display: 'block', + }, + '.ss__list__options': { + flexFlow: 'row wrap', + gap: `${custom.spacing.x1}px ${custom.spacing.x2}px`, + '.ss__list__option': { + flex: '0 1 auto', + width: `calc((100% - ${custom.spacing.x2}px) / 2)`, + minWidth: '1px', + margin: 0, + '.ss__list__option__label': { + ...custom.styles.textOverflow(), + }, + }, + }, + }, + { + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__list__options .ss__list__option': { + width: `calc((100% - ${custom.spacing.x2 * 2}px) / 3)`, + }, + }, + }, + { + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__list__options .ss__list__option': { + width: `calc((100% - ${custom.spacing.x2 * 3}px) / 4)`, + }, + }, + }, + ]); + + return props?.horizontal ? listHorizontalStyles : listStyles; +}; + +// List component props +export const list: ThemeComponent<'list', ListProps> = { + default: { + list: { + themeStyleScript: listStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/loadMore.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/loadMore.ts new file mode 100644 index 000000000..79ca7e62c --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/loadMore.ts @@ -0,0 +1,56 @@ +import { css } from '@emotion/react'; +import type { LoadMoreProps } from '../../../../components/Molecules/LoadMore'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the LoadMore component +const loadMoreStyleScript = (props: LoadMoreProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const borderColor = props?.backgroundColor != custom.colors.gray01 ? custom.utils.darkenColor(props.backgroundColor, 0.25) : custom.colors.gray02; + + // load more styles + const loadMoreStyles = css({ + ...custom.styles.boxSizing('loadMore', props?.treePath, props?.name), + '&.ss__load-more': { + '&, .ss__load-more__progress': { + gap: `${custom.spacing.x2}px`, + }, + '.ss__load-more__icon': { + margin: 0, + }, + '.ss__load-more__progress': { + '.ss__load-more__progress__indicator': { + margin: '0 auto', + border: `1px solid ${borderColor}`, + ...custom.styles.borderRadius(5), + '.ss__load-more__progress__indicator__bar': { + margin: '-1px', + }, + }, + '.ss__load-more__progress__text': { + color: variables?.colors?.text, + }, + }, + }, + }); + + return loadMoreStyles; +}; + +// LoadMore component props +export const loadMore: ThemeComponent<'loadMore', LoadMoreProps> = { + default: { + loadMore: { + themeStyleScript: loadMoreStyleScript, + color: custom.colors.primary, + backgroundColor: custom.colors.gray01, + }, + 'loadMore icon': { + color: custom.colors.primary, + }, + 'loadMore button icon': { + color: 'currentColor', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/modal.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/modal.ts new file mode 100644 index 000000000..e7ff51a17 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/modal.ts @@ -0,0 +1,29 @@ +import { css } from '@emotion/react'; +import type { ModalProps } from '../../../../components/Molecules/Modal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Modal component +const modalStyleScript = (props: ModalProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // modal styles + const modalStyles = css({ + cursor: 'pointer', + color: variables?.colors?.text, + ...custom.styles.boxSizing('modal', props?.treePath, props?.name), + }); + + return modalStyles; +}; + +// Modal component props +export const modal: ThemeComponent<'modal', ModalProps> = { + default: { + modal: { + themeStyleScript: modalStyleScript, + overlayColor: 'rgba(0, 0, 0, 0.80)', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/overlayBadge.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/overlayBadge.ts new file mode 100644 index 000000000..a2d5fa77e --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/overlayBadge.ts @@ -0,0 +1,34 @@ +import { css } from '@emotion/react'; +import type { OverlayBadgeProps } from '../../../../components/Molecules/OverlayBadge'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const overlayBadgeStyleScript = (props: OverlayBadgeProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // overlay badge styles + const overlayBadgeStyles = css({ + ...custom.styles.boxSizing('overlayBadge', props?.treePath, props?.name), + '.ss__overlay-badge__grid-wrapper': { + zIndex: 1, + gap: `${custom.spacing.x2}px`, + bottom: 'auto', + '.ss__overlay-badge__grid-wrapper__slot': { + gap: `${custom.spacing.x1}px`, + }, + }, + }); + + return overlayBadgeStyles; +}; + +// OverlayBadge component props +export const overlayBadge: ThemeComponent<'overlayBadge', OverlayBadgeProps> = { + default: { + overlayBadge: { + themeStyleScript: overlayBadgeStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/pagination.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/pagination.ts new file mode 100644 index 000000000..2dbb5479d --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/pagination.ts @@ -0,0 +1,71 @@ +import { css } from '@emotion/react'; +import type { PaginationProps } from '../../../../components/Molecules/Pagination'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Pagination component +const paginationStyleScript = (props: PaginationProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + const paginationStyles = css({ + ...custom.styles.boxSizing('pagination', props?.treePath, props?.name), + nav: { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + justifyContent: 'center', + gap: `${custom.spacing.x4}px`, + '.ss__pagination__page, span': { + padding: 0, + fontSize: '16px', + color: variables?.colors?.text, + }, + '.ss__pagination__page': { + minWidth: '1px', + minHeight: '1px', + '&.ss__pagination__page--active': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + '.ss__pagination__page--previous, .ss__pagination__page--next': { + lineHeight: `10px`, + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + nav: { + gap: `${custom.spacing.x2}px`, + '.ss__pagination__page, span': { + fontSize: '14px', + }, + }, + }, + }); + + return paginationStyles; +}; + +// Pagination component props +export const pagination: ThemeComponent<'pagination', PaginationProps> = { + default: { + pagination: { + themeStyleScript: paginationStyleScript, + }, + 'pagination icon': { + size: `${custom.sizes.icon12}px`, + color: custom.colors.primary, + }, + 'pagination icon.prev': { + icon: custom.icons.arrowLeft, + }, + 'pagination icon.next': { + icon: custom.icons.arrowRight, + }, + }, + mobile: { + 'pagination icon': { + size: `${custom.sizes.icon14}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/perPage.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/perPage.ts new file mode 100644 index 000000000..3854de64d --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/perPage.ts @@ -0,0 +1,26 @@ +import { css } from '@emotion/react'; +import type { PerPageProps } from '../../../../components/Molecules/PerPage'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the PerPage component +const perPageStyleScript = (props: PerPageProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // perPage styles + const perPageStyles = css({ + ...custom.styles.boxSizing('perPage', props?.treePath, props?.name), + }); + + return perPageStyles; +}; + +// PerPage component props +export const perPage: ThemeComponent<'perPage', PerPageProps> = { + default: { + perPage: { + themeStyleScript: perPageStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/radio.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/radio.ts new file mode 100644 index 000000000..328a1624f --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/radio.ts @@ -0,0 +1,74 @@ +import { css } from '@emotion/react'; +import type { RadioProps } from '../../../../components/Molecules/Radio'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const darkGray = custom.utils.darkenColor(); + +// CSS in JS style script for the Radio component +const radioStyleScript = (props: RadioProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // default radio styles + const defaultRadiosStyles = css([ + { + position: 'relative', + top: '-1px', + ...custom.styles.box('', 0), + ...custom.styles.borderRadius(50, '%'), + ...custom.styles.boxSizing('radio', props?.treePath, props?.name), + '&.ss__radio--disabled': { + ...custom.styles.disabled(), + }, + '&.ss__radio--active': { + borderColor: darkGray, + '.ss__icon': { + opacity: 1, + }, + }, + '.ss__icon': { + opacity: 0, + }, + }, + ]); + + // native radio styles + const nativeRadiosStyles = css([ + { + lineHeight: 0, + ...custom.styles.boxSizing('radio', props?.treePath, props?.name), + '&.ss__radio--disabled .ss__radio__input': { + ...custom.styles.disabled(), + }, + '.ss__radio__input': { + margin: 0, + padding: 0, + width: props?.size ? props.size : `${custom.sizes.icon16}px`, + height: props?.size ? props.size : `${custom.sizes.icon16}px`, + lineHeight: 1, + cursor: 'pointer', + }, + }, + ]); + + return props?.native ? nativeRadiosStyles : defaultRadiosStyles; +}; + +// Radio component props +export const radio: ThemeComponent<'radio', RadioProps> = { + default: { + radio: { + themeStyleScript: radioStyleScript, + checkedIcon: 'circle', + unCheckedIcon: 'circle', + size: `${custom.sizes.icon16}px`, + color: custom.colors.primary, + }, + 'radio icon': { + width: `calc(50% + 1px)`, + height: `calc(50% + 1px)`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/radioList.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/radioList.ts new file mode 100644 index 000000000..d70670f8d --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/radioList.ts @@ -0,0 +1,76 @@ +import { css } from '@emotion/react'; +import type { RadioListProps } from '../../../../components/Molecules/RadioList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const radioSpacing = custom.sizes.icon16 + custom.spacing.x2; + +// CSS in JS style script for the RadioList component +const radioListStyleScript = (props: RadioListProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // radio list styles + const radioListStyles = css({ + ...custom.styles.boxSizing('radioList', props?.treePath, props?.name), + '&, .ss__radio-list__options-wrapper, .ss__radio-list__title': { + display: 'block', + }, + '&.ss__radio-list--disabled': { + ...custom.styles.disabled(), + }, + '.ss__radio-list__title, .ss__radio-list__options-wrapper': { + width: '100%', + }, + '.ss__radio-list__title, .ss__radio-list__options-wrapper .ss__radio-list__option': { + padding: 0, + }, + '.ss__radio-list__title': { + margin: `0 0 ${custom.spacing.x2}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + }, + '.ss__radio-list__options-wrapper': { + '.ss__radio-list__option': { + position: 'relative', + lineHeight: 1.5, + color: variables?.colors?.text, + gap: `${custom.spacing.x2}px`, + margin: `0 0 ${custom.spacing.x1}px 0`, + padding: props?.hideOptionRadios ? `` : `0 0 0 ${radioSpacing}px`, + '&:last-of-type': { + marginBottom: 0, + }, + '.ss__radio-list__option__label, .ss__radio-list__option__icon': { + padding: 0, + }, + '.ss__radio': { + position: 'absolute', + top: '1.5px', + left: 0, + '&:has(.ss__radio__input)': { + top: '2.5px', + }, + }, + '.ss__radio-list__option__icon': { + position: 'relative', + top: '-1px', + }, + }, + '.ss__radio-list__option--selected': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }); + + return radioListStyles; +}; + +// RadioList component props +export const radioList: ThemeComponent<'radioList', RadioListProps> = { + default: { + radioList: { + themeStyleScript: radioListStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/rating.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/rating.ts new file mode 100644 index 000000000..f9138139b --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/rating.ts @@ -0,0 +1,56 @@ +import { css } from '@emotion/react'; +import type { RatingProps } from '../../../../components/Molecules/Rating'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const darkGray = custom.utils.darkenColor(); + +// CSS in JS style script for the Rating component +const ratingStyleScript = (props: RatingProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // rating styles + const ratingStyles = css({ + flexWrap: 'wrap', + gap: `${custom.spacing.x1}px`, + lineHeight: 1, + ...custom.styles.boxSizing('rating', props?.treePath, props?.name), + '.ss__rating__icons': { + '&, .ss__rating__stars .ss__rating__stars__star': { + lineHeight: 0, + }, + '.ss__rating__stars': { + gap: '2px', + gridTemplateColumns: 'repeat(5, 1fr)', + }, + }, + '.ss__rating__count, .ss__rating__text': { + fontSize: '12px', + color: variables?.colors?.text, + }, + }); + + return ratingStyles; +}; + +// Rating component props +export const rating: ThemeComponent<'rating', RatingProps> = { + default: { + rating: { + themeStyleScript: ratingStyleScript, + emptyIcon: 'star', + fullIcon: 'star', + }, + 'rating icon': { + size: `${custom.sizes.icon14}px`, + }, + 'rating icon.star--empty': { + color: darkGray, + }, + 'rating icon.star--full': { + color: custom.colors.primary, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/result.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/result.ts new file mode 100644 index 000000000..c61e3a3d2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/result.ts @@ -0,0 +1,182 @@ +import { css } from '@emotion/react'; +import type { ResultProps } from '../../../../components/Molecules/Result'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const lightGray = custom.utils.lightenColor(); + +// CSS in JS style script for the Result component +const resultStyleScript = (props: ResultProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // result styles + const resultStyles = css({ + ...custom.styles.boxSizing('result', props?.treePath, props?.name), + '&.ss__result--sale': { + '.ss__result__details': { + '.ss__result__details__pricing': { + '.ss__result__price:not(.ss__price--strike)': { + '&, span': { + color: variables?.colors?.primary, + }, + }, + }, + }, + }, + '&, &.ss__result--grid, &.ss__result--list': { + alignItems: 'stretch', + gap: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + '&, .ss__result__details': { + flexFlow: 'column nowrap', + }, + '& > *': { + minWidth: '1px', + }, + '.ss__result__image-wrapper': { + flex: '0 1 auto', + border: `1px solid ${custom.colors.gray02}`, + a: { + display: 'block', + }, + '.ss__image': { + position: 'relative', + height: 0, + padding: '0 0 100% 0', + overflow: 'hidden', + '&, img': { + display: 'block', + }, + img: { + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + width: '100%', + height: '100%', + objectPosition: 'center center', + }, + }, + }, + '.ss__result__details': { + display: 'flex', + flex: '1 1 0%', + gap: `${custom.spacing.x2}px`, + padding: 0, + margin: 0, + '& > *, .ss__result__details__title, .ss__result__details__title, .ss__result__details__pricing': { + margin: 0, + }, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__result__details__title': { + order: -2, + a: { + color: variables?.colors?.text, + }, + }, + '.ss__result__details__pricing': { + order: -1, + '.ss__result__price': { + fontSize: '16px', + '&:not(.ss__price--strike)': { + fontWeight: custom.fonts.weight01, + }, + }, + '.ss__price--strike': { + fontSize: '14px', + '&, span': { + color: lightGray, + }, + }, + }, + '.ss__result__add-to-cart-wrapper .ss__button': { + width: `100%`, + }, + '.ss__result__details__variant-selection, .ss__result__add-to-cart-wrapper': { + marginTop: 'auto', + order: 20, + }, + '.ss__result__details__variant-selection ~ .ss__result__add-to-cart-wrapper, .ss__result__add-to-cart-wrapper ~ .ss__result__details__variant-selection': + { + marginTop: 0, + }, + }, + }, + '&.ss__result--list': { + '.ss__result__details': { + textAlign: 'center', + '.ss__result__details__title a': { + fontSize: '18px', + fontWeight: custom.fonts.weight02, + }, + }, + }, + [`${custom.utils.getBp(mobileBp - 100)}`]: { + '&.ss__result--list': { + '&, .ss__result__details': { + flexFlow: 'row wrap', + }, + '.ss__result__image-wrapper': { + flex: '0 0 33.33%', + 'a, .ss__overlay-badge, .ss__image': { + height: '100%', + }, + '.ss__image': { + paddingBottom: 0, + img: { + position: 'static', + }, + }, + }, + '.ss__result__details': { + alignContent: 'center', + flex: '1 1 0%', + textAlign: 'left', + '& > *': { + flex: '1 1 100%', + }, + '.ss__result__details__title': { + flex: '1 1 0%', + }, + '.ss__result__details__pricing': { + flex: '0 1 auto', + }, + '.ss__callout-badge, .ss__result__details__rating-wrapper': { + justifyContent: 'flex-start', + }, + '.ss__result__details__variant-selection': { + display: 'flex', + flexFlow: 'row wrap', + alignItems: 'center', + gap: `${custom.spacing.x2}px`, + '.ss__variant-selection': { + width: `calc((100% - ${custom.spacing.x2}px) / 2)`, + margin: 0, + '.ss__slideshow .ss__slideshow__container .ss__slideshow__track': { + justifyContent: 'flex-start', + }, + }, + }, + }, + }, + }, + }); + + return resultStyles; +}; + +// Result component props +export const result: ThemeComponent<'result', ResultProps> = { + default: { + result: { + themeStyleScript: resultStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/searchInput.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/searchInput.ts new file mode 100644 index 000000000..25dca3e58 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/searchInput.ts @@ -0,0 +1,109 @@ +import { css } from '@emotion/react'; +import type { SearchInputProps } from '../../../../components/Molecules/SearchInput'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const searchInputHeight = custom.sizes.height; +const lightGray = custom.utils.lightenColor(); + +// CSS in JS style script for the SearchInput component +const searchInputStyleScript = (props: SearchInputProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const darkPrimary = custom.utils.darkenColor(variables?.colors?.primary, 0.15); + + // search input styles + const searchInputStyles = css({ + ...custom.styles.boxSizing('searchInput', props?.treePath, props?.name), + '&.ss__search-input': { + margin: `0 0 ${custom.spacing.x4}px`, + height: `${searchInputHeight}px`, + border: 0, + '& > *': { + minWidth: '1px', + '&:first-of-type, &:last-of-type': { + ...custom.styles.borderRadius(), + }, + '&:first-of-type': { + borderTopRightRadius: custom.sizes.radius ? 0 : '', + borderBottomRightRadius: custom.sizes.radius ? 0 : '', + }, + '&:last-of-type': { + borderTopLeftRadius: custom.sizes.radius ? 0 : '', + borderBottomLeftRadius: custom.sizes.radius ? 0 : '', + overflow: custom.sizes.radius ? `hidden` : ``, + }, + }, + '.ss__search-input__input, .ss__search-input__icons, .ss__button': { + height: '100%', + lineHeight: 1, + }, + '.ss__search-input__icons, .ss__search-input__button--close-search-button': { + flex: '0 1 auto', + }, + '.ss__button, .ss__search-input__button--close-search-button': { + width: `${searchInputHeight}px`, + justifyContent: 'center', + '&, &:hover': { + border: 0, + }, + '&, .ss__icon': { + padding: 0, + }, + }, + '.ss__search-input__input': { + flex: '1 1 0%', + minHeight: '1px', + ...custom.styles.box(variables?.colors?.text, `0 ${custom.spacing.x2}px`, false), + fontSize: '14px', + '&::-webkit-input-placeholder': { + color: lightGray, + }, + '&::-ms-input-placeholder': { + color: lightGray, + }, + '&::placeholder': { + color: lightGray, + }, + }, + '.ss__search-input__icons': { + gap: '1px', + margin: '0 0 0 -1px', + backgroundColor: darkPrimary, + }, + '.ss__button': { + borderRadius: custom.sizes.radius ? 0 : '', + }, + '.ss__search-input__button--close-search-button': { + margin: '0 -1px 0 0', + }, + }, + }); + + return searchInputStyles; +}; + +// SearchInput component props +export const searchInput: ThemeComponent<'searchInput', SearchInputProps> = { + default: { + searchInput: { + themeStyleScript: searchInputStyleScript, + }, + 'searchInput icon': { + size: `${custom.sizes.icon14}px`, + }, + 'searchInput button icon': { + color: custom.colors.white, + }, + 'searchInput button.close-search icon': { + icon: custom.icons.arrowLeft, + }, + 'searchInput button.clear-search icon': { + icon: custom.icons.close, + }, + 'searchInput button.submit-search icon': { + icon: custom.icons.search, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/select.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/select.ts new file mode 100644 index 000000000..089a3c6b6 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/select.ts @@ -0,0 +1,141 @@ +import { css } from '@emotion/react'; +import type { SelectProps } from '../../../../components/Molecules/Select'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const dropdownIcon = `.ss__icon--${custom.icons.arrowDown}`; + +// CSS in JS style script for the Select component +const selectStyleScript = (props: SelectProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // default styles + const defaultStyles = css([ + { + display: 'block', + ...custom.styles.boxSizing('select', props?.treePath, props?.name), + '.ss__dropdown': { + '.ss__dropdown__button .ss__button, .ss__dropdown__content': { + ...custom.styles.box(variables?.colors?.text), + }, + '.ss__dropdown__button': { + '.ss__button': { + width: '100%', + paddingTop: 0, + paddingBottom: 0, + textAlign: 'left', + '.ss__button__content': { + '.ss__select__selection__icon': { + margin: 0, + }, + '.ss__select__selection': { + flex: '1 1 0%', + paddingRight: `${custom.spacing.x1}px`, + fontWeight: 'normal', + }, + [dropdownIcon]: { + transition: 'transform ease 0.5s', + }, + }, + }, + }, + '.ss__dropdown__content': { + marginTop: `${custom.spacing.x1}px`, + '.ss__select__select': { + margin: 0, + padding: 0, + border: 0, + backgroundColor: 'transparent', + '.ss__select__select__option': { + lineHeight: 1.5, + color: 'inherit', + gap: `${custom.spacing.x2}px`, + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + backgroundColor: 'transparent', + fontWeight: 'normal', + }, + 'a, span': { + cursor: 'pointer', + }, + }, + '.ss__select__select__option--selected': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }, + }, + '.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__button': { + [dropdownIcon]: { + transform: 'rotate(180deg)', + }, + }, + }, + }, + }, + ]); + + // native styles + const nativeStyles = css([ + { + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + gap: `${custom.spacing.x1}px`, + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + ...custom.styles.box(variables?.colors?.text, `0 ${custom.spacing.x2}px`), + ...custom.styles.boxSizing('select', props?.treePath, props?.name), + '.ss__select__label, .ss__select__select': { + fontSize: '14px', + }, + '.ss__select__label': { + fontWeight: custom.fonts.weight01, + }, + '.ss__select__select': { + flex: '1 1 0%', + padding: `0 ${custom.spacing.x1}px 0 0`, + backgroundColor: 'transparent', + height: '100%', + lineHeight: '100%', + border: 'none', + appearance: 'none', + color: 'inherit', + cursor: 'pointer', + '&::-ms-expand': { + display: 'none', + }, + '&[disabled]': { + ...custom.styles.disabled(), + }, + }, + }, + ]); + + return props?.native ? nativeStyles : defaultStyles; +}; + +// Select component props +export const select: ThemeComponent<'select', SelectProps> = { + default: { + select: { + themeStyleScript: selectStyleScript, + iconOpen: custom.icons.arrowDown, + iconClose: custom.icons.arrowDown, + }, + 'select icon.open': { + size: `${custom.sizes.icon12}px`, + }, + 'select dropdown button icon': { + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/slideout.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/slideout.ts new file mode 100644 index 000000000..2f7faa9b3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/slideout.ts @@ -0,0 +1,26 @@ +import { css } from '@emotion/react'; +import type { SlideoutProps } from '../../../../components/Molecules/Slideout'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Slideout component +const slideoutStyleScript = (props: SlideoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // slideout styles + const slideoutStyles = css({ + ...custom.styles.boxSizing('slideout', props?.treePath, props?.name), + }); + + return slideoutStyles; +}; + +// Slideout component props +export const slideout: ThemeComponent<'slideout', SlideoutProps> = { + default: { + slideout: { + themeStyleScript: slideoutStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/slideshow.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/slideshow.ts new file mode 100644 index 000000000..da0dc1bed --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/slideshow.ts @@ -0,0 +1,112 @@ +import { css } from '@emotion/react'; +import type { SlideshowProps } from '../../../../components/Molecules/Slideshow'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const slideshowSpacing = custom.spacing.x2; +const slideshowButtonSize = 32; +const slideshowPaginationSize = 12; +const slideshowPaginationSpacing = slideshowSpacing + slideshowPaginationSize; +const activeColors = custom.utils.activeColors(); +const buttonColor = activeColors[0]; +const fontColor = activeColors[1]; + +// CSS in JS style script for the Slideshow component +const slideshowStyleScript = (props: SlideshowProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // slideshow styles + const slideshowStyles = css({ + position: 'relative', + width: '100%', + minWidth: '1px', + ...custom.styles.boxSizing('slideshow', props?.treePath, props?.name), + '&:has(.ss__slideshow__pagination)': { + paddingBottom: `${slideshowPaginationSpacing}px`, + '.ss__slideshow__navigation--prev, .ss__slideshow__navigation--next': { + top: `-${slideshowPaginationSpacing}px`, + }, + }, + '.ss__slideshow__container': { + width: 'auto', + margin: `0 -${slideshowSpacing / 2}px`, + }, + '.ss__slideshow__navigation--prev, .ss__slideshow__navigation--next': { + width: `${slideshowButtonSize}px`, + height: `${slideshowButtonSize}px`, + top: 0, + bottom: 0, + margin: 'auto', + transform: 'none', + '.ss__button': { + flexFlow: 'column nowrap', + padding: 0, + width: '100%', + height: '100%', + lineHeight: 1, + color: fontColor, + [`&, &:hover, &:not(.ss__button--disabled):hover, &.ss__button--disabled`]: { + border: `1px solid ${buttonColor}`, + backgroundColor: buttonColor, + }, + }, + }, + '.ss__slideshow__navigation--prev': { + '.ss__button .ss__icon': { + left: '-1.5px', + }, + }, + '.ss__slideshow__navigation--next': { + '.ss__button .ss__icon': { + right: '-1.5px', + }, + }, + '.ss__slideshow__pagination': { + position: 'absolute', + bottom: 0, + left: 0, + right: 0, + margin: 'auto', + width: 'auto', + gap: `${custom.spacing.x1}px`, + '.ss__slideshow__dot': { + opacity: 1, + flex: '0 1 auto', + width: `${slideshowPaginationSize}px`, + height: `${slideshowPaginationSize}px`, + lineHeight: `${slideshowPaginationSize}px`, + minWidth: '1px', + margin: 0, + ...custom.styles.box('', 0, false), + }, + '.ss__slideshow__dot--active': { + backgroundColor: variables?.colors?.primary, + borderColor: variables?.colors?.primary, + }, + }, + }); + + return slideshowStyles; +}; + +// Slideshow component props +export const slideshow: ThemeComponent<'slideshow', SlideshowProps> = { + default: { + slideshow: { + themeStyleScript: slideshowStyleScript, + gap: slideshowSpacing, + centerInsufficientSlides: false, + }, + 'slideshow button icon': { + size: `${custom.sizes.icon12}px`, + }, + 'slideshow button.prev icon': { + icon: custom.icons.arrowLeft, + }, + 'slideshow button.next icon': { + icon: custom.icons.arrowRight, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/sortBy.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/sortBy.ts new file mode 100644 index 000000000..19de98c1c --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/sortBy.ts @@ -0,0 +1,26 @@ +import { css } from '@emotion/react'; +import type { SortByProps } from '../../../../components/Molecules/SortBy'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the SortBy component +const sortByStyleScript = (props: SortByProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // sortBy styles + const sortByStyles = css({ + ...custom.styles.boxSizing('sortBy', props?.treePath, props?.name), + }); + + return sortByStyles; +}; + +// SortBy component props +export const sortBy: ThemeComponent<'sortBy', SortByProps> = { + default: { + sortBy: { + themeStyleScript: sortByStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/swatches.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/swatches.ts new file mode 100644 index 000000000..f4dc8f661 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/swatches.ts @@ -0,0 +1,231 @@ +import { css } from '@emotion/react'; +import type { SwatchesProps } from '../../../../components/Molecules/Swatches'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +//import Color from 'color'; + +// static variables +const swatchesSpacing = custom.spacing.x1; +const swatchesSize = 28; +const swatchesSelector = 'ss__swatches__slideshow__swatch'; +const darkSelector = `&.${swatchesSelector}--dark, &:has(.${swatchesSelector}__inner--grey), &:has(.${swatchesSelector}__inner--gray)`; +const imageSelector = '&:has(.ss__image)'; +const urlSelector = '&[style*="url"]'; +const styleSelector = '&[style], &:has(.ss__image)'; +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const fontColor = activeColors[1]; + +// CSS in JS style script for the Swatches component +const swatchesStyleScript = (props: SwatchesProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // shared styles + const sharedStyles = css({ + ...custom.styles.boxSizing('swatches', props?.treePath, props?.name), + }); + + // swatches carousel styles + const swatchesCarouselStyles = css([ + sharedStyles, + { + '.ss__slideshow': { + display: 'flex', + flexFlow: 'row wrap', + gap: `${swatchesSpacing}px`, + '& > *': { + minWidth: '1px', + flex: '1 1 100%', + }, + '.ss__slideshow__sr-only': { + order: -2, + }, + '.ss__slideshow__container': { + flex: '1 1 0%', + margin: `0 -${swatchesSpacing / 2}px`, + '.ss__slideshow__track': { + '.ss__slideshow__slide': { + '.ss__swatches__slideshow__swatch': { + position: 'relative', + height: `${swatchesSize}px`, + aspectRatio: 1, + border: 0, + '.ss__swatches__slideshow__swatch__inner': { + position: 'relative', + width: '100%', + height: '100%', + ...custom.styles.box(variables?.colors?.text, `${custom.spacing.x1}px`), + '&, .ss__swatches__slideshow__swatch__value': { + overflow: 'hidden', + }, + '.ss__swatches__slideshow__swatch__value': { + maxWidth: '100%', + maxHeight: '100%', + textAlign: 'center', + fontSize: '10px', + lineHeight: 1, + }, + [styleSelector]: { + border: 0, + backgroundColor: 'transparent', + '&:before, &:after': { + content: '""', + display: 'block', + position: 'absolute', + top: 0, + bottom: 0, + left: 0, + right: 0, + ...custom.styles.borderRadius(), + }, + '&:before': { + border: `3px solid ${custom.colors.white}`, + margin: '1px', + opacity: 0, + }, + '&:after': { + border: `1px solid ${custom.colors.black}`, + opacity: 0.15, + }, + '.ss__swatches__slideshow__swatch__value': { + ...custom.styles.srOnly(), + }, + }, + [`${urlSelector}, ${imageSelector}`]: { + '&:before': { + margin: 0, + borderWidth: '4px', + }, + }, + [urlSelector]: { + backgroundRepeat: 'no-repeat !important', + backgroundSize: 'cover !important', + backgroundPosition: 'center !important', + }, + [imageSelector]: { + '&:before, &:after': { + zIndex: 3, + }, + '.ss__image, .ss__swatches__slideshow__swatch__value': { + position: 'absolute', + }, + '.ss__image': { + top: 0, + bottom: 0, + left: 0, + right: 0, + zIndex: 1, + img: { + width: '100%', + height: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + }, + '.ss__swatches__slideshow__swatch__value': { + zIndex: 2, + }, + }, + }, + [darkSelector]: { + '.ss__swatches__slideshow__swatch__inner': { + color: fontColor, + }, + }, + '&.ss__swatches__slideshow__swatch--disabled, &.ss__swatches__slideshow__swatch--unavailable': { + opacity: 1, + '&, &:before, &:after, *': { + pointerEvents: 'unset', + cursor: 'not-allowed !important', + }, + '&:before': { + maxWidth: `${swatchesSize - 4}px`, + top: 0, + bottom: 0, + zIndex: 3, + margin: 'auto 0', + borderTop: `2px solid ${custom.colors.white}`, + outlineColor: custom.colors.gray02, + ...custom.styles.borderRadius(3), + }, + '.ss__swatches__slideshow__swatch__inner': { + opacity: 0.65, + }, + }, + '&.ss__swatches__slideshow__swatch--selected': { + '.ss__swatches__slideshow__swatch__inner': { + borderColor: activeColor, + backgroundColor: activeColor, + color: fontColor, + [styleSelector]: { + border: 0, + backgroundColor: 'transparent', + color: variables?.colors?.text, + '&:before': { + opacity: 1, + }, + '&:after': { + opacity: 0.3, + }, + }, + '.ss__swatches__slideshow__swatch__value': { + fontWeight: custom.fonts.weight01, + }, + }, + [darkSelector]: { + '.ss__swatches__slideshow__swatch__inner': { + color: fontColor, + }, + }, + }, + }, + }, + }, + }, + '.ss__slideshow__navigation--prev, .ss__slideshow__navigation--next': { + flex: '0 1 auto', + width: `${swatchesSize}px`, + height: `${swatchesSize}px`, + margin: 0, + position: 'static', + }, + '.ss__slideshow__navigation--prev': { + order: -1, + }, + }, + }, + ]); + + // swatches grid styles + const swatchesGridStyles = css([ + sharedStyles, + { + '.ss__grid': { + '.ss__grid__options': { + '.ss__grid__option:not(.ss__grid__show-more-wrapper)': { + width: `${swatchesSize}px`, + maxHeight: `${swatchesSize}px`, + }, + }, + }, + }, + ]); + + return props?.type == 'grid' ? swatchesGridStyles : swatchesCarouselStyles; +}; + +// Swatches component props +export const swatches: ThemeComponent<'swatches', SwatchesProps> = { + default: { + swatches: { + themeStyleScript: swatchesStyleScript, + hideLabels: false, + }, + 'swatches slideshow': { + slidesToShow: 4, + gap: swatchesSpacing, + centerInsufficientSlides: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/terms.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/terms.ts new file mode 100644 index 000000000..9f48a6cd5 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/terms.ts @@ -0,0 +1,74 @@ +import { css } from '@emotion/react'; +import type { TermsProps } from '../../../../components/Molecules/Terms'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Terms component +const termsStyleScript = (props: TermsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // terms styles + const termsStyles = css({ + ...custom.styles.boxSizing('terms', props?.treePath, props?.name), + '.ss__terms__title': { + '&, h5': { + padding: 0, + }, + h5: { + margin: `0 0 ${custom.spacing.x4}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + }, + }, + '.ss__terms__options': { + flexFlow: 'row wrap', + justifyContent: 'flex-start', + gap: `${custom.spacing.x1}px ${custom.spacing.x4}px`, + '&, .ss__terms__option': { + listStyle: 'none', + padding: 0, + margin: 0, + }, + '.ss__terms__option': { + flex: '0 1 auto', + minWidth: '1px', + '&, a': { + color: variables?.colors?.primary, + }, + a: { + padding: 0, + fontSize: '14px', + em: { + color: variables?.colors?.text, + fontStyle: 'normal', + fontSize: 'inherit', + fontWeight: 'inherit', + }, + }, + }, + '.ss__terms__option--active': { + 'a, a em': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__terms__title h5, .ss__terms__options .ss__terms__option a': { + fontSize: '14px', + }, + }, + }); + + return termsStyles; +}; + +// Terms component props +export const terms: ThemeComponent<'terms', TermsProps> = { + default: { + terms: { + themeStyleScript: termsStyleScript, + emIfy: true, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/molecules/variantSelection.ts b/packages/snap-preact/components/src/themes/pike/components/molecules/variantSelection.ts new file mode 100644 index 000000000..98b479e52 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/molecules/variantSelection.ts @@ -0,0 +1,146 @@ +import { css } from '@emotion/react'; +import type { VariantSelectionProps } from '../../../../components/Molecules/VariantSelection'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Swatches component +const variantSelectionStyleScript = (props: VariantSelectionProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // shared styles + const sharedStyles = css({ + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + ...custom.styles.boxSizing('variantSelection', props?.treePath, props?.name), + }); + + // variant selection dropdown styles + const variantSelectionDropdownStyles = css([ + sharedStyles, + { + '.ss__dropdown': { + '.ss__dropdown__button, .ss__dropdown__content': { + ...custom.styles.box(variables?.colors?.text), + }, + '.ss__dropdown__button': { + gap: `${custom.spacing.x1}px`, + paddingTop: 0, + paddingBottom: 0, + textAlign: 'left', + height: `${custom.sizes.height}px`, + lineHeight: `${custom.sizes.height}px`, + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__dropdown__button-wrapper': { + flex: '1 1 0%', + overflow: 'hidden', + '.ss__dropdown__button-wrapper__label': { + fontWeight: custom?.fonts?.weight01, + textTransform: 'capitalize', + }, + '.ss__dropdown__button-wrapper__selection': { + ...custom.styles.textOverflow(), + }, + }, + '.ss__variant-selection__icon': { + transition: 'transform ease 0.5s', + }, + }, + '.ss__dropdown__content': { + marginTop: `${custom.spacing.x1}px`, + '.ss__variant-selection__options': { + border: 0, + background: 'none', + textAlign: 'left', + '&, .ss__variant-selection__option': { + listStyle: 'none', + padding: 0, + margin: 0, + }, + '.ss__variant-selection__option': { + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: '0', + }, + '&:hover': { + fontWeight: 'normal', + }, + }, + '.ss__variant-selection__option--selected': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + '.ss__variant-selection__option--unavailable, .ss__variant-selection__option--disabled': { + color: 'inherit', + ...custom.styles.disabled(), + }, + }, + }, + }, + '.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__variant-selection__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + }, + ]); + + // variant selection list styles + const variantSelectionListStyles = css([ + sharedStyles, + { + '.ss__list': { + '.ss__list__title': { + fontSize: '14px', + textAlign: 'left', + }, + '.ss__list__options': { + '.ss__list__option': { + color: variables?.colors?.text, + label: { + color: 'inherit', + cursor: 'inherit', + }, + }, + '.ss__list__option--selected': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + '.ss__list__option--unavailable, .ss__list__option--disabled': { + ...custom.styles.disabled(), + textDecoration: 'line-through', + }, + }, + }, + }, + ]); + + // variant selection swatches syles + const variantSelectionSwatchesStyles = css([sharedStyles]); + + if (props?.type == 'list') { + return variantSelectionListStyles; + } else if (props?.type == 'swatches') { + return variantSelectionSwatchesStyles; + } else { + return variantSelectionDropdownStyles; + } +}; + +// VariantSelection component props +export const variantSelection: ThemeComponent<'variantSelection', VariantSelectionProps> = { + default: { + variantSelection: { + themeStyleScript: variantSelectionStyleScript, + }, + 'variantSelection dropdown icon': { + icon: custom.icons.arrowDown, + size: `${custom.sizes.icon12}px`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/autocomplete.ts new file mode 100644 index 000000000..9a10f4748 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/autocomplete.ts @@ -0,0 +1,407 @@ +import { css } from '@emotion/react'; +import type { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; + +// static variables +const headerSelectors = + '.ss__autocomplete__terms .ss__autocomplete__title h5, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__header, .ss__autocomplete__content__results .ss__autocomplete__title h5, .ss__autocomplete__content__info a, .ss__no-results__recommendations h3'; +const activeSelectors = + '.ss__autocomplete__terms .ss__autocomplete__terms__options .ss__autocomplete__terms__option--active a, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__options .ss__facet-list-options .ss__facet-list-options__option--filtered, .ss__autocomplete__content__results .ss__results .ss__result:hover .ss__result__details .ss__result__details__title a, .ss__autocomplete__content__info a:hover'; + +// CSS in JS style script for the Autocomplete component +const autocompleteStyleScript = (props: AutocompleteProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const desktopBp = variables?.breakpoints?.desktop || custom.breakpoints.desktop; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // autcomplete styles + const autocompleteStyles = css({ + '&.ss__autocomplete': { + flexWrap: 'wrap', + top: '48px', + left: 0, + right: 0, + border: `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.white, + overflow: 'hidden', + gap: `${custom.spacing.x4}px`, + padding: `${custom.spacing.x4}px`, + ...custom.styles.boxSizing('autocomplete', props?.treePath, props?.name), + '&.ss__autocomplete--only-terms': { + width: '100%', + }, + 'a, div, p, .ss__button': { + fontSize: '12px', + }, + 'a, div:not(.ss__button, .ss__rating__icons, .ss__rating__icons .ss__rating__stars .ss__rating__stars__star), p': { + lineHeight: 1.5, + color: variables?.colors?.text, + }, + a: { + display: 'block', + }, + 'ul, ul li': { + padding: 0, + margin: 0, + listStyle: 'none', + }, + '.ss__banner': { + img: { + maxWidth: '100%', + maxHeight: '150px', + height: 'auto', + }, + }, + [headerSelectors]: { + margin: `0 0 ${custom.spacing.x4}px 0`, + padding: 0, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + lineHeight: 1.2, + }, + [activeSelectors]: { + ...custom.styles.activeText(variables?.colors?.primary), + }, + '& > div': { + minWidth: '1px', + maxWidth: 'none', + flex: '1 1 100%', + margin: `0 -${custom.spacing.x4}px`, + padding: `0 ${custom.spacing.x4}px`, + paddingBottom: `${custom.spacing.x4}px`, + borderBottom: `1px solid ${custom.colors.gray02}`, + '&:last-of-type': { + paddingBottom: 0, + borderBottomWidth: 0, + }, + }, + '.ss__autocomplete__terms': { + gap: `${custom.spacing.x4}px`, + flexFlow: 'row nowrap', + backgroundColor: 'transparent', + '& > div': { + minWidth: '1px', + flex: '1 1 0%', + '.ss__autocomplete__title': { + padding: 0, + }, + '.ss__autocomplete__terms__options': { + display: 'flex', + gap: `${custom.spacing.x1}px ${custom.spacing.x4}px`, + justifyContent: 'flex-start', + '.ss__autocomplete__terms__option': { + minWidth: '1px', + flex: '0 1 auto', + }, + '.ss__autocomplete__terms__option, .ss__autocomplete__terms__option--active': { + a: { + padding: 0, + }, + }, + '.ss__autocomplete__terms__option a': { + fontSize: '14px', + em: { + color: variables?.colors?.text, + fontStyle: 'normal', + fontSize: 'inherit', + fontWeight: 'inherit', + }, + }, + '.ss__autocomplete__terms__option--active a': { + backgroundColor: 'transparent', + '&, & em': { + ...custom.styles.activeText(variables?.colors?.primary), + }, + }, + }, + }, + }, + '.ss__autocomplete__facets': { + '.ss__facets': { + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + '.ss__facet': { + flex: '1 1 0%', + margin: 0, + '.ss__facet__header': { + borderBottom: 0, + '.ss__facet__header__inner': { + fontSize: 'inherit', + fontWeight: 'inherit', + lineHeight: 'inherit', + color: 'inherit', + }, + }, + '.ss__facet__options': { + '.ss__facet-hierarchy-options .ss__facet-hierarchy-options__option, .ss__facet-list-options .ss__facet-list-options__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__facet__facet-grid-options .ss__facet-grid-options__option': { + display: 'flex', + }, + }, + }, + }, + '.ss__banner': { + display: 'none', + margin: `${custom.spacing.x4}px 0 0 0`, + }, + }, + '.ss__autocomplete__content': { + display: 'block', + overflow: 'visible', + '.ss__banner': { + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + }, + '.ss__autocomplete__content__results': { + '&:after': { + content: '""', + display: 'block', + height: `${custom.spacing.x4}px`, + margin: `0 -${custom.spacing.x4}px`, + position: 'relative', + zIndex: 2, + }, + '.ss__results': { + overflowY: 'auto', + overflowX: 'hidden', + maxHeight: '54vh', + ...custom.styles.scrollbar(), + }, + '.ss__results .ss__result.ss__result--grid': { + ...custom.styles.resultCompact('grid', '', 12), + }, + '.ss__results .ss__result.ss__result--list': { + ...custom.styles.resultCompact('', '0 0 80px', 12), + }, + }, + '.ss__autocomplete__content__info': { + textAlign: 'left', + borderTop: `1px solid ${custom.colors.gray02}`, + margin: `0 -${custom.spacing.x4}px`, + padding: `${custom.spacing.x4}px ${custom.spacing.x4}px 0 ${custom.spacing.x4}px`, + a: { + position: 'relative', + display: 'inline-block', + padding: `0 ${custom.spacing.x1 + custom.sizes.icon12}px 0 0`, + '&, .ss__icon': { + margin: 0, + }, + '.ss__icon': { + position: 'absolute', + top: 0, + bottom: 0, + right: 0, + margin: 'auto 0', + }, + }, + }, + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + fontSize: '14px', + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + }, + }, + [`${custom.utils.getBp(custom.breakpoints.small, 'max')}`]: { + '&.ss__autocomplete': { + '.ss__autocomplete__content__results .ss__results': { + gridTemplateColumns: `repeat(2, 1fr)`, + '& > *:nth-of-type(n + 3)': { + display: 'none', + }, + }, + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '&.ss__autocomplete': { + '.ss__autocomplete__content .ss__autocomplete__content__info': { + textAlign: 'right', + }, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '&.ss__autocomplete': { + right: 0, + left: 'auto', + '& > div:not(.ss__autocomplete__terms), & > div:not(.ss__autocomplete__terms):last-child': { + paddingBottom: 0, + borderBottomWidth: 0, + }, + '.ss__autocomplete__facets': { + flex: '0 0 200px', + '.ss__facets': { + flexWrap: 'wrap', + '.ss__facet': { + flex: '1 1 100%', + }, + }, + '.ss__banner': { + display: 'block', + }, + }, + '.ss__autocomplete__content': { + flex: '1 1 0%', + '.ss__autocomplete__content__info': { + borderTop: 0, + padding: 0, + margin: 0, + }, + }, + }, + }, + [`${custom.utils.getBp(desktopBp)}`]: { + '&.ss__autocomplete': { + [headerSelectors]: { + fontSize: '16px', + }, + '.ss__autocomplete__terms, .ss__autocomplete__facets': { + flex: '0 0 220px', + }, + '.ss__autocomplete__terms': { + flexWrap: 'wrap', + alignContent: 'flex-start', + paddingBottom: 0, + borderBottomWidth: 0, + '& > div': { + flex: '1 1 100%', + '.ss__autocomplete__terms__options': { + display: 'block', + '.ss__autocomplete__terms__option': { + a: { + padding: `${custom.spacing.x2}px 0`, + transition: `padding-left 0.5s ease`, + fontSize: '16px', + }, + }, + '.ss__autocomplete__terms__option--active': { + a: { + paddingLeft: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + }, + }, + }, + }, + }, + '.ss__autocomplete__content__results .ss__results': { + maxHeight: '60vh', + }, + }, + }, + }); + + return autocompleteStyles; +}; + +// Autocomplete component props +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + ...(autocompleteThemeComponentProps.default?.['autocomplete'] || {}), + themeStyleScript: autocompleteStyleScript, + width: '940px', + contentTitle: 'Product Suggestions', + termsTitle: 'Search Suggestions', + seeMoreButtonIcon: custom.icons.arrowRight, + }, + 'autocomplete facets': { + limit: 3, + }, + 'autocomplete facet': { + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocomplete facetPaletteOptions': { + gridSize: '48px', + hideLabel: false, + }, + 'autocomplete facetGridOptions': { + gridSize: '48px', + }, + 'autocomplete results': { + rows: 2, + columns: 3, + gapSize: `${custom.spacing.x4}px`, + }, + 'autocomplete icon': { + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...autocompleteThemeComponentProps.mobile, + autocomplete: { + ...(autocompleteThemeComponentProps.mobile?.['autocomplete'] || {}), + width: 'auto', + }, + 'autocomplete results': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteThemeComponentProps.tablet, + autocomplete: { + ...(autocompleteThemeComponentProps.tablet?.['autocomplete'] || {}), + width: '600px', + }, + 'autocomplete facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocomplete results': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteThemeComponentProps.desktop, + autocomplete: { + ...(autocompleteThemeComponentProps.desktop?.['autocomplete'] || {}), + width: '700px', + }, + 'autocomplete results': { + rows: 2, + columns: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/facet.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/facet.ts new file mode 100644 index 000000000..3ba33c6d3 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/facet.ts @@ -0,0 +1,163 @@ +import { css } from '@emotion/react'; +import type { FacetProps } from '../../../../components/Organisms/Facet'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const lightGray = custom.utils.lightenColor(); + +// CSS in JS style script for the Facet component +const facetStyleScript = (props: FacetProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // facet styles + const facetStyles = css({ + ...custom.styles.boxSizing('facet', props?.treePath, props?.name), + '&.ss__facet--collapsed': { + '.ss__facet__header': { + '.ss__icon': { + transform: 'rotate(0deg)', + }, + }, + }, + '&.ss__facet--showing-all:has(.ss__facet__show-more-less)': { + '.ss__facet__options': { + maxHeight: `490px`, + overflowY: 'auto', + overflowX: 'hidden', + paddingRight: `${custom.spacing.x2}px`, + }, + }, + '.ss__facet__header': { + margin: ` 0 0 ${custom.spacing.x4}px 0`, + padding: ` 0 0 ${custom.spacing.x2}px 0`, + borderBottom: `2px solid ${variables?.colors?.primary}`, + gap: `${custom.spacing.x2}px`, + ...custom.styles.headerText(props?.color || variables?.colors?.secondary, '16px'), + '.ss__facet__header__inner': { + flex: '1 1 0%', + gap: `${custom.spacing.x1}px`, + alignItems: 'center', + maxWidth: '100%', + 'span:not(.ss__facet__header__selected-count)': { + ...custom.styles.textOverflow(), + }, + '.ss__facet__header__selected-count, .ss__facet__header__clear-all': { + fontSize: '12px', + margin: 0, + }, + '.ss__facet__header__clear-all': { + padding: 0, + height: 'auto', + lineHeight: 'inherit', + marginLeft: 'auto', + '&, &:hover': { + border: 0, + backgroundColor: 'transparent', + color: 'inherit', + }, + '&:hover': { + textDecoration: 'none', + }, + }, + }, + '.ss__icon': { + transition: 'transform ease 0.5s', + transform: 'rotate(180deg)', + }, + }, + '.ss__facet__options': { + marginTop: 0, + maxHeight: 'none', + overflow: 'visible', + ...custom.styles.scrollbar(), + }, + '.ss__search-input': { + margin: `0 0 ${custom.spacing.x4}px`, + }, + '.ss__facet__range-inputs': { + margin: `${custom.spacing.x4}px 0 0 0`, + fontSize: '14px', + color: variables?.colors?.text, + '&, .ss__facet__range-inputs__row': { + gap: `${custom.spacing.x2}px`, + }, + '.ss__facet__range-inputs__row': { + ' > *': { + minWidth: '1px', + flex: '1 1 0%', + }, + '.ss__facet__range-inputs__separator': { + flex: '0 1 auto', + }, + }, + '.ss__facet__range-inputs__separator, .ss__facet__range-inputs__row--button-wrapper .ss__button': { + margin: 0, + }, + '.ss__facet__range-input': { + gap: `${custom.spacing.x1 / 2}px`, + border: 0, + backgroundColor: 'transparent', + }, + '.ss__facet__range-input__prefix': { + padding: 0, + }, + '.ss__facet__range-input__input': { + height: custom.sizes.height, + lineHeight: custom.sizes.height, + ...custom.styles.box(variables?.colors?.text, `0 ${custom.spacing.x2}px`, false), + '&::-webkit-input-placeholder': { + color: lightGray, + }, + '&::-ms-input-placeholder': { + color: lightGray, + }, + '&::placeholder': { + color: lightGray, + }, + }, + '.ss__facet__range-inputs__row--button-wrapper .ss__button': { + width: '100%', + }, + }, + '.ss__facet__show-more-less': { + margin: `${custom.spacing.x2}px 0 0 0`, + flexFlow: 'row nowrap', + display: 'inline-flex', + alignItems: 'center', + gap: `${custom.spacing.x2}px`, + ...custom.styles.activeText(variables?.colors?.primary), + lineHeight: 1, + '.ss__icon': { + margin: 0, + width: `${custom.sizes.icon10}px`, + height: `${custom.sizes.icon10}px`, + flex: `0 0 ${custom.sizes.icon10}px`, + }, + }, + }); + + return facetStyles; +}; + +// Facet component props +export const facet: ThemeComponent<'facet', FacetProps> = { + default: { + facet: { + themeStyleScript: facetStyleScript, + iconCollapse: custom.icons.arrowDown, + iconExpand: custom.icons.arrowDown, + iconOverflowMore: custom.icons.plus, + iconOverflowLess: custom.icons.minus, + }, + 'facet icon.collapse': { + size: `${custom.sizes.icon12}px`, + color: custom.colors.primary, + }, + 'facet icon.expand': { + size: `${custom.sizes.icon12}px`, + color: custom.colors.primary, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/facets.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/facets.ts new file mode 100644 index 000000000..62715d010 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/facets.ts @@ -0,0 +1,36 @@ +import { css } from '@emotion/react'; +import type { FacetsProps } from '../../../../components/Organisms/Facets'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Facets component +const facetsStyleScript = (props: FacetsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // facets styles + const facetsStyles = css({ + ...custom.styles.boxSizing('facets', props?.treePath, props?.name), + '&.ss__facets': { + display: 'block', + width: 'auto', + '.ss__facet': { + margin: `0 0 ${custom.spacing.x6}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + }); + + return facetsStyles; +}; + +// Facets component props +export const facets: ThemeComponent<'facets', FacetsProps> = { + default: { + facets: { + themeStyleScript: facetsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/facetsHorizontal.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/facetsHorizontal.ts new file mode 100644 index 000000000..d911a9ac2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/facetsHorizontal.ts @@ -0,0 +1,215 @@ +import { css } from '@emotion/react'; +import type { FacetsHorizontalProps } from '../../../../components/Organisms/FacetsHorizontal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const dropdownButtonHeight = custom.sizes.height; + +// CSS in JS style script for the Facets component +const facetsHorizontalStyleScript = (props: FacetsHorizontalProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // facets horizontal styles + const facetsHorizontalStyles = css({ + margin: 0, + ...custom.styles.boxSizing('facetsHorizontal', props?.treePath, props?.name), + '.ss__facets-horizontal__header': { + gap: `${custom.spacing.x2}px`, + position: 'relative', + '& > *': { + minWidth: '1px', + flex: '0 1 auto', + width: `calc((100% - ${custom.spacing.x2 * 2}px) / 3)`, + }, + '& > *, .ss__facets-horizontal__header__dropdown, .ss__mobile-sidebar': { + margin: 0, + }, + '.ss__facets-horizontal__header__dropdown': { + position: 'static', + '&.ss__dropdown--open': { + '.ss__dropdown__button': { + '.ss__dropdown__button__heading': { + '.ss__icon': { + transform: 'rotate(180deg)', + }, + }, + }, + '.ss__dropdown__content': { + width: 'auto', + minWidth: '1px', + maxHeight: 'none', + overflowY: 'visible', + padding: `${custom.spacing.x4}px`, + marginTop: `${custom.spacing.x1}px`, + right: 0, + }, + }, + '.ss__dropdown__button, .ss__dropdown__content': { + ...custom.styles.box(variables?.colors?.text, `0 ${custom.spacing.x2}px`), + }, + '.ss__dropdown__button': { + height: `${dropdownButtonHeight}px`, + lineHeight: `${dropdownButtonHeight}px`, + '&, .ss__dropdown__button__heading': { + width: '100%', + }, + '.ss__dropdown__button__heading': { + flexFlow: 'row nowrap', + justifyContent: 'flex-start', + gap: `${custom.spacing.x1}px`, + padding: 0, + '& > *': { + minWidth: '1px', + }, + '.ss__facet__header__inner': { + flex: '1 1 0%', + gap: `${custom.spacing.x1}px`, + alignItems: 'center', + maxWidth: '100%', + paddingRight: `${custom.spacing.x1}px`, + fontWeight: custom.fonts.weight01, + 'span:not(.ss__facet__header__selected-count)': { + ...custom.styles.textOverflow(), + }, + '.ss__facet__header__selected-count, .ss__facet__header__clear-all': { + fontSize: '12px', + margin: 0, + }, + '.ss__facet__header__clear-all': { + padding: 0, + height: 'auto', + lineHeight: 'inherit', + marginLeft: 'auto', + '&, &:hover': { + border: 0, + backgroundColor: 'transparent', + color: 'inherit', + }, + '&:hover': { + textDecoration: 'none', + }, + }, + }, + '.ss__icon': { + transition: 'transform ease 0.5s', + }, + }, + }, + '.ss__dropdown__content': { + '.ss__checkbox, .ss__radio, .ss__search-input .ss__search-input__input, .ss__facet__range-inputs .ss__facet__range-input__input': { + backgroundColor: custom.colors.white, + }, + '.ss__facet': { + margin: 0, + }, + '.ss__facet.ss__facet--showing-all:has(.ss__facet__show-more-less) .ss__facet__options': { + maxHeight: '360px', + }, + '.ss__facet-grid-options': { + '.ss__facet-grid-options__option:not(.ss__facet-grid-options__option--filtered)': { + backgroundColor: custom.colors.white, + }, + }, + '.ss__facet--slider .ss__facet__options, .ss__facet__range-inputs': { + maxWidth: '50%', + marginLeft: 'auto', + marginRight: 'auto', + }, + '.ss__facet__show-more-less': { + justifyContent: 'center', + }, + }, + }, + '.ss__facets-horizontal__header__dropdown .ss__dropdown__content .ss__facet__show-more-less, .ss__mobile-sidebar .ss__slideout__button .ss__button': + { + display: 'flex', + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__facets-horizontal__header': { + '& > *': { + width: `calc((100% - ${custom.spacing.x2 * 3}px) / 4)`, + }, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__facets-horizontal__header': { + '& > *': { + width: `calc((100% - ${custom.spacing.x2 * 5}px) / 6)`, + }, + }, + }, + }); + + return facetsHorizontalStyles; +}; + +// FacetsHorizontal component props +export const facetsHorizontal: ThemeComponent<'facetsHorizontal', FacetsHorizontalProps> = { + default: { + facetsHorizontal: { + themeStyleScript: facetsHorizontalStyleScript, + iconExpand: custom.icons.arrowDown, + iconCollapse: custom.icons.arrowDown, + alwaysShowFiltersButton: true, + }, + 'facetsHorizontal dropdown button icon': { + size: `${custom.sizes.icon12}px`, + }, + 'facetsHorizontal dropdown facet': { + statefulOverflow: true, + horizontal: true, + display: { + list: { + limit: 32, + }, + hierarchy: { + limit: 32, + }, + grid: { + limit: 36, + }, + palette: { + limit: 36, + }, + }, + }, + 'facetsHorizontal mobileSidebar facet': { + statefulOverflow: true, + horizontal: false, + display: { + list: { + limit: 10, + }, + hierarchy: { + limit: 10, + }, + grid: { + limit: 12, + }, + palette: { + limit: 12, + }, + }, + }, + 'facetsHorizontal facetListOptions': { + hideCheckbox: false, + }, + 'facetsHorizontal facetGridOptions': { + gridSize: '48px', + }, + 'facetsHorizontal mobileSidebar facetGridOptions': { + gridSize: '52px', + }, + 'facetsHorizontal facetPaletteOptions': { + gridSize: '48px', + }, + 'facetsHorizontal mobileSidebar facetPaletteOptions': { + gridSize: '52px', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/filterSummary.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/filterSummary.ts new file mode 100644 index 000000000..c6588db60 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/filterSummary.ts @@ -0,0 +1,115 @@ +import { css } from '@emotion/react'; +import type { FilterSummaryProps } from '../../../../components/Organisms/FilterSummary'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the FilterSummary component +const filterSummaryStyleScript = (props: FilterSummaryProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const isSidebar = props?.treePath && (props.treePath.includes('sidebar') || props.treePath.includes('mobileSidebar')) ? true : false; + + // filter summary styles + const filterSummaryStyles = isSidebar + ? { + display: 'block', + } + : { + display: 'flex', + alignItems: 'center', + gap: `${custom.spacing.x2}px`, + }; + + // header styles + const headerStyles = isSidebar + ? { + margin: `0 0 ${custom.spacing.x4}px 0`, + padding: `0 0 ${custom.spacing.x2}px 0`, + borderBottom: `2px solid ${variables?.colors?.primary}`, + ...custom.styles.headerText(variables?.colors?.secondary, '16px'), + } + : { + padding: 0, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + }; + + // shared styles + const sharedStyles = css({ + width: 'auto', + ...filterSummaryStyles, + ...custom.styles.boxSizing('filterSummary', props?.treePath, props?.name), + '.ss__filter-summary__title': { + ...headerStyles, + }, + '.ss__filter-summary__filters': { + margin: 0, + }, + }); + + // inline filter summary styles + // note: inline is a grid type summary style + const inlineFilterSummaryStyles = css([ + sharedStyles, + { + '&.ss__filter-summary--inline': { + '.ss__filter-summary__filters': { + gap: `${custom.spacing.x2}px`, + '.ss__filter': { + '.ss__filter__button': { + ...custom.styles.box('', `${custom.spacing.x1}px ${custom.spacing.x2}px`), + '.ss__button__content': { + '.ss__filter__button__icon': { + marginRight: `${custom.spacing.x1}px`, + }, + }, + }, + }, + }, + }, + }, + ]); + + // list filter summary styles + const listFilterSummaryStyles = css([ + sharedStyles, + { + '&.ss__filter-summary--list': { + '&, .ss__filter-summary__filters': { + display: isSidebar ? '' : 'flex', + }, + '.ss__filter-summary__filters': { + '.ss__filter': { + margin: isSidebar ? `0 0 ${custom.spacing.x1}px 0` : 0, + '&:last-of-type': { + marginBottom: isSidebar ? 0 : '', + }, + '.ss__filter__button': { + '.ss__button__content': { + padding: `0 0 0 ${custom.sizes.icon16 + custom.spacing.x2}px`, + '.ss__filter__button__icon': { + position: 'absolute', + top: '1.5px', + left: 0, + ...custom.styles.box('', '3px'), + width: `${custom.sizes.icon16}px`, + height: `${custom.sizes.icon16}px`, + }, + }, + }, + }, + }, + }, + }, + ]); + + return props?.type == 'list' ? listFilterSummaryStyles : inlineFilterSummaryStyles; +}; + +// FilterSummary component props +export const filterSummary: ThemeComponent<'filterSummary', FilterSummaryProps> = { + default: { + filterSummary: { + themeStyleScript: filterSummaryStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/index.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/index.ts new file mode 100644 index 000000000..2a6ce520d --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/index.ts @@ -0,0 +1,69 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// ORGANISMS Imports +import { autocomplete } from './autocomplete'; +import { facet } from './facet'; +import { facets } from './facets'; +import { facetsHorizontal } from './facetsHorizontal'; +import { filterSummary } from './filterSummary'; +import { mobileSidebar } from './mobileSidebar'; +import { noResults } from './noResults'; +import { results } from './results'; +import { sidebar } from './sidebar'; +import { termsList } from './termsList'; +import { toolbar } from './toolbar'; + +export const organisms: ThemeResponsiveComplete = { + default: { + ...autocomplete.default, + ...facet.default, + ...facets.default, + ...facetsHorizontal.default, + ...filterSummary.default, + ...mobileSidebar.default, + ...noResults.default, + ...results.default, + ...sidebar.default, + ...toolbar.default, + ...termsList.default, + }, + mobile: { + ...autocomplete.mobile, + ...facet.mobile, + ...facets.mobile, + ...facetsHorizontal.mobile, + ...filterSummary.mobile, + ...mobileSidebar.mobile, + ...noResults.mobile, + ...results.mobile, + ...sidebar.mobile, + ...toolbar.mobile, + ...termsList.mobile, + }, + tablet: { + ...autocomplete.tablet, + ...facet.tablet, + ...facets.tablet, + ...facetsHorizontal.tablet, + ...filterSummary.tablet, + ...mobileSidebar.tablet, + ...noResults.tablet, + ...results.tablet, + ...sidebar.tablet, + ...toolbar.tablet, + ...termsList.tablet, + }, + desktop: { + ...autocomplete.desktop, + ...facet.desktop, + ...facets.desktop, + ...facetsHorizontal.desktop, + ...filterSummary.desktop, + ...mobileSidebar.desktop, + ...noResults.desktop, + ...results.desktop, + ...sidebar.desktop, + ...toolbar.desktop, + ...termsList.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/mobileSidebar.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/mobileSidebar.ts new file mode 100644 index 000000000..a2b669539 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/mobileSidebar.ts @@ -0,0 +1,146 @@ +import { css } from '@emotion/react'; +import type { MobileSidebarProps } from '../../../../components/Organisms/MobileSidebar'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const headerHeight = 60; +const footerHeight = 75; +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const fontColor = activeColors[1]; + +// CSS in JS style script for the MobileSidebar component +const mobileSidebarStyleScript = (props: MobileSidebarProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const hideHeader = typeof props?.hideHeader == 'boolean' ? props.hideHeader : false; + const hideFooter = typeof props?.hideFooter == 'boolean' ? props.hideFooter : false; + + // determine inner content height + let innerHeight = 100; + if (!hideHeader && !hideFooter) { + innerHeight = headerHeight + footerHeight; + } else if (hideHeader && !hideFooter) { + innerHeight = headerHeight; + } else if (hideFooter && !hideHeader) { + innerHeight = footerHeight; + } + + // mobile sidebar styles + const mobileSidebarStyles = css({ + ...custom.styles.boxSizing('mobileSidebar', props?.treePath, props?.name), + '.ss__slideout__button .ss__button': { + '.ss__button__content': { + textAlign: 'left', + }, + }, + '.ss__mobile-sidebar__slideout': { + overflowY: 'hidden', + padding: 0, + width: '100%', + '.ss__mobile-sidebar__content': { + height: '100%', + '.ss__mobile-sidebar__header, .ss__mobile-sidebar__footer': { + padding: `0 ${custom.spacing.x4}px`, + gap: `${custom.spacing.x2}px`, + flexFlow: 'row nowrap', + alignItems: 'center', + }, + '.ss__mobile-sidebar__header': { + height: `${headerHeight}px`, + backgroundColor: activeColor, + color: fontColor, + '.ss__mobile-sidebar__header__title': { + margin: 0, + fontSize: '18px', + }, + '.ss__mobile-sidebar__header__close-button': { + padding: 0, + width: 'auto', + height: 'auto', + lineHeight: '0', + border: 0, + backgroundColor: 'transparent', + }, + }, + '.ss__mobile-sidebar__inner': { + height: innerHeight == 100 ? `${innerHeight}%` : `calc(100% - ${innerHeight}px)`, + overflowY: 'auto', + overflowX: 'hidden', + ...custom.styles.scrollbar(), + '.ss__layout': { + overflow: 'hidden', + display: 'block', + '& > *': { + borderBottom: `1px solid ${custom.colors.gray02}`, + padding: `${custom.spacing.x4}px`, + '&:last-of-type': { + borderBottomWidth: 0, + }, + }, + }, + '.ss__filter-summary, .ss__facets': { + padding: 0, + }, + '.ss__filter-summary .ss__filter-summary__title, .ss__facets .ss__facet .ss__facet__header': { + margin: 0, + padding: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + borderBottom: `1px solid ${custom.colors.gray01}`, + backgroundColor: custom.colors.gray01, + color: variables?.colors?.text, + fontSize: '14px', + }, + '.ss__filter-summary .ss__filter-summary__filters, .ss__facets .ss__facet .ss__dropdown__content': { + padding: `${custom.spacing.x4}px`, + }, + '.ss__facets .ss__facet': { + margin: 0, + '&.ss__facet--collapsed': { + borderBottom: `1px solid ${custom.colors.gray02}`, + }, + }, + '.ss__select .ss__dropdown .ss__dropdown__content': { + zIndex: 6, + }, + '.ss__select--native': { + padding: `0 ${custom.spacing.x4}px`, + borderTop: 0, + height: '40px', + lineHeight: '40px', + }, + }, + '.ss__mobile-sidebar__footer': { + height: `${footerHeight}px`, + backgroundColor: custom.colors.white, + borderTop: `1px solid ${custom.colors.gray02}`, + '.ss__button': { + flex: `1 1 0%`, + }, + }, + }, + }, + }); + + return mobileSidebarStyles; +}; + +// MobileSidebar component props +export const mobileSidebar: ThemeComponent<'mobileSidebar', MobileSidebarProps> = { + default: { + mobileSidebar: { + themeStyleScript: mobileSidebarStyleScript, + openButtonIcon: custom.icons.filter, + closeButtonIcon: custom.icons.close, + }, + 'mobileSidebar button.close icon': { + size: `${custom.sizes.icon16}px`, + }, + 'mobileSidebar facets icon.collapse': { + color: 'currentColor', + }, + 'mobileSidebar facets icon.expand': { + color: 'currentColor', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/noResults.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/noResults.ts new file mode 100644 index 000000000..f4588456c --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/noResults.ts @@ -0,0 +1,63 @@ +import { css } from '@emotion/react'; +import type { NoResultsProps } from '../../../../components/Organisms/NoResults'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the NoResults component +const noResultsStyleScript = (props: NoResultsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // no results styles + const noResultsStyles = css({ + ...custom.styles.boxSizing('noResults', props?.treePath, props?.name), + '& > *:not(.ss__no-results__recommendations)': { + 'h1, h2, h3, h4, h5, h6, ul': { + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + 'h1, h2, h3, h4, h5, h6, .ss__no-results__recommendations .ss__recommendation .ss__recommendation__title': { + ...custom.styles.headerText(variables?.colors?.secondary, '20px'), + }, + 'ul li, p': { + color: variables?.colors?.text, + }, + a: { + color: variables?.colors?.primary, + '&:hover': { + color: variables?.colors?.secondary, + }, + }, + ul: { + padding: 0, + marginLeft: `${custom.spacing.x8}px`, + listStyle: 'none', + li: { + listStyle: 'disc', + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + }, + }, + '.ss__no-results__recommendations': { + '.ss__recommendation': { + margin: `${custom.spacing.x4}px 0`, + '.ss__recommendation__title': { + fontSize: '20px', + }, + }, + }, + }); + + return noResultsStyles; +}; + +// NoResults component props +export const noResults: ThemeComponent<'noResults', NoResultsProps> = { + default: { + noResults: { + themeStyleScript: noResultsStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/results.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/results.ts new file mode 100644 index 000000000..dd3a9539e --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/results.ts @@ -0,0 +1,43 @@ +import { css } from '@emotion/react'; +import type { ResultsProps } from '../../../../components/Organisms/Results'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Results component +const resultsStyleScript = (props: ResultsProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // results styles + const resultStyles = css({ + ...custom.styles.boxSizing('results', props?.treePath, props?.name), + '& > *': { + minWidth: '1px', + }, + }); + + return resultStyles; +}; + +// Results component props +export const results: ThemeComponent<'results', ResultsProps> = { + default: { + results: { + themeStyleScript: resultsStyleScript, + gapSize: `${custom.spacing.x4}px`, + columns: 4, + }, + }, + mobile: { + results: { + gapSize: `${custom.spacing.x4}px ${custom.spacing.x2}px`, + columns: 2, + }, + }, + tablet: { + results: { + columns: 3, + }, + }, + desktop: {}, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/sidebar.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/sidebar.ts new file mode 100644 index 000000000..5613193d6 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/sidebar.ts @@ -0,0 +1,38 @@ +import { css } from '@emotion/react'; +import type { SidebarProps } from '../../../../components/Organisms/Sidebar'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Sidebar component +const sidebarStyleScript = (props: SidebarProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // sidebar styles + const sidebarStyles = css({ + ...custom.styles.boxSizing('sidebar', props?.treePath, props?.name), + '.ss__sidebar__title': { + margin: `0 0 ${custom.spacing.x6}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '20px'), + }, + '.ss__sidebar__inner': { + '.ss__layout': { + gap: `${custom.spacing.x6}px`, + }, + '.ss__select': { + width: '100%', + }, + }, + }); + + return sidebarStyles; +}; + +// Sidebar component props +export const sidebar: ThemeComponent<'sidebar', SidebarProps> = { + default: { + sidebar: { + themeStyleScript: sidebarStyleScript, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/termsList.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/termsList.ts new file mode 100644 index 000000000..68a1df5c6 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/termsList.ts @@ -0,0 +1,34 @@ +import { css } from '@emotion/react'; +import type { TermsListProps } from '../../../../components/Organisms/TermsList'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the TermsList component +const termsListStyleScript = (props: TermsListProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // terms list styles + const termsListStyles = css({ + backgroundColor: 'transparent', + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + ...custom.styles.boxSizing('termsList', props?.treePath, props?.name), + '.ss__terms-list__row': { + flex: '1 1 0%', + minWidth: '1px', + }, + }); + + return termsListStyles; +}; + +// TermsList component props +export const termsList: ThemeComponent<'termsList', TermsListProps> = { + default: { + termsList: { + themeStyleScript: termsListStyleScript, + suggestionTitle: 'Search Suggestions', + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/organisms/toolbar.ts b/packages/snap-preact/components/src/themes/pike/components/organisms/toolbar.ts new file mode 100644 index 000000000..298a21d5a --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/organisms/toolbar.ts @@ -0,0 +1,54 @@ +import { css } from '@emotion/react'; +import { ThemeComponent } from '../../../../providers'; +import { ToolbarProps } from '../../../../components/Organisms/Toolbar'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Toolbar component +const toolbarStyleScript = (props: ToolbarProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // toolbar styles + const toolbarStyles = css({ + ...custom.styles.boxSizing('toolbar', props?.treePath, props?.name), + '.ss__button--sidebar-toggle-button-wrapper .ss__button': { + '.ss__button__content': { + textAlign: 'left', + }, + }, + '.ss__layout': { + '&, .ss__layout__row': { + gap: `${custom.spacing.x2}px`, + }, + }, + '.ss__pagination-info': { + fontSize: props?.name == 'bottom' ? '16px' : '18px', + }, + '.ss__banner': { + margin: `${custom.spacing.x2}px 0`, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__pagination-info': { + fontSize: props?.name == 'bottom' ? '14px' : '16px', + }, + }, + }); + + return toolbarStyles; +}; + +// Toolbar component props +export const toolbar: ThemeComponent<'toolbar', ToolbarProps> = { + default: { + toolbar: { + themeStyleScript: toolbarStyleScript, + }, + 'toolbar filterSummary': { + title: `Current Filters:`, + }, + 'toolbar mobileSidebar filterSummary': { + title: `Current Filters`, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteFixed.ts b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteFixed.ts new file mode 100644 index 000000000..06bd424db --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteFixed.ts @@ -0,0 +1,201 @@ +import { css } from '@emotion/react'; +import { autocompleteFixedThemeComponentProps } from '../../../themeComponents/autocompleteFixed'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteFixedProps } from '../../../../components/Templates/AutocompleteFixed'; +import { autocompleteSharedStyleScript } from '../templates/autocompleteShared'; +import { custom } from '../../custom'; + +// static variables +const searchInputHeight = 40; + +// CSS in JS style script for the Search component +const autocompleteFixedStyleScript = (props: AutocompleteFixedProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // autocomplete shared styles + const sharedStyles = css({ + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '.ss__autocomplete-fixed__inner__layout-wrapper': { + '.ss__autocomplete': { + ...autocompleteSharedStyleScript(props, 'autocompleteFixed'), + }, + }, + }, + }, + }, + }); + + // autocomplete fixed styles + const fixedStyles = css({ + ...custom.styles.boxSizing('autocompleteFixed', props?.treePath, props?.name), + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '& > .ss__search-input': { + height: `${searchInputHeight}px`, + margin: 0, + '.ss__button, .ss__search-input__button--close-search-button': { + width: `${searchInputHeight}px`, + }, + }, + '.ss__autocomplete-fixed__inner__layout-wrapper': { + maxHeight: 'none', + width: 'auto', + '&, .ss__autocomplete': { + overflow: 'visible', + }, + '.ss__autocomplete': { + maxWidth: '100%', + width: props?.width, + left: 0, + right: 0, + margin: `${custom.spacing.x2}px auto auto auto`, + }, + }, + }, + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-fixed__inner': { + '.ss__autocomplete-fixed__inner__layout-wrapper': { + '.ss__autocomplete': { + maxWidth: 'none', + left: 'auto', + }, + }, + }, + }, + }, + }, + }); + + // autocomplete styles + const autocompleteFixedStyles = css([sharedStyles, fixedStyles]); + + return autocompleteFixedStyles; +}; + +export const autocompleteFixed: ThemeComponent<'autocompleteFixed', AutocompleteFixedProps> = { + default: { + ...autocompleteFixedThemeComponentProps.default, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.default?.['autocompleteFixed'] || {}), + themeStyleScript: autocompleteFixedStyleScript, + layout: 'standard', + width: '940px', + viewportMaxHeight: false, + contentTitle: 'Product Suggestions', + }, + 'autocompleteFixed facets': { + limit: 3, + }, + 'autocompleteFixed facet': { + ...(autocompleteFixedThemeComponentProps.default?.['autocompleteFixed facet'] || {}), + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocompleteFixed facetPaletteOptions': { + gridSize: '48px', + hideLabel: false, + }, + 'autocompleteFixed facetGridOptions': { + gridSize: '48px', + }, + 'autocompleteFixed results': { + rows: 2, + columns: 3, + gapSize: `${custom.spacing.x4}px`, + }, + 'autocompleteFixed recommendationGrid': { + rows: 2, + columns: 4, + gapSize: `${custom.spacing.x4}px`, + }, + 'autocompleteFixed button.see-more icon': { + size: `${custom.sizes.icon12}px`, + icon: custom.icons.arrowRight, + }, + }, + mobile: { + ...autocompleteFixedThemeComponentProps.mobile, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.mobile?.['autocompleteFixed'] || {}), + layout: 'mini', + width: 'auto', + }, + 'autocompleteFixed results': { + rows: 1, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteFixedThemeComponentProps.tablet, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.tablet?.['autocompleteFixed'] || {}), + layout: 'standard', + width: '600px', + }, + 'autocompleteFixed facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocompleteFixed results': { + rows: 1, + columns: 4, + }, + 'autocompleteFixed recommendationGrid': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteFixedThemeComponentProps.desktop, + autocompleteFixed: { + ...(autocompleteFixedThemeComponentProps.desktop?.['autocompleteFixed'] || {}), + layout: 'standard', + width: '700px', + }, + 'autocompleteFixed results': { + rows: 2, + columns: 3, + }, + 'autocompleteFixed recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteModal.ts b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteModal.ts new file mode 100644 index 000000000..febdefe40 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteModal.ts @@ -0,0 +1,192 @@ +import { css } from '@emotion/react'; +import { autocompleteModalThemeComponentProps } from '../../../themeComponents/autocompleteModal'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteModalProps } from '../../../../components/Templates/AutocompleteModal'; +import { autocompleteSharedStyleScript } from '../templates/autocompleteShared'; +import { custom } from '../../custom'; + +// static variables +const searchInputHeight = 40; + +// CSS in JS style script for the Search component +const autocompleteModalStyleScript = (props: AutocompleteModalProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const desktopBp = variables?.breakpoints?.desktop || custom.breakpoints.desktop; + + // autocomplete shared styles + const sharedStyles = css({ + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + '.ss__autocomplete': { + ...autocompleteSharedStyleScript(props, 'autocompleteModal'), + }, + }, + }, + }, + }); + + // autocomplete modal styles + const modalStyles = css({ + ...custom.styles.boxSizing('autocompleteModal', props?.treePath, props?.name), + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + top: '5vh', + display: 'flex', + flexFlow: 'column nowrap', + height: 'auto', + maxHeight: props?.height ? props?.height : '80vh', + maxWidth: '1000px', + overflow: 'visible', + '& > .ss__search-input': { + height: 'auto', + flex: `0 0 ${searchInputHeight}px`, + margin: 0, + '.ss__button, .ss__search-input__button--close-search-button': { + width: `${searchInputHeight}px`, + }, + }, + '.ss__autocomplete': { + width: '100%', + flex: '1 1 0%', + overflowY: 'auto', + overflowX: 'hidden', + ...custom.styles.scrollbar(), + }, + }, + }, + }, + [`${custom.utils.getBp(desktopBp)}`]: { + '.ss__modal': { + '.ss__modal__content': { + '.ss__autocomplete-modal__inner': { + top: '5vh', + }, + }, + }, + }, + }); + + // autocomplete styles + const autocompleteModalStyles = css([sharedStyles, modalStyles]); + + return autocompleteModalStyles; +}; + +export const autocompleteModal: ThemeComponent<'autocompleteModal', AutocompleteModalProps> = { + default: { + ...autocompleteModalThemeComponentProps.default, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.default?.['autocompleteModal'] || {}), + themeStyleScript: autocompleteModalStyleScript, + layout: 'standard', + width: '90vw', + height: '90vh', + contentTitle: 'Product Suggestions', + }, + 'autocompleteModal facets': { + limit: 3, + }, + 'autocompleteModal facet': { + ...(autocompleteModalThemeComponentProps.default?.['autocompleteModal facet'] || {}), + display: { + list: { + limit: 5, + }, + hierarchy: { + limit: 5, + }, + grid: { + limit: 6, + }, + palette: { + limit: 6, + }, + }, + }, + 'autocompleteModal facetPaletteOptions': { + gridSize: '48px', + hideLabel: false, + }, + 'autocompleteModal facetGridOptions': { + gridSize: '48px', + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + gapSize: `${custom.spacing.x4}px`, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + gapSize: `${custom.spacing.x4}px`, + }, + 'autocompleteModal button.see-more icon': { + size: `${custom.sizes.icon12}px`, + icon: custom.icons.arrowRight, + }, + }, + mobile: { + ...autocompleteModalThemeComponentProps.mobile, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.mobile?.['autocompleteModal'] || {}), + layout: 'mini', + }, + 'autocompleteModal results': { + rows: 1, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 1, + columns: 3, + }, + }, + tablet: { + ...autocompleteModalThemeComponentProps.tablet, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.tablet?.['autocompleteModal'] || {}), + layout: 'standard', + }, + 'autocompleteModal facet': { + display: { + list: { + limit: 3, + }, + hierarchy: { + limit: 3, + }, + grid: { + limit: 4, + }, + palette: { + limit: 4, + }, + }, + }, + 'autocompleteModal results': { + rows: 1, + columns: 4, + }, + 'autocompleteModal recommendationGrid': { + rows: 1, + columns: 4, + }, + }, + desktop: { + ...autocompleteModalThemeComponentProps.desktop, + autocompleteModal: { + ...(autocompleteModalThemeComponentProps.desktop?.['autocompleteModal'] || {}), + layout: 'standard', + }, + 'autocompleteModal results': { + rows: 2, + columns: 3, + }, + 'autocompleteModal recommendationGrid': { + rows: 2, + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteShared.ts b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteShared.ts new file mode 100644 index 000000000..655c077c5 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteShared.ts @@ -0,0 +1,438 @@ +import { css } from '@emotion/react'; +import type { AutocompleteLayoutProps } from '../../../../components/Organisms/AutocompleteLayout'; +import { custom } from '../../custom'; + +// static variables +const headerSelectors = + '.ss__terms-list .ss__terms .ss__terms__title h5, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__header, .ss__autocomplete__content .ss__autocomplete__content__results .ss__autocomplete__title h5, .ss__autocomplete__button--see-more .ss__button__content, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__title'; +const activeSelectors = + '.ss__terms-list .ss__terms .ss__terms__options .ss__terms__option.ss__terms__option--active a, .ss__autocomplete__facets .ss__facets .ss__facet .ss__facet__options .ss__facet-list-options .ss__facet-list-options__option--filtered, .ss__autocomplete__content .ss__autocomplete__content__results .ss__results .ss__result:hover .ss__result__details .ss__result__details__title a, .ss__autocomplete__button--see-more:hover .ss__button__content'; + +// CSS in JS style script for the Autocomplete Layout component +export const autocompleteSharedStyleScript = (props: AutocompleteLayoutProps, template: string) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const desktopBp = variables?.breakpoints?.desktop || custom.breakpoints.desktop; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // determine template being used + const isFixed = template == 'autocompleteFixed'; + const isModal = template == 'autocompleteModal'; + const isSlideout = template == 'autocompleteSlideout'; + + // get autocomplete layout + const acLayout = props?.layout ? props.layout : 'standard'; + + // shared styles + const sharedStyles = css({ + padding: isSlideout ? 0 : `${custom.spacing.x4}px`, + gap: `${custom.spacing.x4}px`, + border: isSlideout ? 0 : `1px solid ${custom.colors.gray02}`, + backgroundColor: custom.colors.white, + 'a, div, p, .ss__button': { + fontSize: '12px', + }, + 'a, div:not(.ss__button, .ss__rating__icons, .ss__rating__icons .ss__rating__stars .ss__rating__stars__star), p': { + lineHeight: 1.5, + color: variables?.colors?.text, + }, + a: { + display: 'block', + }, + 'ul, ul li': { + padding: 0, + margin: 0, + listStyle: 'none', + }, + '.ss__banner': { + img: { + maxWidth: '100%', + maxHeight: '150px', + height: 'auto', + }, + }, + [headerSelectors]: { + margin: `0 0 ${custom.spacing.x4}px 0`, + padding: 0, + ...custom.styles.headerText(variables?.colors?.secondary, '14px'), + lineHeight: 1.2, + }, + [activeSelectors]: { + ...custom.styles.activeText(variables?.colors?.primary), + }, + '.ss__terms-list .ss__terms .ss__terms__options .ss__terms__option a': { + fontSize: '14px', + }, + }); + + // shared layout styles + const sharedLayoutStyles = css({ + alignContent: 'flex-start', + '& > .ss__autocomplete__row': { + flex: '1 1 100%', + minWidth: '1px', + padding: isSlideout ? `0 0 ${custom.spacing.x4}px 0` : `0 ${custom.spacing.x4}px ${custom.spacing.x4}px ${custom.spacing.x4}px`, + margin: isSlideout ? 0 : `0 -${custom.spacing.x4}px`, + borderBottom: `1px solid ${custom.colors.gray02}`, + '&:last-of-type': { + borderBottomWidth: 0, + paddingBottom: 0, + }, + }, + }); + + // shared tablet styles + const sharedDesktopStyles = css({ + [headerSelectors]: { + fontSize: '16px', + }, + '.ss__terms-list .ss__terms .ss__terms__options .ss__terms__option a': { + fontSize: '16px', + }, + }); + + // terms wrapper styles + const termsWrapperStyles = css({ + '.ss__autocomplete__terms-wrapper': { + backgroundColor: 'transparent', + }, + }); + + // facets styles + const facetsStyles = css({ + '.ss__autocomplete__facets': { + padding: 0, + '.ss__facets': { + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4}px`, + '.ss__facet': { + flex: '1 1 0%', + margin: 0, + '.ss__facet__header': { + borderBottom: 0, + '.ss__facet__header__inner': { + fontSize: 'inherit', + fontWeight: 'inherit', + color: 'inherit', + lineHeight: 'inherit', + }, + }, + '.ss__facet__options': { + '.ss__facet-hierarchy-options .ss__facet-hierarchy-options__option, .ss__facet-list-options .ss__facet-list-options__option': { + padding: 0, + margin: `0 0 ${custom.spacing.x1}px 0`, + '&:last-of-type': { + marginBottom: 0, + }, + }, + '.ss__facet__facet-grid-options .ss__facet-grid-options__option': { + display: 'flex', + }, + }, + }, + }, + '.ss__banner': { + display: 'none', + margin: `${custom.spacing.x4}px 0 0 0`, + }, + }, + }); + + // content styles + const contentStyles = css({ + '.ss__autocomplete__content': { + overflow: 'visible', + '.ss__autocomplete__content-inner': { + padding: 0, + '& > *': { + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + }, + }, + }); + + // results layout styles + const resultsLayoutStyles = css({ + gap: `${custom.spacing.x4}px`, + overflowY: isFixed ? 'auto' : 'hidden', + overflowX: 'hidden', + maxHeight: isFixed ? '54vh' : '', + ...custom.styles.scrollbar(), + }); + + // results styles + const resultsStyles = css({ + '.ss__autocomplete__content__results': { + '.ss__results': { + ...resultsLayoutStyles, + }, + '.ss__results .ss__result.ss__result--grid': { + ...custom.styles.resultCompact('grid', '', 12), + }, + '.ss__results .ss__result.ss__result--list': { + ...custom.styles.resultCompact('', '0 0 80px', 12), + }, + }, + }); + + // mobile results styles + const resultsSmallStyles = css({ + '.ss__autocomplete__content__results .ss__results, .ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__recommendations .ss__recommendation-grid__results': + { + gridTemplateColumns: 'repeat(2, 1fr)', + [`& > *:nth-of-type(n + ${isSlideout ? 5 : 3})`]: { + display: 'none', + }, + }, + }); + + // no results styles + const noResultsStyles = css({ + '.ss__autocomplete__content__no-results': { + '.ss__autocomplete__content__no-results__text': { + p: { + display: 'inline', + margin: 0, + padding: 0, + fontSize: '14px', + '& ~ p': { + paddingLeft: '4px', + }, + }, + }, + '.ss__autocomplete__content__no-results__recommendations': { + '.ss__recommendation-grid': { + margin: `${custom.spacing.x4}px 0 0 0`, + }, + '.ss__recommendation-grid__title': { + textAlign: 'left', + }, + '.ss__recommendation-grid__results': { + ...resultsLayoutStyles, + }, + '.ss__recommendation-grid__results .ss__result.ss__result--grid': { + ...custom.styles.resultCompact('grid', '', 12), + }, + '.ss__recommendation-grid__results .ss__result.ss__result--list': { + ...custom.styles.resultCompact('', '0 0 80px', 12), + }, + }, + }, + }); + + // see more styles + const seeMoreStyles = css({ + '.ss__autocomplete__button--see-more': { + order: -1, + padding: 0, + height: 'auto', + lineHeight: 1, + '&, &:hover': { + backgroundColor: 'transparent', + border: 0, + }, + '.ss__button__content': { + margin: 0, + }, + }, + }); + + // see more mobile styles + const seeMoreMobileStyles = css({ + '.ss__autocomplete__button--see-more': { + order: 0, + }, + }); + + // standard styles + const standardStyles = css([ + sharedStyles, + { + alignContent: 'flex-start', + '& > .ss__autocomplete__row': { + gap: `${custom.spacing.x4}px`, + flexWrap: 'wrap', + '.ss__autocomplete__column': { + alignContent: 'flex-start', + minWidth: '1px', + maxWidth: 'none', + flex: '1 1 100%', + margin: `0 -${custom.spacing.x4}px`, + padding: `0 ${custom.spacing.x4}px`, + paddingBottom: `${custom.spacing.x4}px`, + borderBottom: `1px solid ${custom.colors.gray02}`, + '&:last-of-type': { + paddingBottom: 0, + borderBottomWidth: 0, + }, + '.ss__autocomplete__row:has(.ss__autocomplete__button--see-more)': { + minWidth: '1px', + flex: '1 1 100%', + padding: `${custom.spacing.x4}px ${custom.spacing.x4}px 0 ${custom.spacing.x4}px`, + margin: `0 -${custom.spacing.x4}px`, + borderTop: `1px solid ${custom.colors.gray02}`, + }, + }, + }, + }, + termsWrapperStyles, + facetsStyles, + contentStyles, + resultsStyles, + noResultsStyles, + seeMoreStyles, + { + [`${custom.utils.getBp(custom.breakpoints.small, 'max')}`]: { + ...resultsSmallStyles, + }, + }, + { + [`${custom.utils.getBp(mobileBp)}`]: { + ...seeMoreMobileStyles, + }, + }, + { + [`${custom.utils.getBp(tabletBp)}`]: { + '& > .ss__autocomplete__row': { + '.ss__autocomplete__column': { + flex: '1 1 0%', + paddingBottom: 0, + borderBottomWidth: 0, + '&:has(.ss__autocomplete__terms-wrapper)': { + flex: '1 1 100%', + paddingBottom: `${custom.spacing.x4}px`, + borderBottomWidth: '1px', + }, + '&:has(.ss__autocomplete__facets-wrapper)': { + flex: `0 0 ${isModal ? 300 : 200}px`, + }, + '.ss__autocomplete__row:has(.ss__autocomplete__button--see-more)': { + borderTop: 0, + padding: 0, + margin: 0, + }, + }, + }, + '.ss__autocomplete__facets': { + '.ss__facets': { + flexWrap: 'wrap', + '.ss__facet': { + flex: '1 1 100%', + }, + }, + '.ss__banner': { + display: 'block', + }, + }, + }, + }, + { + [`${custom.utils.getBp(desktopBp)}`]: { + '&': sharedDesktopStyles, + '& > .ss__autocomplete__row': { + '.ss__autocomplete__column': { + '&:has(.ss__autocomplete__terms-wrapper)': { + paddingBottom: 0, + borderBottomWidth: 0, + }, + '&:has(.ss__autocomplete__terms-wrapper), &:has(.ss__autocomplete__facets-wrapper)': { + flex: `0 0 ${isModal ? 250 : 220}px`, + }, + }, + }, + '.ss__terms-list': { + flexWrap: 'wrap', + alignContent: 'flex-start', + '.ss__terms-list__row': { + flex: '1 1 100%', + '.ss__terms': { + width: '100%', + '.ss__terms__options': { + display: 'block', + '.ss__terms__option': { + a: { + padding: `${custom.spacing.x2}px 0`, + transition: `padding-left 0.5s ease`, + fontSize: '16px', + }, + }, + '.ss__terms__option--active': { + a: { + paddingLeft: `${custom.spacing.x4}px`, + backgroundColor: custom.colors.gray01, + }, + }, + }, + }, + }, + }, + '.ss__autocomplete__content__results .ss__results': { + maxHeight: isFixed ? '60vh' : '', + }, + }, + }, + ]); + + // mini styles + const miniStyles = css([ + sharedStyles, + sharedLayoutStyles, + termsWrapperStyles, + contentStyles, + { + '.ss__autocomplete__content .ss__autocomplete__content-inner > *:last-of-type': { + marginBottom: 0, + }, + }, + resultsStyles, + noResultsStyles, + seeMoreStyles, + { + [`${custom.utils.getBp(custom.breakpoints.small, 'max')}`]: { + ...resultsSmallStyles, + }, + }, + { + [`${custom.utils.getBp(mobileBp)}`]: { + ...seeMoreMobileStyles, + }, + }, + { + [`${custom.utils.getBp(desktopBp)}`]: { + '&': sharedDesktopStyles, + }, + }, + ]); + + // terms styles + const termsStyles = css([ + sharedStyles, + sharedLayoutStyles, + termsWrapperStyles, + contentStyles, + noResultsStyles, + seeMoreStyles, + { + [`${custom.utils.getBp(mobileBp)}`]: { + ...seeMoreMobileStyles, + }, + }, + { + [`${custom.utils.getBp(desktopBp)}`]: { + '&': sharedDesktopStyles, + '.ss__autocomplete__content__no-results .ss__autocomplete__content__no-results__text p': { + fontSize: '16px', + }, + }, + }, + ]); + + if (acLayout == 'terms') { + return termsStyles; + } else if (acLayout == 'mini') { + return miniStyles; + } else { + return standardStyles; + } +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteSlideout.ts b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteSlideout.ts new file mode 100644 index 000000000..c30d6b539 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/autocompleteSlideout.ts @@ -0,0 +1,123 @@ +import { css } from '@emotion/react'; +import { autocompleteSlideoutThemeComponentProps } from '../../../themeComponents/autocompleteSlideout'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteSlideoutProps } from '../../../../components/Templates/AutocompleteSlideout'; +import { autocompleteSharedStyleScript } from '../templates/autocompleteShared'; +import { custom } from '../../custom'; + +// static variables +const searchInputHeight = 40; + +// CSS in JS style script for the Search component +const autocompleteSlideoutStyleScript = (props: AutocompleteSlideoutProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // autocomplete shared styles + const sharedStyles = css({ + '.ss__autocomplete-slideout__inner': { + '.ss__autocomplete': { + ...autocompleteSharedStyleScript(props, 'autocompleteSlideout'), + }, + }, + }); + + // autocomplete fixed styles + const fixedStyles = css({ + border: 0, + padding: `${custom.spacing.x4}px`, + ...custom.styles.boxSizing('autocompleteSlideout', props?.treePath, props?.name), + '.ss__autocomplete-slideout__inner': { + height: '100%', + '& > .ss__search-input': { + height: `${searchInputHeight}px`, + margin: `0 0 ${custom.spacing.x4}px 0`, + '.ss__button, .ss__search-input__button--close-search-button': { + width: `${searchInputHeight}px`, + }, + }, + '.ss__autocomplete': { + alignContent: 'flex-start', + overflow: 'visible', + height: 'calc(100% - 60px)', + overflowY: 'auto', + overflowX: 'hidden', + ...custom.styles.scrollbar(), + }, + }, + }); + + // autocomplete styles + const autocompleteSlideoutStyles = css([sharedStyles, fixedStyles]); + + return autocompleteSlideoutStyles; +}; + +export const autocompleteSlideout: ThemeComponent<'autocompleteSlideout', AutocompleteSlideoutProps> = { + default: { + ...autocompleteSlideoutThemeComponentProps.default, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.default?.['autocompleteSlideout'] || {}), + themeStyleScript: autocompleteSlideoutStyleScript, + layout: 'mini', + contentTitle: 'Product Suggestions', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout button.see-more icon': { + size: `${custom.sizes.icon12}px`, + icon: custom.icons.arrowRight, + }, + }, + mobile: { + ...autocompleteSlideoutThemeComponentProps.mobile, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.mobile?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, + tablet: { + ...autocompleteSlideoutThemeComponentProps.tablet, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.tablet?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, + desktop: { + ...autocompleteSlideoutThemeComponentProps.desktop, + autocompleteSlideout: { + ...(autocompleteSlideoutThemeComponentProps.desktop?.['autocompleteSlideout'] || {}), + layout: 'mini', + }, + 'autocompleteSlideout results': { + rows: 2, + columns: 3, + }, + 'autocompleteSlideout recommendationGrid': { + rows: 2, + columns: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/index.ts b/packages/snap-preact/components/src/themes/pike/components/templates/index.ts new file mode 100644 index 000000000..e6bef36ce --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/index.ts @@ -0,0 +1,79 @@ +import { ThemeResponsiveComplete } from '../../../../providers'; + +// TEMPLATES +import { autocompleteFixed } from './autocompleteFixed'; +import { autocompleteModal } from './autocompleteModal'; +import { autocompleteSlideout } from './autocompleteSlideout'; +import { recommendation } from './recommendation'; +import { recommendationBundle } from './recommendationBundle'; +import { recommendationBundleEasyAdd } from './recommendationBundleEasyAdd'; +import { recommendationBundleList } from './recommendationBundleList'; +import { recommendationBundleVertical } from './recommendationBundleVertical'; +import { recommendationGrid } from './recommendationGrid'; +import { recommendationEmail } from './recommendationEmail'; +import { search } from './search'; +import { searchHorizontal } from './searchHorizontal'; +import { searchCollapsible } from './searchCollapsible'; + +export const templates: ThemeResponsiveComplete = { + default: { + ...autocompleteFixed.default, + ...autocompleteModal.default, + ...autocompleteSlideout.default, + ...recommendation.default, + ...recommendationBundle.default, + ...recommendationBundleEasyAdd.default, + ...recommendationBundleList.default, + ...recommendationBundleVertical.default, + ...recommendationGrid.default, + ...recommendationEmail.default, + ...search.default, + ...searchCollapsible.default, + ...searchHorizontal.default, + }, + mobile: { + ...autocompleteFixed.mobile, + ...autocompleteModal.mobile, + ...autocompleteSlideout.mobile, + ...recommendation.mobile, + ...recommendationBundle.mobile, + ...recommendationBundleEasyAdd.mobile, + ...recommendationBundleList.mobile, + ...recommendationBundleVertical.mobile, + ...recommendationGrid.mobile, + ...recommendationEmail.mobile, + ...search.mobile, + ...searchCollapsible.mobile, + ...searchHorizontal.mobile, + }, + tablet: { + ...autocompleteFixed.tablet, + ...autocompleteModal.tablet, + ...autocompleteSlideout.tablet, + ...recommendation.tablet, + ...recommendationBundle.tablet, + ...recommendationBundleEasyAdd.tablet, + ...recommendationBundleList.tablet, + ...recommendationBundleVertical.tablet, + ...recommendationGrid.tablet, + ...recommendationEmail.tablet, + ...search.tablet, + ...searchCollapsible.tablet, + ...searchHorizontal.tablet, + }, + desktop: { + ...autocompleteFixed.desktop, + ...autocompleteModal.desktop, + ...autocompleteSlideout.desktop, + ...recommendation.desktop, + ...recommendationBundle.desktop, + ...recommendationBundleEasyAdd.desktop, + ...recommendationBundleList.desktop, + ...recommendationBundleVertical.desktop, + ...recommendationGrid.desktop, + ...recommendationEmail.desktop, + ...search.desktop, + ...searchCollapsible.desktop, + ...searchHorizontal.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendation.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendation.ts new file mode 100644 index 000000000..69767bf62 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendation.ts @@ -0,0 +1,161 @@ +import { css } from '@emotion/react'; +import type { RecommendationProps } from '../../../../components/Templates/Recommendation'; +import { recommendationThemeComponentProps } from '../../../themeComponents/recommendation'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// static variables +const arrowSizes = { + default: 24, + mobile: 28, + tablet: 32, +}; + +// CSS in JS style script for the Recommendation component +const recommendationStyleScript = (props: RecommendationProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const desktopBp = variables?.breakpoints?.desktop || custom.breakpoints.desktop; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // recommendation styles + const recommendationStyles = css({ + margin: `${custom.spacing.x8}px 0`, + position: 'relative', + ...custom.styles.boxSizing('recommendation', props?.treePath, props?.name), + '.ss__recommendation__title': { + margin: `0 0 ${custom.spacing.x4}px 0`, + paddingRight: `${arrowSizes.default * 2 + custom.spacing.x1 + custom.spacing.x2}px`, + ...custom.styles.headerText(variables?.colors?.secondary, '18px'), + ...custom.styles.textOverflow(), + }, + '.ss__carousel': { + position: 'static', + '& >': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: '1px', + bottom: 'auto', + left: 'auto', + width: `${arrowSizes.default}px`, + height: `${arrowSizes.default}px`, + }, + '.ss__carousel__prev-wrapper': { + right: `${arrowSizes.default + custom.spacing.x1}px`, + }, + '.ss__carousel__next-wrapper': { + right: 0, + }, + }, + }, + [`${custom.utils.getBp(custom.breakpoints.small)}`]: { + '.ss__recommendation__title': { + fontSize: '22px', + }, + '.ss__carousel': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: '4.5px', + }, + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__carousel': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: '2.5px', + width: `${arrowSizes.mobile}px`, + height: `${arrowSizes.mobile}px`, + }, + '.ss__carousel__prev-wrapper': { + right: `${arrowSizes.mobile + custom.spacing.x1}px`, + }, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__recommendation__title': { + textAlign: 'center', + }, + '.ss__carousel': { + position: 'relative', + padding: `0 ${custom.spacing.x4 + arrowSizes.tablet}px`, + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + top: 0, + bottom: `calc(10.15rem - ${custom.spacing.x4}px)`, + width: `${arrowSizes.tablet}px`, + height: `${arrowSizes.tablet}px`, + }, + '.ss__carousel__prev-wrapper': { + right: `auto`, + left: 0, + }, + }, + }, + [`${custom.utils.getBp(desktopBp)}`]: { + '.ss__carousel': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + bottom: `calc(11rem - ${custom.spacing.x4}px)`, + }, + }, + }, + }); + + return recommendationStyles; +}; + +// Recommendation component props come from Template export +export const recommendation: ThemeComponent<'recommendation', RecommendationProps> = { + default: { + ...recommendationThemeComponentProps.default, + recommendation: { + ...(recommendationThemeComponentProps.default?.['recommendation'] || {}), + themeStyleScript: recommendationStyleScript, + }, + 'recommendation carousel': { + spaceBetween: custom.spacing.x4, + }, + 'recommendation carousel icon.prev': { + size: `${custom.sizes.icon12}px`, + }, + 'recommendation carousel icon.next': { + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...recommendationThemeComponentProps.mobile, + recommendation: { + ...(recommendationThemeComponentProps.mobile?.['recommendation'] || {}), + }, + 'recommendation carousel': { + spaceBetween: custom.spacing.x2, + }, + 'recommendation carousel icon.prev': { + size: `${custom.sizes.icon08}px`, + }, + 'recommendation carousel icon.next': { + size: `${custom.sizes.icon08}px`, + }, + }, + tablet: { + ...recommendationThemeComponentProps.tablet, + recommendation: { + ...(recommendationThemeComponentProps.tablet?.['recommendation'] || {}), + }, + 'recommendation carousel': { + spaceBetween: custom.spacing.x4, + }, + 'recommendation carousel icon.prev': { + size: `${custom.sizes.icon10}px`, + }, + 'recommendation carousel icon.next': { + size: `${custom.sizes.icon10}px`, + }, + }, + desktop: { + ...recommendationThemeComponentProps.desktop, + recommendation: { + ...(recommendationThemeComponentProps.desktop?.['recommendation'] || {}), + }, + 'recommendation carousel': { + spaceBetween: custom.spacing.x4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundle.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundle.ts new file mode 100644 index 000000000..fd950cf3b --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundle.ts @@ -0,0 +1,201 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleProps } from '../../../../components/Templates/RecommendationBundle'; +import { recommendationBundleThemeComponentProps } from '../../../themeComponents/recommendationBundle'; +import { ThemeComponent } from '../../../../providers'; +import { recommendationCTAStyleScript } from './recommendationCTA'; +import { custom } from '../../custom'; + +// static variables +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const fontColor = activeColors[1]; +const seedBadgeHeight = 22; +const checkboxHeight = 16; + +// CSS in JS style script for the RecommendationBundle component +const recommendationBundleStyleScript = (props: RecommendationBundleProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // bundle shared styles + const sharedStyles = css({ + '.ss__recommendation-bundle__wrapper__cta': { + ...recommendationCTAStyleScript(props, 'bundle', `${custom.spacing.x4}px`), + }, + }); + + // bundle styles + const bundleStyles = css({ + margin: `${custom.spacing.x8}px 0`, + ...custom.styles.boxSizing('recommendationBundle', props?.treePath, props?.name), + '.ss__recommendation-bundle__title': { + margin: `0 0 ${custom.spacing.x4}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '18px'), + }, + '.ss__recommendation-bundle__wrapper': { + flexFlow: 'row wrap', + width: 'auto', + maxWidth: 'none', + margin: `0 -${custom.spacing.x1}px`, + '& > *': { + flex: '0 1 auto', + minWidth: '1px', + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__carousel': { + width: `50%`, + padding: `0 ${custom.spacing.x1}px`, + }, + '.ss__recommendation-bundle__wrapper__carousel': { + '.ss__recommendation__carousel >': { + '.ss__carousel__prev-wrapper, .ss__carousel__next-wrapper': { + bottom: `calc(10.15rem - ${custom.spacing.x4}px)`, + }, + }, + }, + '.ss__recommendation-bundle__wrapper__cta': { + flex: '1 1 0%', + }, + '.ss__result-tracker, .ss__recommendation-bundle__wrapper__selector, .ss__recommendation-bundle__wrapper__selector .ss__recommendation-bundle__wrapper__selector__result-wrapper, .ss__result': + { + height: '100%', + margin: 0, + }, + '.ss__recommendation-bundle__wrapper__selector': { + '&.ss__recommendation-bundle__wrapper__selector--seed': { + width: 'auto !important', + '.ss__recommendation-bundle__wrapper__selector__result-wrapper .ss__result': { + '&:has(.ss__overlay-badge__grid-wrapper__slot--right) .ss__overlay-badge .ss__overlay-badge__grid-wrapper .ss__overlay-badge__grid-wrapper__slot--right': + { + paddingTop: `${checkboxHeight + custom.spacing.x2}px`, + }, + '&:has(.ss__overlay-badge__grid-wrapper__slot--left) .ss__overlay-badge .ss__overlay-badge__grid-wrapper .ss__overlay-badge__grid-wrapper__slot--left': + { + paddingTop: `${seedBadgeHeight + custom.spacing.x2}px`, + }, + }, + }, + '.ss__recommendation-bundle__wrapper__selector__result-wrapper': { + 'ss__recommendation-bundle__wrapper__selector__result-wrapper__seed-badge, .ss__checkbox': { + position: 'absolute', + zIndex: '5px', + }, + '.ss__recommendation-bundle__wrapper__selector__result-wrapper__seed-badge': { + top: '5px', + left: '5px', + backgroundColor: activeColor, + fontSize: '12px', + fontWeight: custom.fonts.weight01, + color: fontColor, + height: `${seedBadgeHeight}px`, + lineHeight: `${seedBadgeHeight}px`, + padding: `0 ${custom.spacing.x2}px`, + }, + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + '.ss__result': { + '&:has(.ss__overlay-badge__grid-wrapper__slot--right) .ss__overlay-badge .ss__overlay-badge__grid-wrapper .ss__overlay-badge__grid-wrapper__slot--right': + { + paddingTop: `${checkboxHeight + custom.spacing.x2}px`, + }, + }, + }, + }, + }, + [`${custom.utils.getBp(custom.breakpoints.small)}`]: { + '.ss__recommendation-bundle__title': { + fontSize: '22px', + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__recommendation-bundle__wrapper': { + flexFlow: `row nowrap`, + margin: `0 0 -${custom.spacing.x4}px 0`, + '.ss__recommendation-bundle__wrapper__seed-container, .ss__recommendation-bundle__wrapper__carousel': { + padding: `0 ${custom.spacing.x4}px 0 0`, + }, + '.ss__recommendation-bundle__wrapper__seed-container': { + width: '25%', + }, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__recommendation-bundle__title': { + textAlign: 'center', + }, + '.ss__recommendation-bundle__wrapper': { + '.ss__recommendation-bundle__wrapper__seed-container': { + width: `20%`, + }, + '.ss__recommendation-bundle__wrapper__carousel': { + width: '60%', + }, + }, + }, + }); + + // recommendation bundle styles + const recommendationBundleStyles = css([sharedStyles, bundleStyles]); + + return recommendationBundleStyles; +}; + +// RecommendationBundle component props come from Template export +export const recommendationBundle: ThemeComponent<'recommendationBundle', RecommendationBundleProps> = { + default: { + ...recommendationBundleThemeComponentProps.default, + recommendationBundle: { + ...(recommendationBundleThemeComponentProps.default?.['recommendationBundle'] || {}), + themeStyleScript: recommendationBundleStyleScript, + ctaButtonText: 'Add Selected', + ctaButtonSuccessText: 'Added!', + separatorIcon: false, + separatorIconSeedOnly: false, + }, + 'recommendationBundle icon.bundle-cart': { + size: `${custom.sizes.icon16 * 2}px`, + icon: custom.icons.bag, + color: custom.colors.secondary, + }, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + 'recommendationBundle carousel icon.prev': { + size: `${custom.sizes.icon12}px`, + }, + 'recommendationBundle carousel icon.next': { + size: `${custom.sizes.icon12}px`, + }, + }, + mobile: { + ...recommendationBundleThemeComponentProps.mobile, + recommendationBundle: { + ...(recommendationBundleThemeComponentProps.mobile?.['recommendationBundle'] || {}), + }, + 'recommendationBundle carousel': { + spaceBetween: 0, + }, + }, + tablet: { + ...recommendationBundleThemeComponentProps.tablet, + recommendationBundle: { + ...(recommendationBundleThemeComponentProps.tablet?.['recommendationBundle'] || {}), + }, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, + desktop: { + ...recommendationBundleThemeComponentProps.desktop, + recommendationBundle: { + ...(recommendationBundleThemeComponentProps.desktop?.['recommendationBundle'] || {}), + }, + 'recommendationBundle carousel': { + spaceBetween: custom.spacing.x4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleEasyAdd.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleEasyAdd.ts new file mode 100644 index 000000000..6507c31b8 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleEasyAdd.ts @@ -0,0 +1,99 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleEasyAddProps } from '../../../../components/Templates/RecommendationBundleEasyAdd'; +import { recommendationBundleEasyAddThemeComponentProps } from '../../../themeComponents/recommendationBundleEasyAdd'; +import { ThemeComponent } from '../../../../providers'; +import { recommendationCTAStyleScript } from './recommendationCTA'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundleEasyAdd component +const recommendationBundleEasyAddStyleScript = (props: RecommendationBundleEasyAddProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // bundle easy add shared styles + const sharedStyles = css({ + '.ss__recommendation-bundle-easy-add__wrapper__cta': { + ...recommendationCTAStyleScript(props, 'bundle-easy-add'), + }, + }); + + // bundle easy add styles + const bundleEasyAddStyles = css({ + margin: `${custom.spacing.x4}px 0`, + ...custom.styles.boxSizing('recommendationBundleEasyAdd', props?.treePath, props?.name), + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-easy-add__title': { + ...custom.styles.headerText(variables?.colors?.secondary, '16px'), + }, + '.ss__recommendation-bundle-easy-add__wrapper': { + display: 'block', + '.ss__recommendation-bundle-easy-add__wrapper__selector': { + '.ss__recommendation-bundle-easy-add__wrapper__selector__result-wrapper': { + margin: 0, + '.ss__result.ss__result--grid': { + ...custom.styles.resultCompact('grid'), + }, + '.ss__result.ss__result--list': { + ...custom.styles.resultCompact(), + }, + }, + }, + }, + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal': { + '.ss__recommendation-bundle-easy-add__wrapper__cta__subtotal__icon__wrapper': { + display: 'none', + }, + }, + }); + + // recommendation bundle easy add styles + const recommendationBundleEasyAddStyles = css([sharedStyles, bundleEasyAddStyles]); + + return recommendationBundleEasyAddStyles; +}; + +// RecommendationBundleEasyAdd component props come from Template export +export const recommendationBundleEasyAdd: ThemeComponent<'recommendationBundleEasyAdd', RecommendationBundleEasyAddProps> = { + default: { + ...recommendationBundleEasyAddThemeComponentProps.default, + recommendationBundleEasyAdd: { + ...(recommendationBundleEasyAddThemeComponentProps.default?.['recommendationBundleEasyAdd'] || {}), + themeStyleScript: recommendationBundleEasyAddStyleScript, + ctaButtonText: 'Add Both to Cart', + ctaButtonSuccessText: 'Added!', + }, + 'recommendationBundleEasyAdd icon.bundle-cart': { + size: `${custom.sizes.icon16 * 2}px`, + icon: custom.icons.bag, + color: custom.colors.secondary, + }, + 'recommendationBundleEasyAdd result': { + layout: 'list', + }, + }, + mobile: { + ...recommendationBundleEasyAddThemeComponentProps.mobile, + recommendationBundleEasyAdd: { + ...(recommendationBundleEasyAddThemeComponentProps.mobile?.['recommendationBundleEasyAdd'] || {}), + }, + }, + tablet: { + ...recommendationBundleEasyAddThemeComponentProps.tablet, + recommendationBundleEasyAdd: { + ...(recommendationBundleEasyAddThemeComponentProps.tablet?.['recommendationBundleEasyAdd'] || {}), + }, + }, + desktop: { + ...recommendationBundleEasyAddThemeComponentProps.desktop, + recommendationBundleEasyAdd: { + ...(recommendationBundleEasyAddThemeComponentProps.desktop?.['recommendationBundleEasyAdd'] || {}), + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleList.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleList.ts new file mode 100644 index 000000000..d1a54f461 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleList.ts @@ -0,0 +1,171 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleListProps } from '../../../../components/Templates/RecommendationBundleList'; +import { recommendationBundleListThemeComponentProps } from '../../../themeComponents/recommendationBundleList'; +import { ThemeComponent } from '../../../../providers'; +import { recommendationCTAStyleScript } from './recommendationCTA'; +import { custom } from '../../custom'; + +// static variables +const plusIconSize = custom.sizes.icon12; + +// CSS in JS style script for the RecommendationBundleList component +const recommendationBundleListStyleScript = (props: RecommendationBundleListProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + // bundle list shared styles + const sharedStyles = css({ + '.ss__recommendation-bundle-list__wrapper__cta': { + ...recommendationCTAStyleScript(props, 'bundle-list'), + }, + }); + + // bundle list styles + const bundleListStyles = css({ + margin: `${custom.spacing.x4}px 0`, + ...custom.styles.boxSizing('recommendationBundleList', props?.treePath, props?.name), + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `${custom.spacing.x2}px 0 0 0`, + '&:first-of-type': { + marginTop: 0, + }, + }, + }, + '.ss__recommendation-bundle-list__title': { + ...custom.styles.headerText(variables?.colors?.secondary, '16px'), + }, + '.ss__recommendation-bundle-list__wrapper': { + flexFlow: 'row wrap', + gap: `${custom.spacing.x2}px ${custom.spacing.x4}px`, + '& > *': { + minWidth: '1px', + width: 'auto', + flex: '1 1 100%', + }, + '.ss__recommendation-bundle-list__wrapper__selector': { + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper': { + alignItems: 'flex-start', + gap: `${custom.spacing.x2}px`, + margin: 0, + '.ss__recommendation-bundle-list__wrapper__selector__result-wrapper__checkbox, .ss__result': { + flex: '0 1 auto', + minWidth: '1px', + }, + '.ss__result': { + flex: '1 1 0%', + }, + '.ss__result.ss__result--grid': { + ...custom.styles.resultCompact('grid'), + }, + '.ss__result.ss__result--list': { + ...custom.styles.resultCompact(), + }, + }, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta': { + '.ss__recommendation-bundle-list__wrapper__cta__inner': { + '.ss__recommendation-bundle-list__wrapper__cta__inner__images': { + position: 'relative', + flexFlow: 'row nowrap', + gap: `${custom.spacing.x4 + plusIconSize}px`, + margin: `-${custom.spacing.x2}px -${custom.spacing.x2}px 0 -${custom.spacing.x2}px`, + padding: `0 0 ${custom.spacing.x2}px 0`, + backgroundColor: custom.colors.white, + borderBottom: `1px solid ${custom.colors.gray02}`, + '&:after': { + content: '""', + display: 'block', + position: 'absolute', + top: '-1px', + bottom: 0, + left: '-1px', + right: '-1px', + zIndex: 1, + margin: 'auto', + border: `1px solid ${custom.colors.white}`, + }, + '.ss__recommendation-bundle-list__wrapper__cta__inner__image-wrapper': { + position: 'relative', + zIndex: 2, + flex: '1 1 0%', + minWidth: '1px', + padding: 0, + '.ss__icon': { + top: 0, + bottom: 0, + right: `-${custom.spacing.x2 + plusIconSize}px`, + margin: 'auto 0', + }, + }, + }, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal': { + marginTop: `${custom.spacing.x2}px`, + '.ss__recommendation-bundle-list__wrapper__cta__subtotal__icon__wrapper': { + display: 'none', + }, + }, + }, + }, + [`${custom.utils.getBp(custom.breakpoints.small)}`]: { + '.ss__recommendation-bundle-list__wrapper > *': { + width: `calc((100% - ${custom.spacing.x4}px) / 2)`, + flex: '0 1 auto', + }, + }, + }); + + // recommendation bundle list styles + const recommendationBundleListStyles = css([sharedStyles, bundleListStyles]); + + return recommendationBundleListStyles; +}; + +// RecommendationBundleList component props come from Template export +export const recommendationBundleList: ThemeComponent<'recommendationBundleList', RecommendationBundleListProps> = { + default: { + ...recommendationBundleListThemeComponentProps.default, + recommendationBundleList: { + ...(recommendationBundleListThemeComponentProps.default?.['recommendationBundleList'] || {}), + themeStyleScript: recommendationBundleListStyleScript, + ctaButtonText: 'Add Selected', + ctaButtonSuccessText: 'Added!', + limit: 6, + }, + 'recommendationBundleList icon.bundle-cart-separator': { + size: `${plusIconSize}px`, + icon: custom.icons.plus, + color: custom.colors.secondary, + }, + 'recommendationBundleList icon.bundle-cart': { + size: `${custom.sizes.icon16 * 2}px`, + icon: custom.icons.bag, + color: custom.colors.secondary, + }, + 'recommendationBundleList checkbox': { + size: `${custom.sizes.icon16 + 2}px`, + }, + 'recommendationBundleList checkbox icon': { + size: `${custom.sizes.icon10}px`, + }, + }, + mobile: { + ...recommendationBundleListThemeComponentProps.mobile, + recommendationBundleList: { + ...(recommendationBundleListThemeComponentProps.mobile?.['recommendationBundleList'] || {}), + }, + }, + tablet: { + ...recommendationBundleListThemeComponentProps.tablet, + recommendationBundleList: { + ...(recommendationBundleListThemeComponentProps.tablet?.['recommendationBundleList'] || {}), + }, + }, + desktop: { + ...recommendationBundleListThemeComponentProps.desktop, + recommendationBundleList: { + ...(recommendationBundleListThemeComponentProps.desktop?.['recommendationBundleList'] || {}), + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleVertical.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleVertical.ts new file mode 100644 index 000000000..c6df0b8eb --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationBundleVertical.ts @@ -0,0 +1,162 @@ +import { css } from '@emotion/react'; +import type { RecommendationBundleVerticalProps } from '../../../../components/Templates/RecommendationBundleVertical'; +import { recommendationBundleVerticalThemeComponentProps } from '../../../themeComponents/recommendationBundleVertical'; +import { ThemeComponent } from '../../../../providers'; +import { recommendationCTAStyleScript } from './recommendationCTA'; +import { custom } from '../../custom'; + +// static variables +const activeColors = custom.utils.activeColors(); +const activeColor = activeColors[0]; +const fontColor = activeColors[1]; +const seedBadgeHeight = 22; +const checkboxHeight = 16; + +// CSS in JS style script for the RecommendationBundleVertical component +const recommendationBundleVerticalStyleScript = (props: RecommendationBundleVerticalProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // bundle vertical shared styles + const sharedStyles = css({ + '.ss__recommendation-bundle-vertical__wrapper__cta': { + ...recommendationCTAStyleScript(props, 'bundle-vertical'), + }, + }); + + // bundle vertical styles + const bundleVerticalStyles = css({ + margin: `${custom.spacing.x4}px 0`, + ...custom.styles.boxSizing('recommendationBundleVertical', props?.treePath, props?.name), + '.ss__recommendation-profile-tracker': { + '& > *': { + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + }, + '.ss__recommendation-bundle-vertical__title': { + ...custom.styles.headerText(variables?.colors?.secondary, '16px'), + }, + '.ss__recommendation-bundle-vertical__wrapper': { + gap: `${custom.spacing.x2}px`, + '.ss__recommendation-bundle-vertical__wrapper__selector': { + '&.ss__recommendation-bundle-vertical__wrapper__selector--seed': { + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper .ss__result': { + '&:has(.ss__overlay-badge__grid-wrapper__slot--right) .ss__overlay-badge .ss__overlay-badge__grid-wrapper .ss__overlay-badge__grid-wrapper__slot--right': + { + paddingTop: `${checkboxHeight + custom.spacing.x2}px`, + }, + '&:has(.ss__overlay-badge__grid-wrapper__slot--left) .ss__overlay-badge .ss__overlay-badge__grid-wrapper .ss__overlay-badge__grid-wrapper__slot--left': + { + paddingTop: `${seedBadgeHeight + custom.spacing.x2}px`, + }, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper': { + margin: 0, + '&:has(.ss__result--grid)': { + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + }, + '&:has(.ss__result--list)': { + '.ss__checkbox': { + top: '5px', + right: '5px', + }, + }, + 'ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper__seed-badge, .ss__checkbox': { + position: 'absolute', + zIndex: '5px', + }, + '.ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper__seed-badge': { + top: '5px', + left: '5px', + backgroundColor: activeColor, + fontSize: '12px', + fontWeight: custom.fonts.weight01, + color: fontColor, + height: `${seedBadgeHeight}px`, + lineHeight: `${seedBadgeHeight}px`, + padding: `0 ${custom.spacing.x2}px`, + }, + '.ss__result': { + '&:has(.ss__overlay-badge__grid-wrapper__slot--right) .ss__overlay-badge .ss__overlay-badge__grid-wrapper .ss__overlay-badge__grid-wrapper__slot--right': + { + paddingTop: `${checkboxHeight + custom.spacing.x2}px`, + }, + }, + '.ss__result.ss__result--grid': { + ...custom.styles.resultCompact('grid'), + }, + '.ss__result.ss__result--list': { + ...custom.styles.resultCompact(), + }, + }, + }, + }, + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal': { + '.ss__recommendation-bundle-vertical__wrapper__cta__subtotal__icon__wrapper': { + display: 'none', + }, + }, + [`${custom.utils.getBp(mobileBp - 100)}`]: { + '.ss__recommendation-bundle-vertical__wrapper .ss__recommendation-bundle-vertical__wrapper__selector .ss__recommendation-bundle-vertical__wrapper__selector__result-wrapper:has(.ss__result--list) .ss__checkbox': + { + right: 'auto', + left: `calc(33.33% - ${custom.spacing.x4}px)`, + }, + }, + }); + + // recommendation bundle vertical styles + const recommendationBundleVerticalStyles = css([sharedStyles, bundleVerticalStyles]); + + return recommendationBundleVerticalStyles; +}; + +// RecommendationBundleVertical component props come from Template export +export const recommendationBundleVertical: ThemeComponent<'recommendationBundleVertical', RecommendationBundleVerticalProps> = { + default: { + ...recommendationBundleVerticalThemeComponentProps.default, + recommendationBundleVertical: { + ...(recommendationBundleVerticalThemeComponentProps.default?.['recommendationBundleVertical'] || {}), + themeStyleScript: recommendationBundleVerticalStyleScript, + ctaButtonText: 'Add Selected', + ctaButtonSuccessText: 'Added!', + separatorIcon: false, + separatorIconSeedOnly: false, + limit: 8, + }, + 'recommendationBundleVertical icon.bundle-cart': { + size: `${custom.sizes.icon16 * 2}px`, + icon: custom.icons.bag, + color: custom.colors.secondary, + }, + 'recommendationBundleVertical result': { + layout: 'list', + }, + }, + mobile: { + ...recommendationBundleVerticalThemeComponentProps.mobile, + recommendationBundleVertical: { + ...(recommendationBundleVerticalThemeComponentProps.mobile?.['recommendationBundleVertical'] || {}), + }, + }, + tablet: { + ...recommendationBundleVerticalThemeComponentProps.tablet, + recommendationBundleVertical: { + ...(recommendationBundleVerticalThemeComponentProps.tablet?.['recommendationBundleVertical'] || {}), + }, + }, + desktop: { + ...recommendationBundleVerticalThemeComponentProps.desktop, + recommendationBundleVertical: { + ...(recommendationBundleVerticalThemeComponentProps.desktop?.['recommendationBundleVertical'] || {}), + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationCTA.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationCTA.ts new file mode 100644 index 000000000..9604b0eb2 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationCTA.ts @@ -0,0 +1,81 @@ +import { css } from '@emotion/react'; +import { custom } from '../../custom'; +import { Theme } from '../../../../providers'; + +// CTA props +type CTAProps = { + theme?: Theme; +}; + +// static variables +const lightGray = custom.utils.lightenColor(); + +// CSS in JS style script for the Recommendation CTA component +export const recommendationCTAStyleScript = (props: CTAProps, handle: string, spacing?: string) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const recommendationHandle = `.ss__recommendation-${handle}__wrapper`; + + // shared styles + const sharedStyles = css({ + display: 'flex', + flexFlow: 'row wrap', + justifyContent: 'center', + alignItems: 'center', + alignContent: 'center', + gap: `${custom.spacing.x2}px`, + ...custom.styles.box(variables?.colors?.text, spacing ? spacing : `${custom.spacing.x2}px`), + '& > *': { + flex: '1 1 100%', + minWidth: '1px', + }, + [`${recommendationHandle}__cta__subtotal, ${recommendationHandle}__cta__button`]: { + position: 'relative', + zIndex: 2, + }, + [`${recommendationHandle}__cta__subtotal`]: { + color: variables?.colors?.text, + '& > *': { + margin: `0 0 ${custom.spacing.x2}px 0`, + '&:last-child': { + marginBottom: 0, + }, + }, + [`${recommendationHandle}__cta__subtotal__icon__wrapper`]: { + lineHeight: 1, + }, + [`${recommendationHandle}__cta__subtotal__title`]: { + display: 'block', + ...custom.styles.headerText(variables?.colors?.secondary, '16px'), + }, + [`${recommendationHandle}__cta__subtotal__prices`]: { + label: { + margin: 0, + padding: 0, + '& ~ label': { + paddingLeft: `${custom.spacing.x1}px`, + }, + }, + [`${recommendationHandle}__cta__subtotal__strike`]: { + '&, span': { + color: lightGray, + }, + '& ~ ${recommendationHandle}__cta__subtotal__price': { + '&, span': { + color: variables?.colors?.primary, + }, + }, + }, + [`${recommendationHandle}__cta__subtotal__price`]: { + '&, span': { + fontSize: '16px', + color: variables?.colors?.text, + fontWeight: custom.fonts.weight01, + }, + }, + }, + }, + }); + + return sharedStyles; +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationEmail.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationEmail.ts new file mode 100644 index 000000000..e2cb93ff6 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationEmail.ts @@ -0,0 +1,64 @@ +import { css } from '@emotion/react'; +import type { RecommendationEmailProps } from '../../../../components/Templates/RecommendationEmail'; +import { recommendationEmailThemeComponentProps } from '../../../themeComponents/recommendationEmail'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationEmail component +const recommendationEmailStyleScript = (props: RecommendationEmailProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + + const recommendationEmailStyles = css({ + ...custom.styles.boxSizing('recommendationEmail', props?.treePath, props?.name), + '.ss__recommendation-email__result-wrapper': { + width: '400px !important', + height: '475px', + margin: `0 0 ${custom.spacing.x6}px 0`, + padding: `0 ${custom.spacing.x2}px`, + overflow: 'hidden', + }, + '.ss__result': { + '&, &*': { + fontSize: '14px', + lineHeight: 1.4, + textAlign: 'center', + }, + '.ss__result__details': { + '.ss__result__details__title a': { + display: 'block', + height: '20px', + ...custom.styles.textOverflow(), + }, + }, + }, + }); + + return recommendationEmailStyles; +}; + +// RecommendationEmail component props come from Template export +export const recommendationEmail: ThemeComponent<'recommendationEmail', RecommendationEmailProps> = { + default: { + ...recommendationEmailThemeComponentProps.default, + recommendationEmail: { + ...(recommendationEmailThemeComponentProps.default?.['recommendationEmail'] || {}), + themeStyleScript: recommendationEmailStyleScript, + }, + 'recommendationEmail result': { + hideBadge: false, + }, + 'recommendationEmail result image': { + lazy: false, + }, + }, + mobile: { + ...recommendationEmailThemeComponentProps.mobile, + }, + tablet: { + ...recommendationEmailThemeComponentProps.tablet, + }, + desktop: { + ...recommendationEmailThemeComponentProps.desktop, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/recommendationGrid.ts b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationGrid.ts new file mode 100644 index 000000000..93c51b599 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/recommendationGrid.ts @@ -0,0 +1,73 @@ +import { css } from '@emotion/react'; +import type { RecommendationGridProps } from '../../../../components/Templates/RecommendationGrid'; +import { recommendationGridThemeComponentProps } from '../../../themeComponents/recommendationGrid'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the RecommendationBundle component +const recommendationGridStyleScript = (props: RecommendationGridProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // recommendation grid styles + const recommendationGridStyles = css({ + margin: `${custom.spacing.x8}px 0`, + maxHeight: 'none', + ...custom.styles.boxSizing('recommendationGrid', props?.treePath, props?.name), + '.ss__recommendation-grid__title': { + margin: `0 0 ${custom.spacing.x4}px 0`, + ...custom.styles.headerText(variables?.colors?.secondary, '18px'), + }, + '.ss__recommendation-grid__results': { + overflowX: 'auto', + ...custom.styles.scrollbar(), + }, + [`${custom.utils.getBp(custom.breakpoints.small)}`]: { + '.ss__recommendation-grid__title': { + fontSize: '22px', + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__recommendation-grid__title': { + textAlign: 'center', + }, + }, + }); + + return recommendationGridStyles; +}; + +// RecommendationGrid component props come from Template export +export const recommendationGrid: ThemeComponent<'recommendationGrid', RecommendationGridProps> = { + default: { + ...recommendationGridThemeComponentProps.default, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.default?.['recommendationGrid'] || {}), + themeStyleScript: recommendationGridStyleScript, + gapSize: `${custom.spacing.x4}px`, + columns: 4, + }, + }, + mobile: { + ...recommendationGridThemeComponentProps.mobile, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.mobile?.['recommendationGrid'] || {}), + gapSize: `${custom.spacing.x4}px ${custom.spacing.x2}px`, + columns: 2, + }, + }, + tablet: { + ...recommendationGridThemeComponentProps.tablet, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.tablet?.['recommendationGrid'] || {}), + columns: 3, + }, + }, + desktop: { + ...recommendationGridThemeComponentProps.desktop, + recommendationGrid: { + ...(recommendationGridThemeComponentProps.desktop?.['recommendationGrid'] || {}), + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/search.ts b/packages/snap-preact/components/src/themes/pike/components/templates/search.ts new file mode 100644 index 000000000..995191012 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/search.ts @@ -0,0 +1,141 @@ +import { css } from '@emotion/react'; +import type { SearchProps } from '../../../../components/Templates/Search'; +import { searchThemeComponentProps } from '../../../themeComponents/search'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchStyleScript = (props: SearchProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // search styles + const searchStyles = css({ + ...custom.styles.boxSizing('search', props?.treePath, props?.name), + '.ss__search__header-section, .ss__search__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + }, + '.ss__search__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search__sidebar, .ss__search__content': { + minWidth: '1px', + }, + '.ss__search__sidebar': { + flex: '0 1 auto', + '.ss__sidebar': { + width: '250px', + }, + }, + '.ss__search__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + '.ss__toolbar': { + '.ss__layout__row': { + '&:has(.ss__pagination-info:last-child)': { + flexDirection: 'row-reverse', + }, + '&:has(.ss__mobile-sidebar)': { + '.ss__mobile-sidebar': { + minWidth: '1px', + '.ss__mobile-sidebar__slideout__button': { + width: '100%', + }, + }, + }, + }, + }, + }, + [`${custom.utils.getBp(custom.breakpoints.small)}`]: { + '.ss__search__main-section': { + '.ss__toolbar': { + '.ss__layout__row:has(.ss__mobile-sidebar)': { + '.ss__mobile-sidebar': { + minWidth: '200px', + }, + }, + }, + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__search__main-section': { + '.ss__toolbar': { + '.ss__layout__row': { + '&:has(.ss__select)': { + '.ss__select': { + flex: '1 1 0%', + }, + '.ss__layout__separator': { + display: 'none', + }, + }, + '.ss__pagination-info': { + flex: '1 1 100%', + order: -1, + }, + }, + }, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '.ss__search__main-section': { + '.ss__toolbar': { + '.ss__layout__row': { + '&:has(.ss__select)': { + '.ss__select': { + flex: '0 1 auto', + }, + '.ss__layout__separator': { + display: 'block', + }, + }, + '.ss__pagination-info': { + flex: '1 1 0%', + order: 0, + }, + }, + }, + }, + }, + }); + + return searchStyles; +}; + +// Search component props come from Template export +export const search: ThemeComponent<'search', SearchProps> = { + default: { + ...searchThemeComponentProps.default, + search: { + ...(searchThemeComponentProps.default?.['search'] || {}), + themeStyleScript: searchStyleScript, + mobileDisplayAt: `${custom.breakpoints.mobile}px`, + }, + }, + mobile: { + ...searchThemeComponentProps.mobile, + search: { + ...(searchThemeComponentProps.mobile?.['search'] || {}), + }, + }, + tablet: { + ...searchThemeComponentProps.tablet, + search: { + ...(searchThemeComponentProps.tablet?.['search'] || {}), + }, + 'search results': { + columns: 2, + }, + }, + desktop: { + ...searchThemeComponentProps.desktop, + search: { + ...(searchThemeComponentProps.desktop?.['search'] || {}), + }, + 'search results': { + columns: 3, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/searchCollapsible.ts b/packages/snap-preact/components/src/themes/pike/components/templates/searchCollapsible.ts new file mode 100644 index 000000000..e6729ffbb --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/searchCollapsible.ts @@ -0,0 +1,164 @@ +import { css } from '@emotion/react'; +import type { SearchCollapsibleProps } from '../../../../components/Templates/SearchCollapsible'; +import { searchCollapsibleThemeComponentProps } from '../../../themeComponents/searchCollapsible'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchCollapsibleStyleScript = (props: SearchCollapsibleProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const tabletBp = variables?.breakpoints?.tablet || custom.breakpoints.tablet; + + // search collapsible styles + const searchCollapsibleStyles = css({ + ...custom.styles.boxSizing('searchCollapsible', props?.treePath, props?.name), + '&:not(:has(.ss__no-results))': { + '.ss__search-collapsible__header-section': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '.ss__toolbar': { + '.ss__layout__row:has(.ss__search-header)': { + margin: `0 0 ${custom.spacing.x4}px 0`, + '.ss__search-header': { + textAlign: 'center', + }, + }, + }, + }, + }, + '.ss__search-collapsible__header-section, .ss__search-collapsible__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + }, + '.ss__search-collapsible__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search-collapsible__sidebar, .ss__search-collapsible__content': { + minWidth: '1px', + }, + '.ss__search-collapsible__sidebar': { + flex: '0 1 auto', + '.ss__sidebar': { + width: '250px', + }, + }, + '.ss__search-collapsible__content': { + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + }, + [`${custom.utils.getBp(tabletBp)}`]: { + '&:not(:has(.ss__no-results))': { + '.ss__search-collapsible__header-section': { + margin: 0, + '.ss__toolbar': { + '.ss__layout__row:has(.ss__search-header)': { + flexWrap: 'nowrap', + '.ss__search-header': { + textAlign: 'left', + '&:has(.ss__search-header__subtitle)': { + '.ss__search-header__title': { + padding: `0 ${custom.spacing.x1}px 0 0`, + '&:after': { + content: '"."', + }, + }, + }, + '.ss__search-header__title, .ss__search-header__subtitle': { + display: 'inline', + }, + '.ss__search-header__title': { + fontSize: '16px', + }, + '.ss__search-header__subtitle': { + fontSize: '14px', + }, + }, + }, + }, + }, + }, + '&:not(.ss__search-collapsible--sidebar-open)': { + '&:has(.ss__list__option--selected[title*="2"])': { + '.ss__results-grid': { + gridTemplateColumns: 'repeat(3, 1fr)', + }, + }, + '&:has(.ss__list__option--selected[title*="3"])': { + '.ss__results-grid': { + gridTemplateColumns: 'repeat(4, 1fr)', + }, + }, + '&:has(.ss__list__option--selected[title*="4"])': { + '.ss__results-grid': { + gridTemplateColumns: 'repeat(5, 1fr)', + }, + }, + }, + }, + }); + + return searchCollapsibleStyles; +}; + +export const searchCollapsible: ThemeComponent<'searchCollapsible', SearchCollapsibleProps> = { + default: { + ...searchCollapsibleThemeComponentProps.default, + searchCollapsible: { + ...(searchCollapsibleThemeComponentProps.default?.['searchCollapsible'] || {}), + themeStyleScript: searchCollapsibleStyleScript, + }, + 'searchCollapsible sidebar': { + hideTitleText: true, + }, + 'searchCollapsible button.sidebar-toggle': { + icon: custom.icons.filter, + }, + 'searchCollapsible filterSummary': { + type: 'list', + }, + }, + mobile: { + ...searchCollapsibleThemeComponentProps.mobile, + searchCollapsible: { + ...(searchCollapsibleThemeComponentProps.mobile?.['searchCollapsible'] || {}), + }, + }, + tablet: { + ...searchCollapsibleThemeComponentProps.tablet, + searchCollapsible: { + ...(searchCollapsibleThemeComponentProps.tablet?.['searchCollapsible'] || {}), + }, + }, + desktop: { + ...searchCollapsibleThemeComponentProps.desktop, + searchCollapsible: { + ...(searchCollapsibleThemeComponentProps.desktop?.['searchCollapsible'] || {}), + layoutOptions: [ + { + value: 1, + label: '3 wide', + default: true, + icon: 'layout-grid-3', + overrides: { + components: { + 'searchCollapsible results': { + columns: 3, + }, + }, + }, + }, + { + value: 2, + label: '2 wide', + icon: 'layout-grid-2', + overrides: { + components: { + 'searchCollapsible results': { + columns: 2, + }, + }, + }, + }, + ], + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/components/templates/searchHorizontal.ts b/packages/snap-preact/components/src/themes/pike/components/templates/searchHorizontal.ts new file mode 100644 index 000000000..0adc8a657 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/components/templates/searchHorizontal.ts @@ -0,0 +1,106 @@ +import { css } from '@emotion/react'; +import type { SearchHorizontalProps } from '../../../../components/Templates/SearchHorizontal'; +import { searchHorizontalThemeComponentProps } from '../../../themeComponents/searchHorizontal'; +import { ThemeComponent } from '../../../../providers'; +import { custom } from '../../custom'; + +// CSS in JS style script for the Search component +const searchHorizontalStyleScript = (props: SearchHorizontalProps) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const variables = props?.theme?.variables; + const mobileBp = variables?.breakpoints?.mobile || custom.breakpoints.mobile; + + // search horizontal styles + const searchHorizontalStyles = css({ + ...custom.styles.boxSizing('searchHorizontal', props?.treePath, props?.name), + '.ss__search-horizontal__header-section, .ss__search-horizontal__main-section': { + margin: `0 0 ${custom.spacing.x6}px 0`, + }, + '.ss__search-horizontal__main-section': { + gap: `${custom.spacing.x6}px`, + '.ss__search-horizontal__content': { + minWidth: '1px', + flex: '1 1 0%', + gap: `${custom.spacing.x4}px`, + }, + '.ss__facets-horizontal': { + margin: `0 0 ${custom.spacing.x4}px 0`, + }, + '.ss__toolbar': { + '.ss__layout__row': { + '&:has(.ss__mobile-sidebar)': { + '.ss__mobile-sidebar': { + minWidth: '1px', + '.ss__mobile-sidebar__slideout__button': { + width: '100%', + }, + }, + }, + '&:has(.ss__select)': { + '.ss__select': { + flex: '1 1 0%', + }, + }, + }, + }, + }, + [`${custom.utils.getBp(custom.breakpoints.small)}`]: { + '.ss__search-horizontal__main-section': { + '.ss__toolbar': { + '.ss__layout__row:has(.ss__mobile-sidebar)': { + '.ss__mobile-sidebar': { + minWidth: '200px', + }, + }, + }, + }, + }, + [`${custom.utils.getBp(mobileBp)}`]: { + '.ss__search-horizontal__main-section': { + '.ss__toolbar': { + '.ss__layout__row:has(.ss__select)': { + '.ss__select': { + flex: '0 1 auto', + }, + }, + }, + }, + }, + }); + + return searchHorizontalStyles; +}; + +export const searchHorizontal: ThemeComponent<'searchHorizontal', SearchHorizontalProps> = { + default: { + ...searchHorizontalThemeComponentProps.default, + searchHorizontal: { + ...(searchHorizontalThemeComponentProps.default?.['searchHorizontal'] || {}), + themeStyleScript: searchHorizontalStyleScript, + }, + 'searchHorizontal results': { + columns: 5, + }, + }, + mobile: { + ...searchHorizontalThemeComponentProps.mobile, + searchHorizontal: { + ...(searchHorizontalThemeComponentProps.mobile?.['searchHorizontal'] || {}), + }, + }, + tablet: { + ...searchHorizontalThemeComponentProps.tablet, + searchHorizontal: { + ...(searchHorizontalThemeComponentProps.tablet?.['searchHorizontal'] || {}), + }, + }, + desktop: { + ...searchHorizontalThemeComponentProps.desktop, + searchHorizontal: { + ...(searchHorizontalThemeComponentProps.desktop?.['searchHorizontal'] || {}), + }, + 'searchHorizontal results': { + columns: 4, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/pike/custom.ts b/packages/snap-preact/components/src/themes/pike/custom.ts new file mode 100644 index 000000000..ca3800c83 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/custom.ts @@ -0,0 +1,335 @@ +import { IconType } from '../../components/Atoms/Icon'; +import Color from 'color'; + +// calculate spacing +const spacing = 5; +const spacingCalc = (value: number) => { + return spacing * value; +}; + +// custom theme object +// contains defaults, colors, utils, global styles, etc. +export const custom: CustomThemeType = { + breakpoints: { + small: 540, + mobile: 767, + tablet: 991, + desktop: 1199, + }, + colors: { + text: '#515151', // theme color + primary: '#00aeef', // theme color + secondary: '#1d4990', // theme color + accent: '#2154a5', // theme color + white: '#ffffff', + black: '#000000', + gray01: '#f8f8f8', // lighter gray: bg color under terms, dropdown, checkboxes + gray02: '#ebebeb', // light gray: borders for autocomplete, dropdown, checkboxes + }, + fonts: { + weight01: 700, // main font weight + weight02: 700, // header font weight + style: false, + transform: 'none', + }, + icons: { + arrowLeft: 'chevron-left', + arrowRight: 'chevron-right', + arrowDown: 'chevron-down', + arrowUp: 'chevron-up', + bag: 'bag', + check: 'square', + close: 'close', + minus: 'minus', + plus: 'plus', + filter: 'filter', + search: 'search', + sort: 'sort', + }, + sizes: { + font: 16, // base font size + height: 35, // refers to height for button and dropdown sizes + icon08: 8, + icon10: 10, + icon12: 12, + icon14: 14, + icon16: 16, + radius: 0, // global border radius value + }, + spacing: { + x1: spacing, + x2: spacingCalc(2), + x3: spacingCalc(3), + x4: spacingCalc(4), + x5: spacingCalc(5), + x6: spacingCalc(6), + x7: spacingCalc(7), + x8: spacingCalc(8), + }, + styles: { + activeText: (color?: string) => { + // active text styles + return { + '&, &:hover': { + fontWeight: custom?.fonts?.weight01, + color: color ? color : '', + }, + }; + }, + badgeText: (fontSize: number) => { + // badge text styles + return { + display: 'block', + fontSize: fontSize, + lineHeight: 1.2, + }; + }, + borderRadius: (value?: number, unit?: string) => { + const hasValue = value || value === 0 ? true : false; + value = hasValue ? value : custom.sizes.radius; + unit = unit ? unit : value === 0 ? '' : 'px'; + + // sets border radius + return { + borderRadius: hasValue || custom.sizes.radius ? `${value}${unit}` : ``, + }; + }, + box: (color?: string, padding?: number | string, radius?: boolean) => { + // styles for box designs + + // define padding value + if (padding) { + padding = padding; + } else if (padding === 0) { + padding = ''; + } else { + padding = `${custom.spacing.x2}px` as number | string; + } + + // check if radius setting is available + const hasRadius = typeof radius == 'boolean' ? radius : true; + + // radius style if available + const radiusStyle = hasRadius && custom.sizes.radius ? custom.styles.borderRadius() : null; + + return { + border: `1px solid ${custom.colors.gray02}`, + ...radiusStyle, + backgroundColor: custom.colors.gray01, + color: color ? color : '', + padding: padding, + }; + }, + boxSizing: (component: string, treePath?: string, name?: string) => { + treePath = treePath ? treePath : component; + component = name ? `${component}.${name}` : component; // if name is present, add to component + component = treePath.includes('storybook') ? `storybook ${component}` : component; // or if component is in storybook, add it + + // box-sizing rules for uniform sizing + // if path and component are same, apply box-sizing + // if they are not the same, this means some parent component will have the box sizing rules + if (treePath == component) { + return { + '&, *, *:before, *:after': { + boxSizing: 'border-box', + }, + }; + } else { + return null; + } + }, + disabled: () => { + // disabled styles + return { + '&': { + opacity: 0.65, + pointerEvents: 'unset', + }, + '&, *': { + cursor: 'not-allowed !important', + }, + }; + }, + headerText: (color?: string, fontSize?: string) => { + // header text styles + return { + fontSize: fontSize ? fontSize : '', + fontWeight: custom?.fonts?.weight02, + textTransform: custom?.fonts?.transform, + color: color ? color : '', + }; + }, + resultCompact: (layout?: string, imageWidth?: string, fontSize?: number) => { + layout = (layout && layout == 'grid') || layout == 'list' ? layout : 'list'; + fontSize = fontSize ? fontSize : 14; + + // shared styles + const sharedStyles = { + '&': { + gap: `${custom.spacing.x1}px`, + }, + '.ss__result__details__title a, .ss__result__details__pricing .ss__price--strike, .ss__result__details__pricing .ss__price--strike span': { + fontSize: `${fontSize}px`, + }, + '.ss__result__details__pricing .ss__result__price': { + fontSize: `${fontSize + 2}px`, + }, + '.ss__result__details__title a': { + display: '-webkit-box', + WebkitBoxOrient: 'vertical', + overflow: 'hidden', + WebkitLineClamp: '2', + }, + '.ss__result__add-to-cart-wrapper': { + marginTop: '2.5px', + }, + }; + + // compact grid styles + const gridStyles = { + '.ss__result__details': { + ...sharedStyles, + }, + }; + + // compact list styles + const listStyles = { + '&': { + gap: `${custom.spacing.x2}px`, + }, + '.ss__result__image-wrapper': { + flex: imageWidth ? imageWidth : '', + }, + '.ss__result__details': { + '.ss__result__details__title, .ss__result__details__pricing': { + flex: '1 1 100%', + }, + ...sharedStyles, + '.ss__result__details__variant-selection .ss__variant-selection': { + width: '100%', + }, + }, + }; + + return layout == 'grid' ? gridStyles : listStyles; + }, + scrollbar: () => { + // scrollbar styles + return { + '&::-webkit-scrollbar': { + width: '8px', + height: '8px', + }, + '&::-webkit-scrollbar-track': { + backgroundColor: custom.colors.gray01, + }, + '&::-webkit-scrollbar-thumb': { + backgroundColor: custom.colors.gray02, + }, + }; + }, + srOnly: () => { + // screen reader only styles + return { + position: 'absolute', + width: '1px', + height: '1px', + padding: 0, + margin: '-1px', + overflow: 'hidden', + clip: 'rect(0, 0, 0, 0)', + }; + }, + textOverflow: () => { + // text overflow styles + return { + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap', + }; + }, + }, + utils: { + activeColors: (color?: string) => { + // get active color and related font color + color = color ? color : custom.colors.primary; + const whiteColor = new Color(custom.colors.white); + const blackColor = new Color(custom.colors.black); + const activeColor = new Color(color); + const accentColor = activeColor.isDark() || activeColor.hex().toLowerCase() == custom.colors.primary ? whiteColor : blackColor; + return [activeColor.hex().toLowerCase(), accentColor.hex().toLowerCase()]; + }, + darkenColor: (color?: string, amount?: number) => { + // darken a color + amount = amount ? amount : 0.075; + color = color ? color : custom.colors.gray02; + const darkColor = new Color(color).darken(amount).hex().toLowerCase(); + return darkColor; + }, + getBp: (bp: number, rule?: string) => { + // get breakpoint selector + rule = rule && (rule == 'min' || rule == 'max') ? rule : 'min'; + return `@media (${rule}-width: ${rule == 'min' ? bp + 1 : bp}px)`; + }, + lightenColor: (color?: string, amount?: number) => { + // lighten a color + amount = amount ? amount : 0.42; + color = color ? color : custom.colors.text; + const lightColor = new Color(color).lighten(amount).hex().toLowerCase(); + return lightColor; + }, + }, +}; + +// types for custom theme object +type ObjectAnyType = { + [key: string]: any; +}; + +type ObjectIconType = { + [key: string]: IconType; +}; + +type ObjectNestedType = { + [key: string]: ObjectNumberOrStringType | ObjectNestedType; +}; + +type ObjectNumberType = { + [key: string]: number; +}; + +type ObjectNumberOrStringType = { + [key: string]: number | string; +}; + +type ObjectStringType = { + [key: string]: string; +}; + +type CustomThemeType = { + breakpoints: ObjectNumberType; + colors: ObjectStringType; + fonts: ObjectAnyType; + icons: ObjectIconType; + sizes: ObjectNumberType; + spacing: ObjectNumberType; + styles: { + activeText: (color?: string) => ObjectNestedType; + badgeText: (fontSize: number) => ObjectNumberOrStringType; + borderRadius: (value?: number, unit?: string) => ObjectStringType | null; + box: (color?: string, padding?: number | string, radius?: boolean) => ObjectNumberOrStringType; + boxSizing: (component: string, treePath?: string, name?: string) => ObjectNestedType | null; + disabled: () => ObjectNumberOrStringType | ObjectNestedType; + headerText: (color?: string, fontSize?: string) => ObjectNumberOrStringType; + resultCompact: (layout?: string, imageWidth?: string, fontSize?: number) => ObjectNumberOrStringType | ObjectNestedType; + scrollbar: () => ObjectNestedType; + srOnly: () => ObjectNumberOrStringType; + textOverflow: () => ObjectNumberOrStringType; + }; + utils: { + activeColors: (color?: string) => string[]; + darkenColor: (color?: string, amount?: number) => string; + getBp: (bp: number, rule?: string) => string; + lightenColor: (color?: string, amount?: number) => string; + }; +}; diff --git a/packages/snap-preact/components/src/themes/pike/pike.ts b/packages/snap-preact/components/src/themes/pike/pike.ts new file mode 100644 index 000000000..cf08d19a7 --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/pike.ts @@ -0,0 +1,25 @@ +import { ThemeComplete, ThemeVariables } from '../../providers'; +import { components } from './components'; +import { responsive } from './responsive'; +import { custom } from './custom'; + +const pikeVariables: ThemeVariables = { + breakpoints: { + mobile: custom.breakpoints.mobile, + tablet: custom.breakpoints.tablet, + desktop: custom.breakpoints.desktop, + }, + colors: { + text: custom.colors.text, + primary: custom.colors.primary, + secondary: custom.colors.secondary, + accent: custom.colors.accent, + }, +}; + +export const pike: ThemeComplete = { + name: 'pike', + variables: pikeVariables, + components, + responsive, +}; diff --git a/packages/snap-preact/components/src/themes/pike/responsive.ts b/packages/snap-preact/components/src/themes/pike/responsive.ts new file mode 100644 index 000000000..61ae08bfe --- /dev/null +++ b/packages/snap-preact/components/src/themes/pike/responsive.ts @@ -0,0 +1,8 @@ +import { ThemeResponsive } from '../../providers/theme'; +import { mobileComponents, tabletComponents, desktopComponents } from './components'; + +export const responsive: ThemeResponsive = { + mobile: mobileComponents, + tablet: tabletComponents, + desktop: desktopComponents, +}; diff --git a/packages/snap-preact/components/src/themes/snapnco/components/molecules/checkbox.ts b/packages/snap-preact/components/src/themes/snapnco/components/molecules/checkbox.ts index ffd9898a5..85d07d096 100644 --- a/packages/snap-preact/components/src/themes/snapnco/components/molecules/checkbox.ts +++ b/packages/snap-preact/components/src/themes/snapnco/components/molecules/checkbox.ts @@ -6,7 +6,7 @@ import { ThemeComponent } from '../../../../providers'; // CSS in JS style script for the Checkbox component const checkboxStyleScript = ({ color, theme }: CheckboxProps) => { const variables = theme?.variables; - const backgroundColorObj = new Color(color || variables?.colors.primary); + const backgroundColorObj = new Color(color || variables?.colors.primary || undefined); const backgroundTextColorObj = backgroundColorObj.isDark() ? new Color('#fff') : new Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/snapnco/components/molecules/facetGridOptions.ts b/packages/snap-preact/components/src/themes/snapnco/components/molecules/facetGridOptions.ts index dab389417..58f32f712 100644 --- a/packages/snap-preact/components/src/themes/snapnco/components/molecules/facetGridOptions.ts +++ b/packages/snap-preact/components/src/themes/snapnco/components/molecules/facetGridOptions.ts @@ -6,7 +6,7 @@ import { ThemeComponent } from '../../../../providers'; // CSS in JS style script for the FacetGridOptions component const facetGridOptionsStyleScript = ({ theme }: FacetGridOptionsProps) => { const variables = theme?.variables; - const backgroundColorObj = new Color(variables?.colors.primary); + const backgroundColorObj = new Color(variables?.colors.primary || undefined); const colorObj = backgroundColorObj.isDark() ? new Color('#fff') : new Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/snapnco/components/molecules/loadMore.ts b/packages/snap-preact/components/src/themes/snapnco/components/molecules/loadMore.ts index 4b3d911f7..c7424eab7 100644 --- a/packages/snap-preact/components/src/themes/snapnco/components/molecules/loadMore.ts +++ b/packages/snap-preact/components/src/themes/snapnco/components/molecules/loadMore.ts @@ -7,7 +7,7 @@ import { ThemeComponent } from '../../../../providers'; const loadMoreStyleScript = ({ color, backgroundColor, theme }: LoadMoreProps) => { const variables = theme?.variables; - const barColour = new Color(color || variables?.colors.accent); + const barColour = new Color(color || variables?.colors.accent || undefined); const backgroundColour = backgroundColor ? new Color(backgroundColor) : barColour.lightness(90); return css({ diff --git a/packages/snap-preact/components/src/themes/snapnco/components/molecules/select.ts b/packages/snap-preact/components/src/themes/snapnco/components/molecules/select.ts index 7541ff95b..04bb584c5 100644 --- a/packages/snap-preact/components/src/themes/snapnco/components/molecules/select.ts +++ b/packages/snap-preact/components/src/themes/snapnco/components/molecules/select.ts @@ -5,7 +5,7 @@ import { ThemeComponent } from '../../../../providers'; // CSS in JS style script for the Select component const selectStyleScript = ({ backgroundColor, theme }: SelectProps) => { const variables = theme?.variables; - const transparentSecondary = new Color(theme?.variables?.colors?.secondary).opaquer(0.2); + const transparentSecondary = new Color(theme?.variables?.colors?.secondary || undefined).opaquer(0.2); return css({ '.ss__dropdown': { '.ss__select__dropdown__button': { diff --git a/packages/snap-preact/components/src/themes/snapnco/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/snapnco/components/organisms/autocomplete.ts new file mode 100644 index 000000000..abeed134d --- /dev/null +++ b/packages/snap-preact/components/src/themes/snapnco/components/organisms/autocomplete.ts @@ -0,0 +1,22 @@ +import { css } from '@emotion/react'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; + +// CSS in JS style script for the Search component +const autocompleteStyleScript = ({}: AutocompleteProps) => { + return css({}); +}; + +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + ...(autocompleteThemeComponentProps.default?.['autocomplete'] || {}), + themeStyleScript: autocompleteStyleScript, + }, + }, + mobile: autocompleteThemeComponentProps.mobile, + desktop: autocompleteThemeComponentProps.desktop, + tablet: autocompleteThemeComponentProps.tablet, +}; diff --git a/packages/snap-preact/components/src/themes/snapnco/components/organisms/index.ts b/packages/snap-preact/components/src/themes/snapnco/components/organisms/index.ts index 257776ad6..598caab61 100644 --- a/packages/snap-preact/components/src/themes/snapnco/components/organisms/index.ts +++ b/packages/snap-preact/components/src/themes/snapnco/components/organisms/index.ts @@ -9,9 +9,11 @@ import { noResults } from './noResults'; import { sidebar } from './sidebar'; import { termsList } from './termsList'; import { toolbar } from './toolbar'; +import { autocomplete } from './autocomplete'; export const organisms: ThemeResponsiveComplete = { default: { + ...autocomplete.default, ...facet.default, ...facetsHorizontal.default, ...filterSummary.default, @@ -22,6 +24,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.default, }, mobile: { + ...autocomplete.mobile, ...facet.mobile, ...facetsHorizontal.mobile, ...filterSummary.mobile, @@ -32,6 +35,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.mobile, }, tablet: { + ...autocomplete.tablet, ...facet.tablet, ...facetsHorizontal.tablet, ...filterSummary.tablet, @@ -42,6 +46,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.tablet, }, desktop: { + ...autocomplete.desktop, ...facet.desktop, ...facetsHorizontal.desktop, ...filterSummary.desktop, diff --git a/packages/snap-preact/components/src/themes/snappy/components/molecules/checkbox.ts b/packages/snap-preact/components/src/themes/snappy/components/molecules/checkbox.ts index 070279010..eacea5145 100644 --- a/packages/snap-preact/components/src/themes/snappy/components/molecules/checkbox.ts +++ b/packages/snap-preact/components/src/themes/snappy/components/molecules/checkbox.ts @@ -5,7 +5,7 @@ import { ThemeComponent } from '../../../../providers'; // CSS in JS style script for the Checkbox component const checkboxStyleScript = ({ color, theme }: CheckboxProps) => { const variables = theme?.variables; - const backgroundColorObj = new Color(color || variables?.colors.primary); + const backgroundColorObj = new Color(color || variables?.colors.primary || undefined); const backgroundTextColorObj = backgroundColorObj.isDark() ? new Color('#fff') : new Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/snappy/components/molecules/facetGridOptions.ts b/packages/snap-preact/components/src/themes/snappy/components/molecules/facetGridOptions.ts index 02931aac1..614656f38 100644 --- a/packages/snap-preact/components/src/themes/snappy/components/molecules/facetGridOptions.ts +++ b/packages/snap-preact/components/src/themes/snappy/components/molecules/facetGridOptions.ts @@ -5,7 +5,7 @@ import { ThemeComponent } from '../../../../providers'; // CSS in JS style script for the FacetGridOptions component const facetGridOptionsStyleScript = ({ theme }: FacetGridOptionsProps) => { const variables = theme?.variables; - const backgroundColorObj = new Color(variables?.colors.primary); + const backgroundColorObj = new Color(variables?.colors.primary || undefined); const colorObj = backgroundColorObj.isDark() ? new Color('#fff') : new Color('#000'); return css({ diff --git a/packages/snap-preact/components/src/themes/snappy/components/molecules/loadMore.ts b/packages/snap-preact/components/src/themes/snappy/components/molecules/loadMore.ts index d8b6ac091..806306731 100644 --- a/packages/snap-preact/components/src/themes/snappy/components/molecules/loadMore.ts +++ b/packages/snap-preact/components/src/themes/snappy/components/molecules/loadMore.ts @@ -6,8 +6,8 @@ import { ThemeComponent } from '../../../../providers'; const loadMoreStyleScript = ({ color, backgroundColor, theme }: LoadMoreProps) => { const variables = theme?.variables; - const barColour = new Color(color || variables?.colors.accent); - const backgroundColour = backgroundColor ? new Color(backgroundColor) : barColour.lightness(90); + const barColour = new Color(color || variables?.colors.accent || undefined); + const backgroundColour = backgroundColor ? new Color(backgroundColor || undefined) : barColour.lightness(90); return css({ '.ss__button': { diff --git a/packages/snap-preact/components/src/themes/snappy/components/molecules/select.ts b/packages/snap-preact/components/src/themes/snappy/components/molecules/select.ts index 7541ff95b..04bb584c5 100644 --- a/packages/snap-preact/components/src/themes/snappy/components/molecules/select.ts +++ b/packages/snap-preact/components/src/themes/snappy/components/molecules/select.ts @@ -5,7 +5,7 @@ import { ThemeComponent } from '../../../../providers'; // CSS in JS style script for the Select component const selectStyleScript = ({ backgroundColor, theme }: SelectProps) => { const variables = theme?.variables; - const transparentSecondary = new Color(theme?.variables?.colors?.secondary).opaquer(0.2); + const transparentSecondary = new Color(theme?.variables?.colors?.secondary || undefined).opaquer(0.2); return css({ '.ss__dropdown': { '.ss__select__dropdown__button': { diff --git a/packages/snap-preact/components/src/themes/snappy/components/organisms/autocomplete.ts b/packages/snap-preact/components/src/themes/snappy/components/organisms/autocomplete.ts new file mode 100644 index 000000000..abeed134d --- /dev/null +++ b/packages/snap-preact/components/src/themes/snappy/components/organisms/autocomplete.ts @@ -0,0 +1,22 @@ +import { css } from '@emotion/react'; +import { autocompleteThemeComponentProps } from '../../../themeComponents/autocomplete'; +import { ThemeComponent } from '../../../../providers'; +import { AutocompleteProps } from '../../../../components/Organisms/Autocomplete'; + +// CSS in JS style script for the Search component +const autocompleteStyleScript = ({}: AutocompleteProps) => { + return css({}); +}; + +export const autocomplete: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + ...autocompleteThemeComponentProps.default, + autocomplete: { + ...(autocompleteThemeComponentProps.default?.['autocomplete'] || {}), + themeStyleScript: autocompleteStyleScript, + }, + }, + mobile: autocompleteThemeComponentProps.mobile, + desktop: autocompleteThemeComponentProps.desktop, + tablet: autocompleteThemeComponentProps.tablet, +}; diff --git a/packages/snap-preact/components/src/themes/snappy/components/organisms/index.ts b/packages/snap-preact/components/src/themes/snappy/components/organisms/index.ts index 257776ad6..598caab61 100644 --- a/packages/snap-preact/components/src/themes/snappy/components/organisms/index.ts +++ b/packages/snap-preact/components/src/themes/snappy/components/organisms/index.ts @@ -9,9 +9,11 @@ import { noResults } from './noResults'; import { sidebar } from './sidebar'; import { termsList } from './termsList'; import { toolbar } from './toolbar'; +import { autocomplete } from './autocomplete'; export const organisms: ThemeResponsiveComplete = { default: { + ...autocomplete.default, ...facet.default, ...facetsHorizontal.default, ...filterSummary.default, @@ -22,6 +24,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.default, }, mobile: { + ...autocomplete.mobile, ...facet.mobile, ...facetsHorizontal.mobile, ...filterSummary.mobile, @@ -32,6 +35,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.mobile, }, tablet: { + ...autocomplete.tablet, ...facet.tablet, ...facetsHorizontal.tablet, ...filterSummary.tablet, @@ -42,6 +46,7 @@ export const organisms: ThemeResponsiveComplete = { ...termsList.tablet, }, desktop: { + ...autocomplete.desktop, ...facet.desktop, ...facetsHorizontal.desktop, ...filterSummary.desktop, diff --git a/packages/snap-preact/components/src/themes/themeComponents/autocomplete.ts b/packages/snap-preact/components/src/themes/themeComponents/autocomplete.ts new file mode 100644 index 000000000..8ff55834d --- /dev/null +++ b/packages/snap-preact/components/src/themes/themeComponents/autocomplete.ts @@ -0,0 +1,76 @@ +import { AutocompleteProps } from '../../components/Organisms/Autocomplete'; +import { ThemeComponent } from '../../providers'; + +export const autocompleteThemeComponentProps: ThemeComponent<'autocomplete', AutocompleteProps> = { + default: { + 'autocomplete facet': { + // valueProps, + previewOnFocus: true, + limit: 6, + disableOverflow: true, + disableCollapse: true, + searchable: false, + showClearAllText: false, + showSelectedCount: false, + rangeInputs: false, + }, + 'autocomplete facetGridOptions': { + // onClick: facetClickEvent, + columns: 3, + }, + 'autocomplete facetHierarchyOptions': { + // onClick: facetClickEvent, + hideCount: true, + }, + 'autocomplete facetListOptions': { + // onClick: facetClickEvent, + hideCheckbox: true, + hideCount: true, + }, + 'autocomplete facetPaletteOptions': { + // onClick: facetClickEvent, + hideLabel: true, + columns: 3, + }, + 'autocomplete result': { + hideBadge: true, + hideVariantSelections: true, + }, + 'autocomplete recommendationGrid': { + columns: 4, + rows: 2, + }, + }, + mobile: { + 'autocomplete results': { + columns: 2, + rows: 1, + }, + + 'autocomplete recommendationGrid': { + columns: 2, + rows: 1, + }, + 'autocomplete searchInput': { + closeSearchButton: { + icon: 'angle-left', + }, + }, + }, + tablet: { + 'autocomplete results': { + columns: 3, + rows: 1, + }, + }, + desktop: { + 'autocomplete results': { + columns: 2, + rows: 2, + }, + 'autocomplete recommendationGrid': { + columns: 3, + rows: 2, + }, + }, +}; diff --git a/packages/snap-preact/components/src/themes/themeComponents/autocompleteFixed.ts b/packages/snap-preact/components/src/themes/themeComponents/autocompleteFixed.ts index 0ff70fee5..efd56ea00 100644 --- a/packages/snap-preact/components/src/themes/themeComponents/autocompleteFixed.ts +++ b/packages/snap-preact/components/src/themes/themeComponents/autocompleteFixed.ts @@ -10,6 +10,9 @@ export const autocompleteFixedThemeComponentProps: ThemeComponent<'autocompleteF disableOverflow: true, disableCollapse: true, searchable: false, + showClearAllText: false, + showSelectedCount: false, + rangeInputs: false, }, 'autocompleteFixed facetGridOptions': { // onClick: facetClickEvent, @@ -40,11 +43,7 @@ export const autocompleteFixedThemeComponentProps: ThemeComponent<'autocompleteF }, mobile: { autocompleteFixed: { - layout: [['c1']], - column1: { - layout: [['termsList'], ['content'], ['_', 'button.see-more']], - width: '100%', - }, + layout: 'mini', }, 'autocompleteFixed results': { columns: 2, diff --git a/packages/snap-preact/components/src/themes/themeComponents/autocompleteModal.ts b/packages/snap-preact/components/src/themes/themeComponents/autocompleteModal.ts index 6249316d3..599124e1b 100644 --- a/packages/snap-preact/components/src/themes/themeComponents/autocompleteModal.ts +++ b/packages/snap-preact/components/src/themes/themeComponents/autocompleteModal.ts @@ -10,6 +10,9 @@ export const autocompleteModalThemeComponentProps: ThemeComponent<'autocompleteM disableOverflow: true, disableCollapse: true, searchable: false, + showClearAllText: false, + showSelectedCount: false, + rangeInputs: false, }, 'autocompleteModal facetGridOptions': { // onClick: facetClickEvent, @@ -40,11 +43,7 @@ export const autocompleteModalThemeComponentProps: ThemeComponent<'autocompleteM }, mobile: { autocompleteModal: { - layout: [['c1']], - column1: { - layout: [['termsList'], ['content'], ['_', 'button.see-more']], - width: '100%', - }, + layout: 'mini', }, 'autocompleteModal results': { columns: 2, diff --git a/packages/snap-preact/components/src/themes/themeComponents/autocompleteSlideout.ts b/packages/snap-preact/components/src/themes/themeComponents/autocompleteSlideout.ts index 4a98292b8..a68fd8b95 100644 --- a/packages/snap-preact/components/src/themes/themeComponents/autocompleteSlideout.ts +++ b/packages/snap-preact/components/src/themes/themeComponents/autocompleteSlideout.ts @@ -14,6 +14,9 @@ export const autocompleteSlideoutThemeComponentProps: ThemeComponent<'autocomple disableOverflow: true, disableCollapse: true, searchable: false, + showClearAllText: false, + showSelectedCount: false, + rangeInputs: false, }, 'autocompleteSlideout facetGridOptions': { // onClick: facetClickEvent, @@ -44,11 +47,7 @@ export const autocompleteSlideoutThemeComponentProps: ThemeComponent<'autocomple }, mobile: { autocompleteSlideout: { - layout: [['c1']], - column1: { - layout: [['button.see-more'], ['termsList'], ['content']], - width: '100%', - }, + layout: 'mini', }, 'autocompleteSlideout recommendationGrid': { columns: 2, diff --git a/packages/snap-preact/components/src/themes/themeComponents/searchHorizontal.ts b/packages/snap-preact/components/src/themes/themeComponents/searchHorizontal.ts index 68113cf6d..16fd5a361 100644 --- a/packages/snap-preact/components/src/themes/themeComponents/searchHorizontal.ts +++ b/packages/snap-preact/components/src/themes/themeComponents/searchHorizontal.ts @@ -5,25 +5,27 @@ export const searchHorizontalThemeComponentProps: ThemeComponent<'searchHorizont default: { searchHorizontal: { hideSidebar: true, - internalClassName: 'ss__search-horizontal', }, 'searchHorizontal toolbar.top': { - layout: [['banner.header'], ['searchHeader'], ['banner.banner'], ['filterSummary'], ['paginationInfo', '_', 'sortBy', 'perPage']], + layout: [['searchHeader'], ['banner.header']], }, 'searchHorizontal toolbar.middle': { - layout: ['facetsHorizontal'], + layout: [['filterSummary'], ['facetsHorizontal'], ['paginationInfo', '_', 'sortBy', 'perPage'], ['banner.banner']], }, 'searchHorizontal toolbar.bottom': { - layout: [['banner.footer'], ['_', 'pagination']], + layout: [['banner.footer'], ['_', 'pagination', '_']], }, 'searchHorizontal facetsHorizontal': { limit: 9, }, + 'searchHorizontal mobileSidebar': { + layout: ['filterSummary', 'facets', 'banner.left'], + }, }, mobile: { - 'searchHorizontal toolbar.top': { - layout: [['banner.header'], ['searchHeader'], ['banner.banner'], ['paginationInfo', '_'], ['filterSummary'], ['_', 'sortBy', 'perPage']], + 'searchHorizontal toolbar.middle': { + layout: [['paginationInfo', '_', 'mobileSidebar'], ['sortBy', 'perPage'], ['banner.banner']], }, 'searchHorizontal facetsHorizontal': { limit: 4, diff --git a/packages/snap-preact/components/src/utilities/mergeProps.ts b/packages/snap-preact/components/src/utilities/mergeProps.ts index ad0ef47dc..849e338d6 100644 --- a/packages/snap-preact/components/src/utilities/mergeProps.ts +++ b/packages/snap-preact/components/src/utilities/mergeProps.ts @@ -107,11 +107,12 @@ export function mergeProps( mergedProps.theme.variables = globalTheme.variables; } - //if custom component, re-spread props again - if (treePath && treePath.indexOf('customComponent') > -1) { + // if custom component, re-spread props again + if (treePath && (treePath.indexOf('customComponent') > -1 || treePath.startsWith('storybook'))) { mergedProps = { ...mergedProps, ...props, + treePath, }; } } diff --git a/packages/snap-preact/components/src/utilities/snapify.ts b/packages/snap-preact/components/src/utilities/snapify.ts index 94030428c..583bd9981 100644 --- a/packages/snap-preact/components/src/utilities/snapify.ts +++ b/packages/snap-preact/components/src/utilities/snapify.ts @@ -27,7 +27,7 @@ const controllers: { } = {}; const client = { - globals: { siteId: '8uyt2m' }, + globals: { siteId: 'atkzs2' }, }; export class Snapify { diff --git a/packages/snap-preact/components/tests/cypress/component/molecules/swatches.cy.tsx b/packages/snap-preact/components/tests/cypress/component/molecules/swatches.cy.tsx index 5b22fea65..ca63b815f 100644 --- a/packages/snap-preact/components/tests/cypress/component/molecules/swatches.cy.tsx +++ b/packages/snap-preact/components/tests/cypress/component/molecules/swatches.cy.tsx @@ -287,7 +287,7 @@ describe('Swatches Component', async () => { cy.get('.ss__swatches__grid').should('exist'); cy.get('.ss__grid__option').should('have.length', defaultColumns); - cy.get('.ss__grid__option').should('satisfy', ($el) => { + cy.get('.ss__grid__option .ss__grid__option__inner').should('satisfy', ($el) => { for (let i = 0; i < $el.length; i++) { const backgroundStyle = $el[i].style.background; return backgroundStyle == options[i].value.toLowerCase(); @@ -313,7 +313,7 @@ describe('Swatches Component', async () => { cy.get('.ss__slideshow__next').should('not.exist'); cy.get('.ss__swatches__grid').should('exist'); cy.get('.ss__grid__option').should('have.length', defaultColumns); - cy.get('.ss__grid__option--selected') + cy.get('.ss__grid__option--selected .ss__grid__option__inner') .should('exist') .should('satisfy', ($el) => { const backgroundStyle = $el[0].style.background; diff --git a/packages/snap-preact/src/Templates/Stores/LibraryStore.ts b/packages/snap-preact/src/Templates/Stores/LibraryStore.ts index d33cbf7b3..b651f7252 100644 --- a/packages/snap-preact/src/Templates/Stores/LibraryStore.ts +++ b/packages/snap-preact/src/Templates/Stores/LibraryStore.ts @@ -28,9 +28,12 @@ type LibraryComponentMap = { export type LibraryImports = { theme: { base: (args?: any) => Promise; - bocachica: (args?: any) => Promise; - snappy: (args?: any) => Promise; - snapnco: (args?: any) => Promise; + // bocachica: (args?: any) => Promise; + // everest: (args?: any) => Promise; + // matterhorn: (args?: any) => Promise; + pike: (args?: any) => Promise; + // snapnco: (args?: any) => Promise; + // snappy: (args?: any) => Promise; }; plugins: { shopify: { @@ -147,15 +150,24 @@ export class LibraryStore { base: async () => { return this.themes.base || (this.themes.base = (await import('./library/themes/base')).base); }, - bocachica: async () => { - return this.themes.bocachica || (this.themes.bocachica = (await import('./library/themes/bocachica')).bocachica); - }, - snappy: async () => { - return this.themes.snappy || (this.themes.snappy = (await import('./library/themes/snappy')).snappy); - }, - snapnco: async () => { - return this.themes.snapnco || (this.themes.snapnco = (await import('./library/themes/snapnco')).snapnco); + // bocachica: async () => { + // return this.themes.bocachica || (this.themes.bocachica = (await import('./library/themes/bocachica')).bocachica); + // }, + // everest: async () => { + // return this.themes.everest || (this.themes.everest = (await import('../../../components/src/themes/everest/everest')).everest); + // }, + // matterhorn: async () => { + // return this.themes.matterhorn || (this.themes.matterhorn = (await import('../../../components/src/themes/matterhorn/matterhorn')).matterhorn); + // }, + pike: async () => { + return this.themes.pike || (this.themes.pike = (await import('../../../components/src/themes/pike/pike')).pike); }, + // snapnco: async () => { + // return this.themes.snapnco || (this.themes.snapnco = (await import('./library/themes/snapnco')).snapnco); + // }, + // snappy: async () => { + // return this.themes.snappy || (this.themes.snappy = (await import('./library/themes/snappy')).snappy); + // }, }, plugins: { shopify: { diff --git a/packages/snap-preact/src/Templates/Stores/TemplatesStore.test.ts b/packages/snap-preact/src/Templates/Stores/TemplatesStore.test.ts index 13fb4463c..377f8ac9c 100644 --- a/packages/snap-preact/src/Templates/Stores/TemplatesStore.test.ts +++ b/packages/snap-preact/src/Templates/Stores/TemplatesStore.test.ts @@ -9,7 +9,7 @@ describe('TemplateStore', () => { platform: 'other', }, theme: { - extends: 'bocachica', + extends: 'base', }, }; const store = new TemplatesStore({ config }); @@ -24,7 +24,7 @@ describe('TemplateStore', () => { it('can define config', () => { const config: SnapTemplatesConfig = { theme: { - extends: 'bocachica', + extends: 'base', }, config: { siteId: '8uyt2m', @@ -42,7 +42,7 @@ describe('TemplateStore', () => { it("fallsback if language and currency doesn't exist", () => { const config: SnapTemplatesConfig = { theme: { - extends: 'bocachica', + extends: 'base', }, config: { siteId: '8uyt2m', @@ -61,7 +61,7 @@ describe('TemplateStore', () => { it('can change language and currency', async () => { const config: SnapTemplatesConfig = { theme: { - extends: 'bocachica', + extends: 'base', }, config: { siteId: '8uyt2m', @@ -82,7 +82,7 @@ describe('TemplateStore', () => { it('can change innerWidth', () => { const config: SnapTemplatesConfig = { theme: { - extends: 'bocachica', + extends: 'base', }, config: { siteId: '8uyt2m', @@ -106,7 +106,7 @@ describe('TemplateStore', () => { platform: 'other', }, theme: { - extends: 'bocachica', + extends: 'pike', }, }; const store = new TemplatesStore({ config }); @@ -129,7 +129,7 @@ describe('TemplateStore', () => { spy.mockClear(); // addTheme manual call - const base = await store.library.import.theme.bocachica(); + const base = await store.library.import.theme.base(); const customTheme = 'customTheme'; store.addTheme({ @@ -149,7 +149,7 @@ describe('TemplateStore', () => { const newTheme = store.getThemeStore(customTheme); expect(newTheme?.name).toBe(customTheme); // @ts-ignore - private property - expect(newTheme.base.name).toBe('bocachica'); + expect(newTheme.base.name).toBe('base'); }); it('can addTarget', async () => { @@ -159,7 +159,7 @@ describe('TemplateStore', () => { platform: 'other', }, theme: { - extends: 'bocachica', + extends: 'base', }, }; const store = new TemplatesStore({ config }); diff --git a/packages/snap-preact/src/Templates/Stores/ThemeStore.tsx b/packages/snap-preact/src/Templates/Stores/ThemeStore.tsx index f85973314..b381c61b7 100644 --- a/packages/snap-preact/src/Templates/Stores/ThemeStore.tsx +++ b/packages/snap-preact/src/Templates/Stores/ThemeStore.tsx @@ -297,6 +297,12 @@ function prefixComponentKeys(prefix: string, components?: ThemeComponents): Them if (components) { Object.keys(components).forEach((key) => { + //does the key already have the prefix? - this is needed when using the editor. + if (key.indexOf(prefix) === 0) { + newComponents[key as keyof typeof newComponents] = components![key as keyof typeof components]; + return; + } + // add the prefix to the key newComponents[`${prefix}${key}` as keyof typeof newComponents] = components![key as keyof typeof components]; }); }