Created
May 6, 2020 17:02
-
-
Save klauskohut/af22c7da47f62dd47ea5fc7c9aebbd50 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| master page mutation: | |
| mutation updateMasterPage($id: ID!, $masterPage: UpdateMasterPage!) { | |
| updateMasterPage(id: $id, masterPage: $masterPage) { | |
| id | |
| name | |
| __typename | |
| } | |
| } | |
| master page variables: | |
| { | |
| "id": "b06cfee8-5194-40dd-9200-936eaa741d58", | |
| "masterPage": { | |
| "name": "Products", | |
| "compositions": [ | |
| { | |
| "query": "", | |
| "componentID": "4d133f25-2955-41c5-8107-ebef23014929", | |
| "breadcrumbs": [], | |
| "id": "14efd78a-46c5-4071-9c23-c36dfe165422" | |
| }, | |
| { | |
| "query": " query ProductStickyAddToCartQuery($cmsEntryID: ID!) { selector : cmsEntryStringField ( id:\"20f53e61-32a5-42aa-9d9b-e1bfbe066463\",cmsFieldID:\"2e4322f1-2a97-4ff6-9311-6e8385a235c8\" ) ,variantId : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"7cb5a6cd-32af-4012-8806-b65fef1890d8\" ) }", | |
| "componentID": "8307f5b6-16a1-4217-a312-296919023e5b", | |
| "breadcrumbs": [ | |
| { | |
| "componentFieldID": "2e4322f1-2a97-4ff6-9311-6e8385a235c8", | |
| "trails": [ | |
| { | |
| "entityID": "20f53e61-32a5-42aa-9d9b-e1bfbe066463", | |
| "entityType": "cmsEntry", | |
| "entityValue": "ProductBox" | |
| }, | |
| { | |
| "entityID": "2e4322f1-2a97-4ff6-9311-6e8385a235c8", | |
| "entityType": "cmsField", | |
| "entityValue": "selector" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "39b960b3-9ead-4147-ac5e-dba4e501f683", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "7cb5a6cd-32af-4012-8806-b65fef1890d8", | |
| "entityType": "cmsField", | |
| "entityValue": "storefrontID" | |
| } | |
| ] | |
| } | |
| ], | |
| "id": "434d8cf2-8905-42c7-81b8-4ad7bcb3e87a" | |
| }, | |
| { | |
| "query": " query ProductBoxQuery($cmsEntryID: ID!) { faq : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"412d0787-a25b-4f97-a4b0-ab9931bc7c8d\" ) ,productName : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"b3f08edf-4bcf-475a-bc8c-3568e0249d10\" ) ,tags : cmsEntryStringArray ( id:$cmsEntryID ,cmsFieldID:\"74d8a4b0-eaeb-4513-bf69-1ec8bec18de6\" ) ,images : cmsEntryReferenceObjectArray ( id:$cmsEntryID ,cmsFieldID:\"49233aba-9baa-4c9b-a78a-700167951f7b\" ) ,description : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"b8f6fda6-5f9b-456e-8d8c-724cf620d5d6\" ) ,info : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"4147395b-646b-4c64-b569-8783ac3d163b\" ) ,variants : cmsEntryReferenceObjectArray ( id:$cmsEntryID ,cmsFieldID:\"bdc84199-08ea-431a-9254-2b29b51887b0\" ) }", | |
| "componentID": "9c40a0f8-a7b5-4224-947e-1be7fd3305e9", | |
| "breadcrumbs": [ | |
| { | |
| "componentFieldID": "ffc3e6f6-72cb-48a3-a069-cfe4109c60a2", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "b3f08edf-4bcf-475a-bc8c-3568e0249d10", | |
| "entityType": "cmsField", | |
| "entityValue": "name" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "532ed937-f99b-4d33-a807-869e43d5e740", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "74d8a4b0-eaeb-4513-bf69-1ec8bec18de6", | |
| "entityType": "cmsField", | |
| "entityValue": "tags" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "ea09ca9a-d337-4e9d-bc27-93e5c91b2d62", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "49233aba-9baa-4c9b-a78a-700167951f7b", | |
| "entityType": "cmsField", | |
| "entityValue": "images" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "d55dfe65-3a2d-472a-b4ee-d5bad25c6695", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "412d0787-a25b-4f97-a4b0-ab9931bc7c8d", | |
| "entityType": "cmsField", | |
| "entityValue": "FAQ" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "7424d587-8acd-4e1e-9fdd-1cc0ddcfdd4d", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "b8f6fda6-5f9b-456e-8d8c-724cf620d5d6", | |
| "entityType": "cmsField", | |
| "entityValue": "AccordeonDescription" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "df5b09cb-5310-4727-bc94-47e71fd296bd", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "4147395b-646b-4c64-b569-8783ac3d163b", | |
| "entityType": "cmsField", | |
| "entityValue": "Info" | |
| } | |
| ] | |
| }, | |
| { | |
| "componentFieldID": "34d7f953-db6d-45f7-9ebd-67a33497d7a9", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products" | |
| }, | |
| { | |
| "entityID": "bdc84199-08ea-431a-9254-2b29b51887b0", | |
| "entityType": "cmsField", | |
| "entityValue": "variants" | |
| } | |
| ] | |
| } | |
| ], | |
| "id": "bf2d7479-b5b6-4506-86ce-993b3a54c0ed" | |
| }, | |
| { | |
| "query": "", | |
| "componentID": "bd92b602-7d81-4544-bad3-56dc53dbb8b8", | |
| "breadcrumbs": [], | |
| "id": "5e7bdc44-ef44-4f8a-9d38-469d5f6637d7" | |
| }, | |
| { | |
| "query": "", | |
| "componentID": "645fc079-bad0-4f95-9076-bfb8cc076172", | |
| "breadcrumbs": [], | |
| "id": "b947e597-e901-45ad-bf81-153a29742ece" | |
| } | |
| ], | |
| "cmsModelID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8" | |
| } | |
| } | |
| -------------------------------------------------------------------------------------------------- | |
| page query: | |
| query Page($id: ID!) { | |
| page(id: $id) { | |
| id | |
| path | |
| displayName | |
| masterPageID | |
| compositions { | |
| id | |
| query | |
| type | |
| masterPageCompositionID | |
| pageVersionID | |
| directives | |
| breadcrumbs { | |
| componentFieldID | |
| trails { | |
| entityID | |
| entityType | |
| entityValue | |
| __typename | |
| } | |
| __typename | |
| } | |
| component { | |
| id | |
| name | |
| code | |
| style | |
| fields { | |
| id | |
| name | |
| placeholder | |
| required | |
| type | |
| system | |
| visible | |
| cmsModelID | |
| options { | |
| itemType | |
| referencedCmsModelID | |
| __typename | |
| } | |
| localized | |
| createdAt | |
| updatedAt | |
| __typename | |
| } | |
| currentVersionID | |
| createdAt | |
| updatedAt | |
| __typename | |
| } | |
| __typename | |
| } | |
| __typename | |
| } | |
| site: currentSite { | |
| ...LivePreviewSiteFragment | |
| __typename | |
| } | |
| components { | |
| name | |
| code | |
| style | |
| __typename | |
| } | |
| } | |
| fragment LivePreviewSiteFragment on Site { | |
| domain | |
| fonts { | |
| url | |
| name | |
| __typename | |
| } | |
| platform | |
| platformDomain | |
| platformStorefrontToken | |
| globalStyles | |
| searchAPIKey | |
| searchIndexes { | |
| name | |
| cmsModel { | |
| id | |
| name | |
| __typename | |
| } | |
| __typename | |
| } | |
| appDependencies { | |
| packageName | |
| version | |
| __typename | |
| } | |
| __typename | |
| } | |
| page variables: | |
| { | |
| "id": "12729fb3-385a-4630-be8c-5a5df0d076ec" | |
| } | |
| page response: | |
| { | |
| "page": { | |
| "id": "12729fb3-385a-4630-be8c-5a5df0d076ec", | |
| "path": "/products/rugged-case", | |
| "displayName": "Rugged Case", | |
| "masterPageID": "b06cfee8-5194-40dd-9200-936eaa741d58", | |
| "compositions": [ | |
| { | |
| "id": "048794d5-e72d-4d92-be8b-c183dcda4eba", | |
| "query": "", | |
| "type": "inherited", | |
| "masterPageCompositionID": "e9297fb6-5bee-4792-8326-01cc26704432", | |
| "pageVersionID": "5dff3968-18f5-4b89-9f21-6439e9ff3641", | |
| "directives": {}, | |
| "breadcrumbs": [], | |
| "component": { | |
| "id": "4d133f25-2955-41c5-8107-ebef23014929", | |
| "name": "Header", | |
| "code": "import React, { useState, useEffect, useRef } from 'react'\nimport cx from 'classnames'\nimport useWindowScroll from 'react-use/lib/useWindowScroll'\nimport { useCartActions } from 'frontend-checkout'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Link from 'frontend-link'\nimport Navbar from 'Components/Navbar'\nimport CartDrawer from 'Components/CartDrawer'\nimport PageWidth from 'Components/PageWidth'\nimport SearchBar from 'Components/SearchBar'\nimport Button from 'Components/Button'\nimport Icons from 'Components/Icons'\nimport './styles.css'\n\nconst featuredCollections = [\n {\n text: 'Black Horween',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/Horween_Black_-_Collection_Thumbnail_Image_-_02.jpg?v=1587068795',\n url: '/collections/black-collection',\n },\n {\n text: 'Rustic Brown Horween',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/Horween_Rustic_Brown_-_Collection_Thumbnail_Image_-_01.jpg?v=1587068796',\n url: '/collections/rustic-brown-collection',\n },\n {\n text: 'Wireless Power',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/Wireless_Power_-_Collection_Thumbnail_Image_-_01.jpg?v=1587068796',\n url: '/collections/power-wireless-chargin',\n },\n]\n\nconst featuredBlogPosts = [\n {\n text: 'COVID-19 | Our Response',\n imageUrl: 'https://cdn.shopify.com/s/files/1/0384/6721/files/Feature_-_01.jpg?v=1585157063',\n url: '/pages/medical-supplies',\n },\n {\n text: 'How to Office Anywhere',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/74435073_2568171996552528_430185643483200668_n.jpg?v=1584385603',\n url: '/blogs/the-nomadic/remote-work-tips',\n },\n {\n text: 'AirPods Pro Review | Our First Impressions',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/BSAW_AIRPODS_PRO_kraked.jpeg?56606',\n url: '/blogs/the-nomadic/airpods-pro-review',\n },\n]\n\nconst menu = [\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'AirPods Pro',\n url: '/collections/airpods-pro-collection',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'Airpods',\n url: '/collections/cases-airpods',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone 11 Pro Max',\n url: '/collections/cases-for-iphone-11-pro-max',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone 11 Pro',\n url: '/collections/cases-for-iphone-11-pro',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone 11',\n url: '/collections/cases-for-iphone-11',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone XS / XR',\n url: '/collections/new-2018-iphone-cases',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'Pixel Buds',\n url: '/collections/pixel-buds',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'Pixel 3 / 4',\n url: '/collections/pixel-4',\n },\n\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Wireless',\n url: '/collections/power-wireless-charging',\n },\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Tesla Model 3',\n url: '/products/tesla-charger',\n },\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Apple Watch',\n url: '/collections/power-apple-watch',\n },\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Battery Packs',\n url: '/collections/power-battery-packs',\n },\n\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'Lightning',\n url: '/collections/cables-lightning',\n },\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'Universal',\n url: '/collections/cables-universal',\n },\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'USB-C',\n url: '/collections/cables-usb-c',\n },\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'Micro USB',\n url: '/collections/cables-micro-usb',\n },\n\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Horween Leather',\n url: '/collections/straps-leather',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Active Leather',\n url: '/collections/active-leather-straps',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Metal Bands',\n url: '/collections/active-leather-straps',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Sport Straps',\n url: '/collections/straps-rugged-sport',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Slim Straps',\n url: '/collections/straps-slim',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Shell Cordovan',\n url: '/collections/straps-shell-cordovan',\n },\n\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Wallets',\n url: '/collections/wallets',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Passport Wallets',\n url: '/collections/passport-wallet',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Key Chains',\n url: '/collections/key-chains',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Mousepads',\n url: '/collections/mousepads',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Moment Lenses',\n url: '/collections/nomad-x-moment',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Wrist Strap',\n url: '/collections/wrist-strap',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Hats',\n url: '/collections/hats',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'New Products',\n url: '/collections/whatsnew',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Blackout Collection',\n url: '/collections/black',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Black Horween',\n url: '/collections/black-collection',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Rustic Brown Horween',\n url: '/collections/rustic-brown-collection',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Active Leather',\n url: '/collections/active-lifestyle',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Outlet Sale',\n url: '/collections/outletsale',\n },\n\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'New Products',\n url: '/collections/whatsnew',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Outlet Sale',\n url: '/collections/outletsale',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Free Cable',\n url: '/products/free-cable-for-the-planet',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Wallpapers',\n url: '/pages/wallpapers',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Zoom Backgrounds',\n url: '/pages/wallpapers',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Support',\n url: '/pages/support',\n },\n].reduce((acc, item) => {\n const doesSubmenuGroupExists = acc.find(group => group.text === item.group)\n if (!doesSubmenuGroupExists) {\n acc.push({\n text: item.group,\n url: item.collectionUrl,\n submenu: [],\n })\n }\n\n acc[acc.length - 1].submenu.push({\n text: item.text,\n url: item.url,\n })\n\n return acc\n}, [])\n\nconst HeaderSubmenu = ({ menuItem }) => {\n return (\n <div className=\"MenuDropdown-column\">\n <Link to={menuItem.url} className=\"MenuDropdown-column-header\">\n {menuItem.text}\n </Link>\n <ul className=\"MenuDropdown-submenu\">\n {menuItem.submenu.map(({ ...submenuItem }, key) => (\n <li className=\"MenuDropdown-submenu-item\" key={key}>\n <Link to={submenuItem.url}>{submenuItem.text}</Link>\n </li>\n ))}\n </ul>\n </div>\n )\n}\n\nconst MenuBanner = () => (\n <div className=\"MenuDropdown-banner\">\n <Link to=\"/pages/medical-supplies\">Medical Supplies Available | Our Response to COVID-19</Link>\n </div>\n)\n\nconst Header = ({ black = false }) => {\n const { showCart } = useCartActions()\n const { y: scrollY } = useWindowScroll()\n let [isNavbarOpen, setNavbarOpen] = useState(false)\n let [isSearchOpen, setIsSearchOpen] = useState(false)\n\n const header = useRef(null)\n const opacityPoint = 300\n\n const toggleNavbar = () => {\n setNavbarOpen(!isNavbarOpen)\n }\n const toggleSearch = () => {\n setIsSearchOpen(!isSearchOpen)\n }\n\n useEffect(() => {\n if (!black && typeof window !== 'undefined') {\n header.current.style.backgroundColor = `rgba(0,0,0, ${scrollY / opacityPoint})`\n }\n }, [black, scrollY])\n\n return (\n <header ref={header} className={cx('Header', { 'Header--black': black })}>\n <div className=\"Header-top-wrap\">\n <CartDrawer />\n <Navbar menu={menu} isOpen={isNavbarOpen} closeNavbar={toggleNavbar} />\n <SearchBar isOpen={isSearchOpen} closeSearch={toggleSearch} />\n <PageWidth>\n <div className=\"Header-top\">\n <div className=\"Header-left-nav\">\n <Link to=\"/\" className=\"LogoNomad\">\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo\"\n />\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo--small\"\n />\n </Link>\n <nav className=\"Nav-main\">\n <ul>\n <li className=\"Nav-main-item\">\n <Link to=\"#\">\n <span>Shop</span>\n </Link>\n <div className=\"Nav-main-dropdown MenuDropdown\">\n <div className=\"MenuDropdown-menu\">\n {menu\n .filter(obj => obj.text != 'Discover')\n .map(({ ...menuItem }, key) => (\n <HeaderSubmenu key={key} menuItem={menuItem} />\n ))}\n </div>\n <MenuBanner />\n </div>\n </li>\n <li className=\"Nav-main-item\">\n <Link to=\"/collections/whatsnew\">Discover</Link>\n <div className=\"Nav-main-dropdown MenuDropdown\">\n <div className=\"MenuDropdown-menu discover\">\n {menu\n .filter(obj => obj.text == 'Discover')\n .map(({ ...menuItem }, key) => (\n <HeaderSubmenu key={key} menuItem={menuItem} />\n ))}\n <div className=\"MenuDropdown-column\">\n <span className=\"MenuDropdown-column-header\">Featured Collections</span>\n <ul className=\"MenuDropdown-featured\">\n {featuredCollections.map(({ ...featuredItem }, key) => (\n <li className=\"MenuDropdown-featured-item\" key={key}>\n <Link to={featuredItem.url}>\n <ResponsiveImage\n alt={featuredItem.text}\n src={featuredItem.imageUrl}\n />\n <span>{featuredItem.text}</span>\n </Link>\n </li>\n ))}\n </ul>\n </div>\n </div>\n <MenuBanner />\n </div>\n </li>\n <li className=\"Nav-main-item\">\n <Link to=\"/pages/blog\">The Nomadic</Link>\n <div className=\"Nav-main-dropdown MenuDropdown\">\n <div className=\"MenuDropdown-menu blog\">\n <div className=\"MenuDropdown-column\">\n <div className=\"MenuDropdown-column-info\">\n <span className=\"MenuDropdown-column-header\">The Nomadic Blog</span>\n <p>\n Our blog, where you’ll find stories from behind the scenes, and get a\n glimpse of our lives as Modern Nomads.\n </p>\n <Button to=\"/pages/blog\" className=\"Btn Btn--default\">\n Explore the Blog\n </Button>\n </div>\n </div>\n\n <div className=\"MenuDropdown-column\">\n <span className=\"MenuDropdown-column-header\">Featured Blog Posts</span>\n <ul className=\"MenuDropdown-featured\">\n {featuredBlogPosts.map(({ ...featuredItem }, key) => (\n <li className=\"MenuDropdown-featured-item\" key={key}>\n <Link to={featuredItem.url}>\n <ResponsiveImage\n alt={featuredItem.text}\n src={featuredItem.imageUrl}\n />\n <span>{featuredItem.text}</span>\n </Link>\n </li>\n ))}\n </ul>\n </div>\n </div>\n <MenuBanner />\n </div>\n </li>\n <li className=\"Nav-main-item btn-medical-supplies\">\n <Link to=\"/pages/medical-supplies\">Medical Supplies</Link>\n </li>\n </ul>\n </nav>\n </div>\n <ul className=\"Header-right-nav\">\n <li>\n <button type=\"button\" onClick={toggleSearch}>\n <Icons name=\"Search\" white className=\"Header-search-svg\" />\n </button>\n </li>\n <li>\n <button type=\"button\" className=\"Header-cart\" onClick={showCart}>\n <Icons name=\"Cart\" white className=\"Header-cart-svg\" />\n </button>\n </li>\n <li className=\"ToggleNavDrawer\">\n <button type=\"button\" onClick={toggleNavbar}>\n <Icons name=\"Menu\" white className=\"Header-menuIcon\" />\n </button>\n </li>\n </ul>\n </div>\n </PageWidth>\n </div>\n </header>\n )\n}\n\nexport default Header\n", | |
| "style": ".Header {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n z-index: 3;\n}\n\n.Header--black {\n position: sticky;\n}\n\n.Header--black {\n background: #000;\n}\n\n.Header button {\n cursor: pointer;\n}\n\n.Header:before {\n bottom: 0;\n content: '';\n display: block;\n left: 0;\n position: absolute;\n top: 0;\n width: 100%;\n background: linear-gradient(to bottom, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0) 100%);\n}\n\n.Header-top-wrap {\n display: flex;\n height: 40px;\n position: relative;\n}\n\n.Header-top {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0;\n width: 100%;\n height: 100%;\n}\n.LogoNomad {\n line-height: 1;\n align-self: center;\n margin-right: 13.5px;\n}\n\n.LogoNomad-logo {\n display: none;\n width: 130px;\n}\n\n.LogoNomad-logo--small {\n width: 90px;\n}\n\n.Header-social {\n color: #000;\n margin: 28px 0 20px;\n}\n\n.Header-title {\n color: #fff;\n font-family: Gotham-Bold, sans-serif;\n font-size: 40px;\n line-height: 1.1;\n padding: 20px;\n position: relative;\n}\n\n.Header-right-nav {\n display: flex;\n align-items: center;\n margin-right: 0;\n}\n\n.Header-right-nav svg {\n display: block;\n}\n\n.Header-right-nav > li {\n padding-left: 20px;\n line-height: 1;\n font-size: 22px;\n display: inline-flex;\n}\n\n.Header-left-nav {\n display: flex;\n height: 100%;\n}\n\n.Nav-main {\n width: 100%;\n display: none;\n}\n\n.Nav-main a {\n text-decoration: none;\n}\n\n.Nav-main > ul {\n display: flex;\n height: 100%;\n box-sizing: border-box;\n padding: 10px 13.5px 0;\n}\n\n.Nav-main-item {\n margin-right: 8px;\n}\n\n.Nav-main-item > a {\n align-items: center;\n display: flex;\n justify-content: center;\n height: 100%;\n padding: 0 15px 10px;\n box-sizing: border-box;\n font-family: 'Gotham-Bold', sans-serif;\n color: white;\n transition: all 0.3s;\n}\n\n.Nav-main-item:hover > a {\n color: black;\n background: white;\n}\n.Nav-main-item:hover .Nav-main-dropdown {\n visibility: visible;\n transform: translate3d(0px, 0px, 0px);\n transition: all 300ms;\n opacity: 1;\n}\n\n.Nav-main-item.btn-medical-supplies {\n margin-bottom: 10px;\n}\n\n.Nav-main-item.btn-medical-supplies a {\n padding: 7px 15px;\n}\n\n.Nav-main-dropdown {\n display: block;\n position: absolute;\n width: 100%;\n left: 40px;\n margin: 0;\n z-index: 5;\n width: calc(100% - 80px);\n visibility: hidden;\n transform: translate3d(-10px, 0px, 0px);\n opacity: 0;\n transition: all 200ms;\n}\n\n.MenuDropdown {\n background: white;\n top: 100%;\n box-shadow: 0px 10px 20px rgba(0,0,0,0.09);\n}\n\n.MenuDropdown-menu {\n box-sizing: border-box;\n padding: 40px 20px;\n display: flex;\n max-width: 1100px;\n text-rendering: optimizeLegibility;\n margin: 0 auto;\n}\n\n.MenuDropdown-menu.discover {\n justify-content: center;\n}\n\n.MenuDropdown-menu.discover .MenuDropdown-column {\n margin-right: 67px;\n margin-left: auto;\n max-width: 180px;\n}\n\n.MenuDropdown-menu.discover .MenuDropdown-column:last-child {\n max-width: 690px;\n margin-left: 0;\n}\n\n.MenuDropdown-menu.blog {\n justify-content: center;\n}\n\n.MenuDropdown-menu.blog .MenuDropdown-column {\n margin-right: 40px;\n margin-left: auto;\n max-width: 270px;\n border: none;\n}\n\n.MenuDropdown-menu.blog .MenuDropdown-column:last-child {\n max-width: 690px;\n margin: 0;\n}\n\n.MenuDropdown-column-info p {\n margin: 3px 25px 40px 0;\n font-size: 15px;\n}\n\n.MenuDropdown-banner {\n background-color: #f3f3f3;\n font-weight: bold;\n text-align: center;\n padding: 10px 20px;\n}\n\n.MenuDropdown-banner a {\n color: #000;\n}\n\n.MenuDropdown-column {\n flex-grow: 1;\n text-align: left;\n position: relative;\n margin-right: 30px;\n max-width: 690px;\n border-right: 2px solid #f3f3f3;\n}\n\n\n.MenuDropdown-column:last-child {\n border: none;\n margin-right: 0;\n}\n\n.MenuDropdown-column:last-child {\n padding-right: 0px;\n}\n\n.MenuDropdown-column:last-child:after {\n display: none;\n}\n\n.MenuDropdown-column--withThumbnail {\n display: flex;\n max-width: 100%;\n color: #000;\n}\n\n.MenuDropdown-column--withThumbnail a {\n color: #000;\n}\n\n.MenuDropdown-column--withThumbnail .left {\n display: flex;\n}\n\n.MenuDropdown-column--withThumbnail .right {\n display: flex;\n width: 100%;\n}\n\n.Thumbnail {\n width: 220px;\n height: 162px;\n overflow: hidden;\n flex-shrink: 0;\n}\n\n.Thumbnail img {\n object-fit: cover;\n min-width: 100%;\n max-height: 100%;\n z-index: -1;\n pointer-events: none;\n}\n\n.MenuDropdown-submenu {\n padding-right: 30px;\n}\n\n.MenuDropdown-submenu-item a {\n color: #000;\n display: inline-block;\n padding: 5px 0;\n font-size: 1em;\n position: relative;\n}\n\n.MenuDropdown-submenu-item a:after {\n border-bottom: 2px solid #000;\n content: ' ';\n display: block;\n position: absolute;\n box-sizing: border-box;\n width: 0%;\n transition: width 0.5s ease;\n height: 0px;\n bottom: 3px;\n}\n\n.MenuDropdown-submenu-item a:hover:after {\n width: 80%;\n}\n\n.MenuDropdown-column-header {\n display: block;\n font-family: Gotham-Bold, sans-serif;\n color: #000;\n font-size: 16px;\n line-height: 1.6;\n padding: 5px 0 10px;\n}\n\n.MenuDropdown-featured {\n display: flex;\n justify-content: space-between;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.MenuDropdown-featured-item {\n position: relative;\n display: block;\n width: 220px;\n height: 162px;\n overflow: hidden;\n cursor: pointer;\n margin-top: 10px;\n}\n\n.MenuDropdown-featured-item:hover {\n opacity: 0.7;\n transition: 0.1s;\n}\n\n.MenuDropdown-featured-item a:before {\n content: \"\";\n display: block;\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n background: linear-gradient(rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 0.7));\n z-index: 1;\n}\n\n.MenuDropdown-featured-item a {\n display: block;\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.MenuDropdown-featured-item img {\n object-fit: cover;\n max-width: 100%;\n height: 100%;\n z-index: -1;\n pointer-events: none;\n}\n\n.MenuDropdown-featured-item span {\n position: absolute;\n bottom: 0px;\n left: 0;\n padding: 0px 0px 6px 12px;\n color: #fff;\n font-size: 14px;\n z-index: 1;\n}\n\n@media (min-width: 768px) {\n .Header-top-wrap {\n height: 60px;\n }\n\n .LogoNomad-logo {\n display: block;\n }\n\n .LogoNomad-logo--small {\n display: none;\n }\n\n .Nav-main {\n display: block;\n }\n\n .Header-right-nav {\n margin-right: 25px;\n }\n\n .Header-right-nav li.ToggleNavDrawer {\n display: none;\n }\n\n .Header-search-form input {\n font-size: 1.5em;\n }\n}\n", | |
| "fields": null, | |
| "currentVersionID": "e9d379dc-b643-40b9-aa00-30bd3e96114c", | |
| "createdAt": 1587051761, | |
| "updatedAt": 1588685682, | |
| "__typename": "Component" | |
| }, | |
| "__typename": "PageComposition" | |
| }, | |
| { | |
| "id": "390726a9-ee6c-4015-9bbb-9afae8f19362", | |
| "query": " query ProductStickyAddToCartQuery($cmsEntryID: ID!) { selector : cmsEntryStringField ( id:\"20f53e61-32a5-42aa-9d9b-e1bfbe066463\",cmsFieldID:\"2e4322f1-2a97-4ff6-9311-6e8385a235c8\" ) ,variantId : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"7cb5a6cd-32af-4012-8806-b65fef1890d8\" ) }", | |
| "type": "inherited", | |
| "masterPageCompositionID": "7bde410e-1b14-48e1-8ee7-d99b550117eb", | |
| "pageVersionID": "5dff3968-18f5-4b89-9f21-6439e9ff3641", | |
| "directives": { | |
| "selector": "ProductBox", | |
| "variantId": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0LzQzMjA0NDkxNjc0MDg=" | |
| }, | |
| "breadcrumbs": [ | |
| { | |
| "componentFieldID": "2e4322f1-2a97-4ff6-9311-6e8385a235c8", | |
| "trails": [ | |
| { | |
| "entityID": "20f53e61-32a5-42aa-9d9b-e1bfbe066463", | |
| "entityType": "cmsEntry", | |
| "entityValue": "ProductBox", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "2e4322f1-2a97-4ff6-9311-6e8385a235c8", | |
| "entityType": "cmsField", | |
| "entityValue": "selector", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "39b960b3-9ead-4147-ac5e-dba4e501f683", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "7cb5a6cd-32af-4012-8806-b65fef1890d8", | |
| "entityType": "cmsField", | |
| "entityValue": "storefrontID", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| } | |
| ], | |
| "component": { | |
| "id": "8307f5b6-16a1-4217-a312-296919023e5b", | |
| "name": "ProductStickyAddToCart", | |
| "code": "import React, { useEffect, useState } from 'react'\nimport useWindowScroll from 'react-use/lib/useWindowScroll'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport AddToCart from 'Components/AddToCart'\n\nimport './styles.css'\n\nconst ProductStickyAddToCart = ({ selector, variantId }) => {\n let [showFilter, setShowFilter] = useState(false)\n const [productDetail, setProductDetail] = useState({})\n\n useEffect(() => {\n const el = document.querySelector(`.${selector}`)\n const detail = {\n title: el.querySelector(`.${selector}-title`).innerText,\n desc: el.querySelector(`.${selector}-desc`).innerText,\n price: el.querySelector(`.${selector}-price`).innerText,\n triggerPoint: el.querySelector('.AddToCart-btn').offsetTop,\n }\n setProductDetail(detail)\n }, [])\n\n const { y: pageYOffset } = useWindowScroll()\n useEffect(() => {\n setShowFilter(productDetail.triggerPoint < pageYOffset)\n }, [pageYOffset])\n\n return (\n <div className={cx('ProductStickyAddToCart', { 'is-visible': showFilter })}>\n <PageWidth className=\"ProductStickyAddToCart-container\">\n <div className=\"ProductStickyAddToCart-detail\">\n <h3 className=\"ProductStickyAddToCart-title\">{productDetail.title}</h3>\n <h5 className=\"ProductStickyAddToCart-desc\">\n {productDetail.desc} - {productDetail.price}\n </h5>\n </div>\n <AddToCart className=\"ProductStickyAddToCart-btn\" variantId={variantId}>\n Add to Cart\n </AddToCart>\n </PageWidth>\n </div>\n )\n}\n\nexport default ProductStickyAddToCart\n", | |
| "style": ".ProductStickyAddToCart {\n background-color: rgba(0, 0, 0, 0.75);\n color: #FFF;\n position: fixed;\n top: -70px;\n left: 0;\n transition: top 0.5s ease;\n width: 100%;\n z-index: 1;\n}\n\n.ProductStickyAddToCart.is-visible {\n top: 60px;\n}\n\n.ProductStickyAddToCart-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.ProductStickyAddToCart-detail {\n display: flex;\n align-items: center;\n}\n\n.ProductStickyAddToCart-title {\n font-family: 'Gotham-Bold';\n font-size: 1em;\n line-height: 1.6;\n}\n\n.ProductStickyAddToCart-desc {\n margin-left: 15px;\n font-family: 'Gotham-Book';\n font-size: 1em;\n}\n\n.ProductStickyAddToCart-btn {\n width: 16.66667%;\n height: 40px;\n margin: 10px;\n background-color: #eee;\n outline: none;\n color: #000;\n}\n\n@media (max-width: 768px) {\n .ProductStickyAddToCart {\n top: -45px;\n height: 39px;\n }\n \n .ProductStickyAddToCart.is-visible {\n top: 40px;\n }\n\n .ProductStickyAddToCart-detail {\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n }\n \n .ProductStickyAddToCart-title {\n padding: 0;\n font-size: 0.75em;\n line-height: 9px;\n }\n \n .ProductStickyAddToCart-desc {\n padding: 0;\n margin-left: 0;\n font-size: 0.75em;\n }\n\n .ProductStickyAddToCart-btn {\n width: 33%;\n height: 24px;\n padding: 1px 10px;\n margin: 0;\n font-size: 12px;\n }\n\n .ProductStickyAddToCart-btn .LoadingSpinner-lds-ring,\n .ProductStickyAddToCart-btn .LoadingSpinner-lds-ring div {\n width: 20px;\n height: 20px;\n }\n}", | |
| "fields": [ | |
| { | |
| "id": "2e4322f1-2a97-4ff6-9311-6e8385a235c8", | |
| "name": "selector", | |
| "placeholder": "Empty Selector", | |
| "required": false, | |
| "type": "string", | |
| "system": true, | |
| "visible": false, | |
| "cmsModelID": "1b9e33de-848c-4166-b147-ae1ebb2a19aa", | |
| "options": null, | |
| "localized": false, | |
| "createdAt": 1587069795, | |
| "updatedAt": 1588685683, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "39b960b3-9ead-4147-ac5e-dba4e501f683", | |
| "name": "variantId", | |
| "placeholder": "Empty variantId", | |
| "required": false, | |
| "type": "string", | |
| "system": true, | |
| "visible": false, | |
| "cmsModelID": "1b9e33de-848c-4166-b147-ae1ebb2a19aa", | |
| "options": null, | |
| "localized": false, | |
| "createdAt": 1587069795, | |
| "updatedAt": 1588685683, | |
| "__typename": "CmsField" | |
| } | |
| ], | |
| "currentVersionID": "d1fd0505-a45a-456a-816a-d3be8f0491da", | |
| "createdAt": 1587051761, | |
| "updatedAt": 1588685683, | |
| "__typename": "Component" | |
| }, | |
| "__typename": "PageComposition" | |
| }, | |
| { | |
| "id": "76a929d0-9bd0-4555-9db6-d57438f95c2d", | |
| "query": " query ProductBoxQuery($cmsEntryID: ID!) { faq : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"05c978df-4480-440e-b0cf-3a296b8167d8\" ) ,productName : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"b3f08edf-4bcf-475a-bc8c-3568e0249d10\" ) ,tags : cmsEntryStringArray ( id:$cmsEntryID ,cmsFieldID:\"74d8a4b0-eaeb-4513-bf69-1ec8bec18de6\" ) ,images : cmsEntryReferenceObjectArray ( id:$cmsEntryID ,cmsFieldID:\"49233aba-9baa-4c9b-a78a-700167951f7b\" ) ,description : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"05c978df-4480-440e-b0cf-3a296b8167d8\" ) ,info : cmsEntryStringField ( id:$cmsEntryID ,cmsFieldID:\"05c978df-4480-440e-b0cf-3a296b8167d8\" ) ,variants : cmsEntryReferenceObjectArray ( id:$cmsEntryID ,cmsFieldID:\"bdc84199-08ea-431a-9254-2b29b51887b0\" ) }", | |
| "type": "inherited", | |
| "masterPageCompositionID": "e3e01879-e850-4219-bcfb-2943ba86476e", | |
| "pageVersionID": "5dff3968-18f5-4b89-9f21-6439e9ff3641", | |
| "directives": { | |
| "description": "Description Designed to give your AirPods a classic, yet bold new look. This two-piece Rugged Case is built with a new optical light pipe for the LED charging indicator on AirPods with Wireless Charging Case. Built with genuine, vegetable-tanned leather designed to beautifully patina with time, Rugged Case creates an AirPods case truly unique to you. Rustic Brown Horween leather from the USA Develops a rugged patina Designed for AirPods with Wireless Charging Case Protective microfiber lining Two-piece construction Works with AirPods and AirPods with Wireless Charging Case Integrated light pipe for Wireless Charging Case LED Also available in Black. Info Materials Rustic Brown Horween leather Black polycarbonate shell Rubber TPE bumper Protective microfiber lining Compatibility Built for AirPods Accessible Lightning port Works with AirPods and AirPods with Wireless Charging Case Dimensions With case on: Total height 58.8mm Total width: 49.3mm Total depth: 26.4mm Wireless Wireless charging requires AirPods Wireless Charging Case Qi Wireless compatible Rugged Case does not affect wireless charging FAQ Does Rugged Case work with AirPods Wireless Charging Case? Yes, it works with the AirPods with Wireless Charging Case and AirPods with Standard Charging Case. How do I remove the case? The best way is to use a Lightning cable. Plug your AirPods in to charge, then hold your case and push on the Lightning cable through to carefully remove the case. How should I care for my Rugged Case for AirPods? The leather will develop a patina over time, giving it a beautiful, worn-in and weathered look unique to you. A soft, damp cloth can help clean it, but we don't recommend fully submerging this case. For best care, use a quality leather conditioner. Learn more Does this case enable wireless charging for my AirPods? No. This case is designed to offer a unique look and additional scratch and drop protection. However, you can charge your AirPods wirelessly with Rugged Case if you have the AirPods Wireless Charging Case.", | |
| "faq": "Description Designed to give your AirPods a classic, yet bold new look. This two-piece Rugged Case is built with a new optical light pipe for the LED charging indicator on AirPods with Wireless Charging Case. Built with genuine, vegetable-tanned leather designed to beautifully patina with time, Rugged Case creates an AirPods case truly unique to you. Rustic Brown Horween leather from the USA Develops a rugged patina Designed for AirPods with Wireless Charging Case Protective microfiber lining Two-piece construction Works with AirPods and AirPods with Wireless Charging Case Integrated light pipe for Wireless Charging Case LED Also available in Black. Info Materials Rustic Brown Horween leather Black polycarbonate shell Rubber TPE bumper Protective microfiber lining Compatibility Built for AirPods Accessible Lightning port Works with AirPods and AirPods with Wireless Charging Case Dimensions With case on: Total height 58.8mm Total width: 49.3mm Total depth: 26.4mm Wireless Wireless charging requires AirPods Wireless Charging Case Qi Wireless compatible Rugged Case does not affect wireless charging FAQ Does Rugged Case work with AirPods Wireless Charging Case? Yes, it works with the AirPods with Wireless Charging Case and AirPods with Standard Charging Case. How do I remove the case? The best way is to use a Lightning cable. Plug your AirPods in to charge, then hold your case and push on the Lightning cable through to carefully remove the case. How should I care for my Rugged Case for AirPods? The leather will develop a patina over time, giving it a beautiful, worn-in and weathered look unique to you. A soft, damp cloth can help clean it, but we don't recommend fully submerging this case. For best care, use a quality leather conditioner. Learn more Does this case enable wireless charging for my AirPods? No. This case is designed to offer a unique look and additional scratch and drop protection. However, you can charge your AirPods wirelessly with Rugged Case if you have the AirPods Wireless Charging Case.", | |
| "images": [ | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/d331774c-5d30-4393-a83d-963da5778d40/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533385776" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/b2a9babf-f0c6-451c-8c23-6222092f587d/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533451312" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/4834ad27-d0dd-4c8f-8d16-d87bae962cd9/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533484080" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/f57525ba-e2f5-49df-8d69-052b01741166/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533516848" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/e5b5be0f-7cb4-49d6-865c-92f97ef22c91/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533713456" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/568e5065-2e07-45ce-b50c-cc930a514b24/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533746224" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/fb1272b8-03e6-46f4-946f-c9cbe027b0a0/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533680688" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/03e0d5db-2c81-490e-a934-8f86c9ae30da/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533549616" | |
| }, | |
| { | |
| "alt": "", | |
| "src": "https://assets.frontend.shogun.dev/0aba13b2-e919-4400-b687-204479a6302f/", | |
| "storefrontid": "gid://shopify/ProductImage/13323533615152" | |
| } | |
| ], | |
| "info": "Description Designed to give your AirPods a classic, yet bold new look. This two-piece Rugged Case is built with a new optical light pipe for the LED charging indicator on AirPods with Wireless Charging Case. Built with genuine, vegetable-tanned leather designed to beautifully patina with time, Rugged Case creates an AirPods case truly unique to you. Rustic Brown Horween leather from the USA Develops a rugged patina Designed for AirPods with Wireless Charging Case Protective microfiber lining Two-piece construction Works with AirPods and AirPods with Wireless Charging Case Integrated light pipe for Wireless Charging Case LED Also available in Black. Info Materials Rustic Brown Horween leather Black polycarbonate shell Rubber TPE bumper Protective microfiber lining Compatibility Built for AirPods Accessible Lightning port Works with AirPods and AirPods with Wireless Charging Case Dimensions With case on: Total height 58.8mm Total width: 49.3mm Total depth: 26.4mm Wireless Wireless charging requires AirPods Wireless Charging Case Qi Wireless compatible Rugged Case does not affect wireless charging FAQ Does Rugged Case work with AirPods Wireless Charging Case? Yes, it works with the AirPods with Wireless Charging Case and AirPods with Standard Charging Case. How do I remove the case? The best way is to use a Lightning cable. Plug your AirPods in to charge, then hold your case and push on the Lightning cable through to carefully remove the case. How should I care for my Rugged Case for AirPods? The leather will develop a patina over time, giving it a beautiful, worn-in and weathered look unique to you. A soft, damp cloth can help clean it, but we don't recommend fully submerging this case. For best care, use a quality leather conditioner. Learn more Does this case enable wireless charging for my AirPods? No. This case is designed to offer a unique look and additional scratch and drop protection. However, you can charge your AirPods wirelessly with Rugged Case if you have the AirPods Wireless Charging Case.", | |
| "productName": "Rugged Case", | |
| "tags": [ | |
| "_not_on_backorder", | |
| "_not_on_sale", | |
| "_related_related-airpods-wireless-brown", | |
| "_sub_title_AirPods | Wireless", | |
| "AirPods", | |
| "Gear" | |
| ], | |
| "variants": [ | |
| { | |
| "availableforsale": true, | |
| "createdat": "2019-10-28T20:39:42Z", | |
| "name": "AirPods / Rustic Brown", | |
| "originalprice": 0, | |
| "position": 1, | |
| "price": 34.95, | |
| "quantity": 148, | |
| "sku": "856504015732", | |
| "storefrontid": "Z2lkOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8zMTA2MzYxOTYzMzIwMA==", | |
| "thumbnail": "https://assets.frontend.shogun.dev/d331774c-5d30-4393-a83d-963da5778d40/", | |
| "updatedat": "2020-05-05T13:14:25Z" | |
| } | |
| ] | |
| }, | |
| "breadcrumbs": [ | |
| { | |
| "componentFieldID": "ffc3e6f6-72cb-48a3-a069-cfe4109c60a2", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "b3f08edf-4bcf-475a-bc8c-3568e0249d10", | |
| "entityType": "cmsField", | |
| "entityValue": "name", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "532ed937-f99b-4d33-a807-869e43d5e740", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "74d8a4b0-eaeb-4513-bf69-1ec8bec18de6", | |
| "entityType": "cmsField", | |
| "entityValue": "tags", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "ea09ca9a-d337-4e9d-bc27-93e5c91b2d62", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "49233aba-9baa-4c9b-a78a-700167951f7b", | |
| "entityType": "cmsField", | |
| "entityValue": "images", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "d55dfe65-3a2d-472a-b4ee-d5bad25c6695", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "05c978df-4480-440e-b0cf-3a296b8167d8", | |
| "entityType": "cmsField", | |
| "entityValue": "description", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "7424d587-8acd-4e1e-9fdd-1cc0ddcfdd4d", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "05c978df-4480-440e-b0cf-3a296b8167d8", | |
| "entityType": "cmsField", | |
| "entityValue": "description", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "df5b09cb-5310-4727-bc94-47e71fd296bd", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "05c978df-4480-440e-b0cf-3a296b8167d8", | |
| "entityType": "cmsField", | |
| "entityValue": "description", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| }, | |
| { | |
| "componentFieldID": "34d7f953-db6d-45f7-9ebd-67a33497d7a9", | |
| "trails": [ | |
| { | |
| "entityID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "entityType": "cmsModel", | |
| "entityValue": "Products", | |
| "__typename": "BreadcrumbItem" | |
| }, | |
| { | |
| "entityID": "bdc84199-08ea-431a-9254-2b29b51887b0", | |
| "entityType": "cmsField", | |
| "entityValue": "variants", | |
| "__typename": "BreadcrumbItem" | |
| } | |
| ], | |
| "__typename": "Breadcrumb" | |
| } | |
| ], | |
| "component": { | |
| "id": "9c40a0f8-a7b5-4224-947e-1be7fd3305e9", | |
| "name": "ProductBox", | |
| "code": "import React, { useEffect } from 'react'\nimport { useHistory, useLocation } from 'react-router-dom'\nimport queryString from 'query-string'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport AddToCart from 'Components/AddToCart'\nimport Carousel from 'Components/Carousel'\nimport Accordions from 'Components/Accordions'\nimport StarRating from 'Components/StarRating'\nimport RichText from 'Components/RichText'\n\nimport './styles.css'\n\nconst ProductBox = ({\n variants = [],\n tags,\n images,\n productId,\n productName,\n reviewsCount,\n reviewsRating,\n tipHTML,\n description,\n info,\n faq,\n}) => {\n console.log('# ProductBox # productName =>', productName)\n console.log('# ProductBox # images =>', images)\n console.log('# ProductBox # variants =>', variants)\n\n const history = useHistory()\n const location = useLocation()\n\n const productSubTitle = getProductSubtitle(tags)\n const accordionItems = [\n {\n title: 'Description',\n content: description,\n },\n {\n title: 'Info',\n content: info,\n },\n {\n title: 'Faq',\n content: faq,\n },\n ]\n\n const variantId = queryString.parse(location.search).variant\n const variant = variants.length ? variants.find(v => v.remote_id == variantId) || variants[0] : []\n\n console.log(variant)\n console.log(images)\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.dataLayer === 'undefined') return\n if (!variant) return\n\n window.dataLayer.push({\n event: 'productDetailView',\n ecommerce: {\n currencyCode: 'USD',\n detail: {\n products: [\n {\n name: productName,\n productId: getRemoteId(productId),\n category: productSubTitle,\n\n id: variant.sku,\n variantId: getRemoteId(variant.id),\n variant: variant.name,\n price: variant.originalPrice,\n compareAtPrice: variant.price,\n inventoryCount: variant.quantity,\n\n brand: 'Nomad Goods',\n },\n ],\n },\n },\n })\n }, [variantId])\n\n const handleVariantClick = v => () => {\n history.push({ search: `?variant=${v.remote_id}` })\n }\n \n return (\n <div className=\"ProductBox\">\n <PageWidth className=\"ProductBox-container\">\n {images && <Carousel images={images} />}\n\n <div className=\"ProductBox-content\">\n <h2 className=\"ProductBox-title\">{productName}</h2>\n <p className=\"ProductBox-desc\">{productSubTitle}</p>\n\n <hr className=\"ProductBox-divider\" />\n\n {variant.originalPrice && variant.originalPrice > variant.price && (\n <span className=\"ProductBox-price is-strikethrough\">${variant.originalPrice}</span>\n )}\n <span className=\"ProductBox-price\">${variant.price}</span>\n\n <div className=\"ProductBox-reviews\">\n {reviewsRating && <StarRating rate={reviewsRating} />}\n {reviewsCount && <p className=\"ProductBox-reviews-count\">{reviewsCount} Reviews</p>}\n </div>\n\n {variant.sale_label && <p className=\"ProductBox-saleLabel\">{variant.sale_label}</p>}\n\n {variants && variants.length > 1 && (\n <div className=\"ProductBox-variants-wrapper\">\n {variants.map(v => (\n <div\n key={v.remote_id}\n className={cx('ProductBox-variant', { active: v === variant })}\n onClick={handleVariantClick(v)}\n >\n ${v.price}\n </div>\n ))}\n </div>\n )}\n\n <AddToCart variantId={variant.id}>Add to Cart</AddToCart>\n\n {tipHTML && (\n <div className=\"ProductBox-tip\">\n <RichText source={tipHTML} />\n </div>\n )}\n\n <Accordions items={accordionItems} />\n </div>\n </PageWidth>\n </div>\n )\n}\n\nfunction getRemoteId(storefrontID) {\n console.log('# ProductBox # storefrontID =>', storefrontID)\n return\n const IdSegments = atob(storefrontID).split('/')\n const lastIdx = IdSegments.length - 1\n\n return IdSegments[lastIdx]\n}\n\nfunction getProductSubtitle(tags) {\n const key = '_sub_title_'\n const subtitleTag = tags && tags.find(tag => tag.includes(key))\n if (!subtitleTag) return ''\n\n return subtitleTag.replace(key, '')\n}\n\nexport default ProductBox\n", | |
| "style": ".ProductBox {\n padding: 60px 0;\n margin-left: -30px;\n background-color: #f3f3f3;\n}\n\n.ProductBox-container {\n display: grid;\n grid-template-columns: 3fr 2fr;\n}\n\n.ProductBox-content {\n margin: 25px 0 0 75px;\n}\n\n.ProductBox-title {\n font-size: 30px;\n}\n\n.ProductBox-desc {\n font-size: 17px;\n font-family: 'Gotham-Book';\n}\n\n.ProductBox-divider {\n margin: 25px 0;\n border: 1px solid #dedede;\n}\n\n.ProductBox-price {\n display: inline-block;\n font-size: 24px;\n font-family: 'Gotham-Bold';\n}\n\n.ProductBox-price.is-strikethrough {\n margin-right: 15px;\n text-decoration: line-through;\n}\n\n.ProductBox-reviews {\n display: flex;\n font-family: 'Gotham-Book';\n font-size: 12px;\n margin-bottom: 25px;\n}\n\n.ProductBox-reviews-count {\n margin-left: 15px;\n}\n\n.ProductBox-saleLabel {\n margin: 15px 0px 25px 0px;\n font-size: 18px;\n font-family: \"Gotham-Bold\";\n padding: 0px;\n color: #d02d2d;\n}\n\n.ProductBox-variants-wrapper {\n margin-bottom: 20px;\n}\n\n.ProductBox-variant {\n position: relative;\n display: inline-block;\n padding: 7px 15px 7px;\n margin: 0 15px 12px 0;\n background-color: #fff;\n cursor: pointer;\n}\n.ProductBox-variant:after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 1px solid #dedede;\n z-index: 1;\n box-sizing: border-box;\n}\n\n.ProductBox-variant.active:after {\n border: 2px solid #000;\n}\n\n.ProductBox-tip {\n margin-top: 20px;\n}\n\n@media (max-width: 767px) {\n .ProductBox {\n padding: 20px 0;\n margin-left: 0;\n }\n\n .ProductBox-container {\n grid-template-columns: 1fr;\n }\n\n .ProductBox-content {\n margin: 20px 0 0;\n }\n\n .ProductBox-desc {\n font-size: 14px;\n }\n}\n", | |
| "fields": [ | |
| { | |
| "id": "d55dfe65-3a2d-472a-b4ee-d5bad25c6695", | |
| "name": "faq", | |
| "placeholder": "FAQ", | |
| "required": false, | |
| "type": "string", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": null, | |
| "localized": false, | |
| "createdAt": 1588668523, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "ffc3e6f6-72cb-48a3-a069-cfe4109c60a2", | |
| "name": "productName", | |
| "placeholder": "Empty Product Name", | |
| "required": false, | |
| "type": "string", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": null, | |
| "localized": false, | |
| "createdAt": 1588348428, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "532ed937-f99b-4d33-a807-869e43d5e740", | |
| "name": "tags", | |
| "placeholder": "Empty Tags", | |
| "required": false, | |
| "type": "array", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": { | |
| "itemType": "string", | |
| "referencedCmsModelID": null, | |
| "__typename": "FieldOptions" | |
| }, | |
| "localized": false, | |
| "createdAt": 1588348428, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "ea09ca9a-d337-4e9d-bc27-93e5c91b2d62", | |
| "name": "images", | |
| "placeholder": "", | |
| "required": false, | |
| "type": "array", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": { | |
| "itemType": "reference", | |
| "referencedCmsModelID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "__typename": "FieldOptions" | |
| }, | |
| "localized": false, | |
| "createdAt": 1588348428, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "7424d587-8acd-4e1e-9fdd-1cc0ddcfdd4d", | |
| "name": "description", | |
| "placeholder": "description", | |
| "required": false, | |
| "type": "string", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": null, | |
| "localized": false, | |
| "createdAt": 1588668504, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "df5b09cb-5310-4727-bc94-47e71fd296bd", | |
| "name": "info", | |
| "placeholder": "Info", | |
| "required": false, | |
| "type": "string", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": null, | |
| "localized": false, | |
| "createdAt": 1588668504, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| }, | |
| { | |
| "id": "34d7f953-db6d-45f7-9ebd-67a33497d7a9", | |
| "name": "variants", | |
| "placeholder": "Variants", | |
| "required": false, | |
| "type": "array", | |
| "system": false, | |
| "visible": true, | |
| "cmsModelID": "5298dd73-1c92-4a72-9db8-4d3914cfc272", | |
| "options": { | |
| "itemType": "reference", | |
| "referencedCmsModelID": "92a673f9-27ab-4e68-a08a-9cbecf6bf9e8", | |
| "__typename": "FieldOptions" | |
| }, | |
| "localized": false, | |
| "createdAt": 1588694381, | |
| "updatedAt": 1588706652, | |
| "__typename": "CmsField" | |
| } | |
| ], | |
| "currentVersionID": "f1deb9ba-3779-4368-bf35-9cd6b08ad13d", | |
| "createdAt": 1587051761, | |
| "updatedAt": 1588706652, | |
| "__typename": "Component" | |
| }, | |
| "__typename": "PageComposition" | |
| }, | |
| { | |
| "id": "e130ea1b-2925-46ce-b8f2-5d6c643a55f7", | |
| "query": "", | |
| "type": "custom_section", | |
| "masterPageCompositionID": "aa8f49ac-7564-48d9-b6cc-9fa1f50e2152", | |
| "pageVersionID": "5dff3968-18f5-4b89-9f21-6439e9ff3641", | |
| "directives": {}, | |
| "breadcrumbs": [], | |
| "component": { | |
| "id": "bd92b602-7d81-4544-bad3-56dc53dbb8b8", | |
| "name": "dropzone", | |
| "code": "", | |
| "style": "", | |
| "fields": [], | |
| "currentVersionID": "fb3c49ff-8ed6-4ac9-af13-7826538db1ca", | |
| "createdAt": 1587051125, | |
| "updatedAt": 1587051125, | |
| "__typename": "Component" | |
| }, | |
| "__typename": "PageComposition" | |
| }, | |
| { | |
| "id": "076a113f-ce5f-487b-ad08-190c3fb5198b", | |
| "query": "", | |
| "type": "inherited", | |
| "masterPageCompositionID": "42ca2da2-3716-4c07-b42e-e2ae3f5bde0b", | |
| "pageVersionID": "5dff3968-18f5-4b89-9f21-6439e9ff3641", | |
| "directives": {}, | |
| "breadcrumbs": [], | |
| "component": { | |
| "id": "645fc079-bad0-4f95-9076-bfb8cc076172", | |
| "name": "Footer", | |
| "code": "import React from 'react'\nimport Link from 'frontend-link'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport SocialLinks from 'Components/SocialLinks'\nimport PageWidth from 'Components/PageWidth'\nimport './styles.css'\n\nconst menu = [\n {\n text: 'Support',\n submenu: [\n {\n text: 'Return & Exchange',\n url: '/pages/support',\n },\n {\n text: 'Shipping Info',\n url: '/pages/shipping',\n },\n {\n text: \"FAQ's\",\n url: 'https://help.hellonomad.com/',\n },\n {\n text: 'Log In',\n url: '/account/login',\n },\n ],\n },\n {\n text: 'About',\n submenu: [\n {\n text: 'About Us',\n url: 'pages/about',\n },\n {\n text: 'Press',\n url: '/pages/press',\n },\n {\n text: 'Careers',\n url: '/pages/careers',\n },\n {\n text: 'Affiliates',\n url: '/pages/affiliates',\n },\n ],\n },\n {\n text: 'Sales',\n submenu: [\n {\n text: 'Corporate Sales',\n url: '/pages/corporate',\n },\n {\n text: 'Wholesale',\n url: '/pages/wholesale-landing',\n },\n {\n text: \"Where We're Sold\",\n url: 'pages/where-we-are-sold',\n },\n {\n text: 'Assets',\n url: '/pages/assets',\n },\n ],\n },\n {\n text: 'Discover',\n submenu: [\n {\n text: 'The Nomadic',\n url: '/blogs/the-nomadic',\n },\n {\n text: 'Wallpapers',\n url: '/pages/wallpapers',\n },\n {\n text: 'Our Friends',\n url: '/pages/our-friends',\n },\n {\n text: 'Holiday Sale',\n url: 'collections/outletsale',\n },\n ],\n },\n]\n\nconst Footer = () => {\n const toggleMenu = element => {\n element.target.parentNode.classList.toggle('is-open')\n }\n\n return (\n <footer className=\"Footer\">\n <PageWidth>\n <div className=\"Footer-row\">\n <ul className=\"Footer-menu\">\n {menu.map(({ ...menuItem }, key) => (\n <li className=\"Footer-menuItem\" key={key}>\n <div className=\"Footer-menuColumnHeader--hideOnSmallScreen\">{menuItem.text}</div>\n <button\n className=\"Footer-menuColumnHeader\"\n onClick={element => toggleMenu(element)}\n >\n {menuItem.text}\n <span className=\"Footer-menuArrowIcon\"></span>\n </button>\n <ul className=\"Footer-submenu\">\n {menuItem.submenu.map(({ ...submenuItem }, key) => (\n <li className=\"Footer-submenuItem\" key={key}>\n <Link to={submenuItem.url} className=\"Footer-submenuLink\">\n {submenuItem.text}\n </Link>\n </li>\n ))}\n </ul>\n </li>\n ))}\n </ul>\n <div className=\"Footer-form\">\n <div className=\"Footer-form-copy\">New Products, Blogs, and Deals.</div>\n <form>\n <input type=\"email\" className=\"Footer-form-email\" placeholder=\"Email\" />\n <Button as=\"button\" type=\"submit\" value=\"submit\">\n Subscribe\n </Button>\n </form>\n </div>\n </div>\n <div className=\"Footer-row Footer-row--logoAndSocials\">\n <div className=\"Footer-logo\">\n <Link to=\"/\" className=\"LogoNomad\">\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo\"\n />\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo--small\"\n />\n </Link>\n </div>\n <div className=\"Footer-social\">\n <SocialLinks white />\n </div>\n </div>\n <div className=\"Footer-row\">\n <div className=\"Footer-copyright\">2020 Nomad Goods, Inc. All rights reserved.</div>\n <div className=\"Footer-privacy\">\n <Link to=\"/pages/privacy\">Privacy</Link>\n <Link to=\"/pages/terms\">Terms</Link>\n </div>\n </div>\n </PageWidth>\n </footer>\n )\n}\n\nexport default Footer\n", | |
| "style": ".Footer {\n background: url(https://cdn.shopify.com/s/files/1/0384/6721/t/101/assets/Topo_Footer_04_-_Mobile_v3.svg) no-repeat;\n background-size: cover;\n padding: 20px 0;\n background-color: #000;\n}\n\n.Footer-row {\n display: flex;\n justify-content: space-between;\n flex-direction: column;\n padding: 20px 0;\n}\n\n.Footer-logo {\n max-width: 110px;\n display: none;\n}\n\n.Footer-logo .LogoNomad-logo {\n max-width: 100%;\n display: block;\n}\n\n.Footer-logo .LogoNomad {\n display: block;\n}\n\n.Footer-row--logoAndSocials {\n padding-top: 0;\n margin-bottom: 20px;\n border-bottom: 1px solid #212121;\n align-items: center;\n justify-content: flex-start;\n}\n\n.Footer-menuItem {\n border-bottom: 1px solid #212121;\n margin-bottom: 4px;\n}\n\n.Footer-menuItem.is-open .Footer-submenu {\n height: 164px;\n opacity: 1;\n visibility: visible;\n}\n\n.Footer-menuItem.is-open .Footer-menuArrowIcon:before {\n transform: rotate(-45deg);\n}\n\n.Footer-menuItem.is-open .Footer-menuArrowIcon:after {\n transform: rotate(45deg);\n}\n\n.Footer-menuColumnHeader--hideOnSmallScreen,\n.Footer-menuColumnHeader {\n color: #fff;\n display: flex;\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 16px;\n font-weight: 400;\n justify-content: space-between;\n line-height: 1.6;\n margin: 20px 0;\n width: 100%;\n}\n\n.Footer-menuColumnHeader--hideOnSmallScreen {\n display: none;\n}\n\n.Footer-menuArrowIcon {\n display: inline-block;\n height: 14px;\n position: relative;\n width: 16px;\n pointer-events: none;\n}\n\n.Footer-menuArrowIcon:before,\n.Footer-menuArrowIcon:after {\n background-color: #efefef;\n content: '';\n display: inline-block;\n height: 2px;\n position: absolute;\n top: 12px;\n transition: transform 0.2s ease;\n width: 10px;\n}\n\n.Footer-menuArrowIcon:before {\n left: 0;\n transform: rotate(45deg);\n}\n\n.Footer-menuArrowIcon:after {\n right: 0;\n transform: rotate(-45deg);\n}\n\n.Footer-submenu {\n height: 0;\n opacity: 0;\n transition: height 0.3s ease, opacity 0.3s ease;\n visibility: hidden;\n}\n\n.Footer-submenuItem {\n padding: 4px 0 8px;\n}\n\n.Footer-submenuLink {\n color: #fff;\n font-size: 15px;\n text-decoration: none;\n}\n\n.Footer-social {\n color: #fff;\n margin: 0;\n width: 100%;\n}\n\n.Footer-privacy {\n margin-top: 10px;\n padding-bottom: 44px;\n}\n\n.Footer-copyright,\n.Footer-privacy a {\n color: #b4b4b4;\n font-size: 14px;\n text-decoration: none;\n}\n\n.Footer-privacy a:not(:last-child):after {\n content: '|';\n padding: 0 13px;\n}\n\n.Footer-form {\n color: white;\n font-size: 14px;\n margin: 20px 0;\n flex: 1;\n order: -1;\n}\n\n.Footer-form-copy {\n margin-bottom: 15px;\n}\n\n.Footer-form form {\n display: flex;\n}\n\n.Footer-form input,\n.Footer-form button {\n background: transparent;\n padding: 8px 16px;\n border: 1px solid white;\n color: white;\n line-height: 1.5;\n}\n\n.Footer-form-email {\n margin-right: 7px;\n flex: 1;\n}\n\n@media (min-width: 768px) {\n .Footer {\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/t/110/assets/Topo_Footer_03.svg);\n }\n\n .Footer-row {\n flex-direction: row;\n }\n\n .Footer-menu {\n display: flex;\n }\n\n .Footer-menuItem + .Footer-menuItem {\n margin-left: 45px;\n }\n\n .Footer-menuItem {\n border: 0;\n margin-bottom: 0;\n }\n\n .Footer-submenu {\n height: auto;\n opacity: 1;\n visibility: visible;\n }\n\n .Footer-privacy {\n margin-top: 0;\n }\n\n .Footer-menuColumnHeader {\n display: none;\n }\n\n .Footer-menuColumnHeader--hideOnSmallScreen {\n display: flex;\n }\n\n .Footer-logo {\n display: block;\n }\n\n .Footer-row--logoAndSocials {\n border-bottom: 1px solid #b4b4b4;\n margin-bottom: 0;\n padding: 20px 0;\n justify-content: space-between;\n }\n\n .Footer-social {\n width: auto;\n }\n\n .Footer-form {\n margin: 20px 0 20px 20px;\n max-width: 354px;\n order: 0;\n }\n\n .Footer-form-email {\n max-width: 250px;\n }\n}\n", | |
| "fields": null, | |
| "currentVersionID": "96d5814a-453a-44bc-9b70-0ba733d837bb", | |
| "createdAt": 1587051761, | |
| "updatedAt": 1588685683, | |
| "__typename": "Component" | |
| }, | |
| "__typename": "PageComposition" | |
| } | |
| ], | |
| "__typename": "Page" | |
| }, | |
| "site": { | |
| "domain": "frontend-carlos-staging.shogun.dev", | |
| "fonts": [ | |
| { | |
| "url": "https://cdn.shopify.com/s/files/1/0384/6721/files/Gotham-Book.otf", | |
| "name": "Gotham Book 400", | |
| "__typename": "Font" | |
| }, | |
| { | |
| "url": "https://cdn.shopify.com/s/files/1/0384/6721/files/Gotham-Bold.otf", | |
| "name": "Gotham-Bold", | |
| "__typename": "Font" | |
| }, | |
| { | |
| "url": "https://cdn.shopify.com/s/files/1/0384/6721/files/Gotham-Book.otf", | |
| "name": "Gotham-Book", | |
| "__typename": "Font" | |
| } | |
| ], | |
| "platform": "shopify", | |
| "platformDomain": "frontend-carlos-development.myshopify.com", | |
| "platformStorefrontToken": "12de778428a518c4389206ce87586b60", | |
| "globalStyles": "/***************/\n/** Nomad Stuff */\n.container {\n margin: 20px;\n}\n\n@media (max-width: 767px) {\n .container {\n margin: 10px;\n }\n}\n\nh2 {\n font-family: 'Gotham-Bold', sans-serif;\n font-weight: 400;\n line-height: 1.6;\n}\n\nbody {\n -webkit-font-smoothing: antialiased;\n color: #000;\n font-family: Inconsolata, 'HelveticaNeue', 'Helvetica Neue', sans-serif;\n line-height: 1.5;\n font-size: 16px;\n}\n\n/** GOOGLE FONT **/\n/* latin */\n@font-face {\n font-family: 'Inconsolata';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: local('Inconsolata Regular'), local('Inconsolata-Regular'),\n url(https://fonts.gstatic.com/s/inconsolata/v18/QldKNThLqRwH-OJ1UHjlKGlZ5qhExfHw.woff2)\n format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,\n U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* latin */\n@font-face {\n font-family: 'Inconsolata';\n font-style: normal;\n font-weight: 700;\n font-display: swap;\n src: local('Inconsolata Bold'), local('Inconsolata-Bold'),\n url(https://fonts.gstatic.com/s/inconsolata/v18/QldXNThLqRwH-OJ1UHjlKGHiw71p5_zaDpwm.woff2)\n format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F,\n U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n\n.visually-hidden {\n position: absolute;\n overflow: hidden;\n clip: rect(0 0 0 0);\n height: 1px;\n width: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n}", | |
| "searchAPIKey": "2ba51dcb994bb4720ba94156b1598486", | |
| "searchIndexes": [], | |
| "appDependencies": [ | |
| { | |
| "packageName": "classnames", | |
| "version": "2.2.6", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "lodash", | |
| "version": "4.17.15", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "css-element-queries", | |
| "version": "1.2.3", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "query-string", | |
| "version": "6.12.0", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "react-input-position", | |
| "version": "1.3.1", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "react-slick", | |
| "version": "0.25.2", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "react-use", | |
| "version": "13.27.1", | |
| "__typename": "AppDependency" | |
| }, | |
| { | |
| "packageName": "smoothscroll-polyfill", | |
| "version": "0.4.4", | |
| "__typename": "AppDependency" | |
| } | |
| ], | |
| "__typename": "Site" | |
| }, | |
| "components": [ | |
| { | |
| "name": "Story", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport useWindowSize from 'react-use/lib/useWindowSize'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\nimport ProductImageComparisonSlider from 'Components/ProductImageComparisonSlider'\nimport AnimatedAirPods from 'Components/AnimatedAirPods'\nimport AnimatedPower from 'Components/AnimatedPower'\n\nimport './styles.css'\n\nconst Story = ({\n resources = [],\n resourcesMobile,\n resourceType = 'image',\n logoSrc,\n logoHref,\n title,\n subtitle,\n description,\n ctaText,\n ctaHref = '#',\n reverse,\n theme,\n padding = [],\n titleSize,\n}) => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n const resolutionResources = isMobile ? resourcesMobile || resources : resources\n\n const mediaContent = (\n <div className=\"Story-media\">\n {resourceType === 'comparison' && (\n <ProductImageComparisonSlider src={resources[0]} comparisonSrc={resources[1]} />\n )}\n {resourceType === 'video' && (\n <video poster={resolutionResources[0]} autoPlay muted playsInline>\n <source src={resolutionResources[1]} />\n </video>\n )}\n {resourceType === 'youtube' && <iframe src={resolutionResources[0]} allowFullScreen />}\n {resourceType === 'airpods-animation' && <AnimatedAirPods resources={resolutionResources} />}\n {resourceType === 'airpods-animation-pro' && (\n <AnimatedAirPods isPro resources={resolutionResources} />\n )}\n {resourceType === 'power-animation' && <AnimatedPower resources={resolutionResources} />}\n {resourceType === 'image' && <ResponsiveImage src={resolutionResources[0]} alt=\"\" />}\n </div>\n )\n\n const textContent = (\n <div className=\"Story-text\">\n <h2 className={`Story-title ${titleSize}`}>{title}</h2>\n {subtitle && <h4 className=\"Story-subtitle\">{subtitle}</h4>}\n <p className=\"Story-description\">{description}</p>\n {ctaText && (\n <Button\n href={ctaHref}\n className={cx('Story-cta', 'Btn--default', {\n 'Btn--inverted': theme === 'light-dark' || theme === 'dark',\n })}\n >\n {ctaText}\n </Button>\n )}\n {logoSrc && (\n <a className=\"Story-logo\" href={logoHref} target=\"_blank\" rel=\"noopener noreferrer\">\n <ResponsiveImage src={logoSrc} alt=\"\" />\n </a>\n )}\n </div>\n )\n\n const paddingClasses = padding.map(pType => `Story--padding-${pType}`)\n\n return (\n <div className={cx('Story', `Story--theme-${theme}`, paddingClasses)}>\n <PageWidth className={cx('Story-wrapper', { 'Story-wrapper--reverse': reverse })}>\n <div className=\"Story-column\">{mediaContent}</div>\n <div className=\"Story-column\">{textContent}</div>\n </PageWidth>\n </div>\n )\n}\n\nexport default Story\n", | |
| "style": ".Story:nth-child(even) {\n background-color: #ffffff;\n}\n\n.Story:nth-child(odd) {\n background-color: #f3f3f3;\n}\n\n.Story-wrapper {\n display: flex;\n padding: 80px 0;\n width: 100%;\n max-width: 1220px;\n}\n\n.Story-column {\n flex: 1;\n margin: auto 0;\n}\n\n.Story-media {\n padding-left: 0;\n padding-right: 60px;\n}\n\n.Story-media img {\n display: block;\n width: 100%;\n}\n\n.Story-media iframe {\n width: 530px;\n height: 297px;\n}\n\n.Story-text {\n padding: 0 60px 0 40px;\n}\n\n.Story-title {\n margin-bottom: 20px;\n}\n\n.Story-title.big {\n font-family: 'Gotham-Bold';\n font-size: 40px;\n line-height: 1;\n margin-bottom: 0;\n}\n\n.Story-title.small {\n font-size: 20px;\n}\n\n.Story-subtitle {\n font-family: 'Gotham-Bold';\n font-size: 20px;\n margin-bottom: 10px;\n}\n\n.Story-description {\n margin-bottom: 30px;\n}\n\n.Story-logo {\n display: block;\n width: 140px;\n margin-top: 15px;\n}\n\n.Story-logo img {\n width: 100%;\n}\n\n/** reverse props **/\n.Story-wrapper--reverse {\n flex-direction: row-reverse;\n}\n\n.Story-wrapper--reverse .Story-media {\n padding-left: 60px;\n padding-right: 0;\n}\n\n.Story-wrapper--reverse .Story-text {\n padding: 0 80px 0 20px;\n}\n\n/** theme props **/\n.Story.Story--theme-gray {\n background-color: #f3f3f3;\n}\n\n.Story.Story--theme-white {\n background-color: #FFF;\n}\n\n.Story.Story--theme-light-dark {\n background-color: #0d0d0d;\n color: #ffffff;\n}\n\n.Story.Story--theme-dark {\n background-color: #000;\n color: white;\n}\n\n/** padding background props **/\n.Story--padding-background {\n margin: 20px;\n max-width: 2560px;\n}\n\n.Story--padding-background .Story-wrapper {\n max-width: 1220px;\n}\n\n.Story--padding-background .Story-wrapper--reverse .Story-text {\n max-width: 500px;\n}\n\n.Story--padding-background .Story-wrapper--reverse .Story-media {\n padding: 0;\n}\n\n.Story--padding-no-padding-top .Story-wrapper {\n padding-top: 0;\n}\n\n.Story--padding-no-padding-bottom .Story-wrapper {\n padding-bottom: 0;\n}\n/** padding no background props **/\n.Story--padding-no-padding-background .Story-wrapper {\n margin: 0;\n padding: 0;\n max-width: none;\n}\n\n.Story--padding-no-padding-background .Story-media {\n display: flex;\n align-items: flex-end;\n height: 700px;\n}\n\n.Story--padding-no-padding-background .Story-text {\n max-width: 450px;\n margin-left: 0;\n margin-right: auto;\n padding: 0 20px 0 60px;\n}\n\n/** padding text props **/\n.Story--padding-no-padding-background .Story-text {\n max-width: 450px;\n margin-left: 0;\n margin-right: auto;\n padding: 0 20px 0 60px;\n}\n\n.Story--padding-no-padding-background .Story-wrapper--reverse .Story-text {\n max-width: 450px;\n margin-left: auto;\n margin-right: 0;\n padding: 0 60px 0 20px;\n}\n\n.Story--padding-no-padding-background .Story-media video {\n height: 97%;\n}\n\n/** padding image-small **/\n.Story--padding-image-small .Story-media {\n padding: 40px 40px 40px 20px;\n}\n\n.Story--padding-image-small .Story-wrapper--reverse .Story-media {\n padding: 40px 60px 40px 20px;\n}\n\n/** padding image-big **/\n.Story--padding-image-big .Story-media {\n padding: 0 60px 0 120px;\n}\n\n.Story--padding-image-big .Story-wrapper--reverse .Story-media {\n padding: 0 140px 0 60px;\n}\n\n/** padding text **/\n.Story--padding-text .Story-text {\n max-width: 500px;\n margin-left: 0;\n margin-right: auto;\n padding: 0 20px 0 60px;\n}\n\n.Story--padding-text .Story-wrapper--reverse .Story-text {\n margin-left: auto;\n margin-right: 0;\n padding: 0 60px 0 20px;\n}\n\n@media (max-width: 767px) {\n .Story.Story--padding-background {\n margin: 10px;\n }\n\n .Story.Story--padding-no-padding-image-mobile .Story-column .Story-media {\n padding: 0;\n margin: -50px -20px 40px;\n }\n\n .Story--padding-no-padding-background .Story-media video {\n width: 100%;\n }\n\n .Story.Story--padding-full-width-image-mobile .Story-column .Story-media {\n margin: -50px -20px 0;\n }\n \n .Story-wrapper {\n flex-direction: column;\n padding: 50px 20px 80px 20px;\n }\n\n .Story .Story-column .Story-media,\n .Story .Story-column .Story-text {\n padding: 0;\n }\n\n .Story--padding-image-small .Story-column .Story-media {\n padding: 0 20px;\n }\n\n .Story-media iframe {\n width: 100%;\n height: 210px;\n }\n\n .Story-title {\n margin: 40px 0 20px;\n font-size: 20px;\n }\n\n .Story-title.big {\n margin: 40px 0 20px;\n font-size: 33px;\n }\n\n .Story-description:last-child {\n margin-bottom: 0;\n }\n\n .Story-logo {\n width: 115px;\n margin-top: 10px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "EssentialProducts", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport ProductImageWithComparisonOnHover from 'Components/ProductImageWithComparisonOnHover'\nimport Link from 'frontend-link'\nimport './styles.css'\n\nconst EssentialProducts = ({ title, products }) => {\n return (\n <div className=\"EssentialProducts\">\n <PageWidth>\n <h2 className=\"EssentialProducts-title\">{title}</h2>\n <div className=\"EssentialProducts-list\">\n {products.map(\n ({\n id,\n image,\n comparisonImageSrc,\n title,\n subtitle,\n alt = '',\n price,\n offPrice,\n offPriceTag,\n url = '',\n }) => (\n <Link key={id} to={url || ''} className=\"EssentialProducts-item\">\n <ProductImageWithComparisonOnHover\n img={image}\n oldImg={comparisonImageSrc}\n alt={alt}\n />\n <div className=\"EssentialProducts-itemMeta\">\n <h3 className=\"EssentialProducts-itemTitle\">{title}</h3>\n <p className=\"EssentialProducts-itemSubtitle\">{subtitle}</p>\n <span\n className={cx('EssentialProducts-itemPrice ', {\n 'is-strikethrough': offPrice,\n })}\n >\n {price}\n </span>\n {offPrice && <span className=\"EssentialProducts-itemPrice\">{offPrice}</span>}\n {offPriceTag && <p className=\"EssentialProducts-itemSaleLabel\">{offPriceTag}</p>}\n </div>\n </Link>\n ),\n )}\n </div>\n </PageWidth>\n </div>\n )\n}\n\nexport default EssentialProducts\n", | |
| "style": ".EssentialProducts {\n padding: 60px 0 80px;\n background-color: #f3f3f3;\n border-top: 1px solid #dedede;\n border-bottom: 1px solid #dedede;\n}\n\n.EssentialProducts-title {\n font-family: Gotham-Bold, sans-serif;\n font-size: 30px;\n margin-bottom: 50px;\n}\n\n.EssentialProducts-list {\n display: grid;\n grid-template-columns: repeat(5, 1fr);\n column-gap: 30px;\n}\n\n.EssentialProducts-item {\n position: relative;\n display: inline-block;\n text-decoration: inherit;\n color: inherit;\n width: 100%;\n padding-top: 100%;\n}\n\n.EssentialProducts-itemMeta {\n text-align: center;\n font-size: 14px;\n padding: 10px 0 6px;\n}\n\n.EssentialProducts-itemTitle {\n font-family: Gotham-Bold, sans-serif;\n font-size: 16px;\n}\n\n.EssentialProducts-itemSubtitle,\n.EssentialProducts-itemPrice {\n font-family: 'Gotham-Book', sans-serif;\n}\n\n.EssentialProducts-itemPrice {\n display: inline-block;\n margin-top: 4px;\n}\n\n.EssentialProducts-itemPrice.is-strikethrough {\n margin-right: 5px;\n text-decoration: line-through;\n}\n\n.EssentialProducts-itemSaleLabel {\n color: #D02D2D;\n font-family: 'Gotham-Bold', sans-serif;\n margin-top: 4px;\n}\n\n@media (max-width: 767px) {\n .EssentialProducts {\n display: none;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "MediaRow", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\nimport useWindowSize from 'react-use/lib/useWindowSize'\n\nimport './styles.css'\n\nconst MediaRow = ({ type, src: srcDesktop, srcMobile, padding, paddingTop, paddingBottom }) => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n\n if (isMobile && !srcMobile) {\n return null\n }\n\n const className = cx('MediaRow', {\n 'MediaRow--padding': padding,\n 'MediaRow--padding-top': paddingTop,\n 'MediaRow--padding-bottom': paddingBottom,\n })\n const src = isMobile ? srcMobile : srcDesktop\n switch (type) {\n case 'img':\n return <ResponsiveImage className={className} src={src} alt=\"mediarow\" />\n case 'video':\n return <video className={className} src={src} autoPlay muted loop playsInline />\n default:\n return null\n }\n}\n\nexport default MediaRow\n", | |
| "style": ".MediaRow {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.MediaRow video {\n pointer-events: none;\n object-fit: contain;\n}\n\n.MediaRow--padding {\n padding: 20px;\n}\n\n.MediaRow--padding-top {\n padding-top: 20px;\n}\n\n.MediaRow--padding-bottom {\n padding-bottom: 20px;\n}\n\n@media (max-width: 767px) {\n .MediaRow--padding {\n padding: 0;\n }\n\n .MediaRow--padding-top {\n padding-top: 5px;\n }\n \n .MediaRow--padding-bottom {\n padding-bottom: 5px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SubCollectionProductList", | |
| "code": "import React, { useEffect, useState, useRef } from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport Button from 'Components/Button'\nimport Pagination from 'Components/Pagination'\nimport ProductImageWithComparisonOnHover from 'Components/ProductImageWithComparisonOnHover'\nimport Link from 'frontend-link'\nimport './styles.css'\n\nconst SubCollectionProductList = ({\n title,\n products = [],\n ctaHref,\n ctaText,\n separator = true,\n withPagination,\n}) => {\n const [currentPage, setCurrentPage] = useState(3)\n const titleRef = useRef()\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.dataLayer === 'undefined') return\n console.log('# SubCollectionProductList # products =>', products)\n\n window.dataLayer.push({\n event: 'collectionView',\n ecommerce: {\n currencyCode: 'USD',\n actionField: { list: 'Collection Page' },\n impressions: products.map((product, position) => ({\n id: product.id,\n name: product.name,\n list: title,\n category: title,\n brand: 'Nomad Goods',\n price: product.minprice,\n position,\n })),\n },\n })\n }, [])\n\n return (\n <div className=\"SubCollectionProductList\">\n <PageWidth>\n <h2 ref={titleRef} className=\"SubCollectionProductList-title\">\n {title}\n </h2>\n\n <ul className=\"SubCollectionProductList-list\">\n {products.map(({\n id,\n offPrice,\n offPriceTag,\n shipDate,\n name,\n images = [],\n minprice,\n slug = '',\n availableforsale,\n tags = [],\n }) => (\n <React.Fragment key={id}>\n {availableforsale && (\n <li className=\"SubCollectionProductList-item\">\n <Link to={slug} className=\"SubCollectionProductList-itemLink\">\n <ProductImageWithComparisonOnHover\n img={(images[0] || []).src}\n oldImg={(images[1] || []).src}\n alt={(images[0] || []).alt}\n />\n <div className=\"SubCollectionProductList-itemMeta\">\n <h3 className=\"SubCollectionProductList-itemTitle\">{name}</h3>\n <p className=\"SubCollectionProductList-itemSubtitle\">\n {getProductSubtitle(tags)}\n </p>\n <span\n className={cx('SubCollectionProductList-itemPrice ', {\n 'is-strikethrough': offPrice,\n })}\n >\n {minprice}\n </span>\n {offPrice && (\n <span className=\"SubCollectionProductList-itemPrice\">{offPrice}</span>\n )}\n {offPriceTag && (\n <p className=\"SubCollectionProductList-itemSaleLabel\">{offPriceTag}</p>\n )}\n {shipDate && (\n <p className=\"SubCollectionProductList-itemShipDate\">{shipDate}</p>\n )}\n </div>\n </Link>\n </li>\n )}\n </React.Fragment>\n ))}\n </ul>\n\n {ctaHref && ctaText && (\n <div className=\"SubCollectionProductList-cta\">\n <Button href={ctaHref} className=\"Btn--default\">\n {ctaText}\n </Button>\n </div>\n )}\n\n {separator && <hr className=\"SubCollectionProductList-separator\" />}\n </PageWidth>\n\n {withPagination && (\n <Pagination\n current={currentPage}\n total={80}\n onChange={setCurrentPage}\n scrollToRef={titleRef}\n />\n )}\n </div>\n )\n}\n\nfunction getProductSubtitle(tags) {\n const key = '_sub_title_'\n const subtitleTag = tags && tags.find(tag => tag.includes(key))\n if (!subtitleTag) return ''\n\n return subtitleTag.replace(key, '')\n}\n\nexport default SubCollectionProductList\n", | |
| "style": ".SubCollectionProductList {\n padding-top: 60px;\n}\n\n.SubCollectionProductList-title {\n font-family: Gotham-Bold, sans-serif;\n font-size: 32px;\n margin-bottom: 40px;\n}\n\n.SubCollectionProductList-list {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n row-gap: 20px;\n column-gap: 30px;\n padding-bottom: 40px;\n}\n\n.SubCollectionProductList-item {\n margin-bottom: 4px;\n}\n\n.SubCollectionProductList-itemLink {\n position: relative;\n display: inline-block;\n text-decoration: inherit;\n color: inherit;\n width: 100%;\n padding-top: 100%;\n}\n\n.SubCollectionProductList-itemMeta {\n font-size: 14px;\n line-height: 1.4;\n padding: 10px 0 6px;\n}\n\n.SubCollectionProductList-itemTitle {\n font-family: Gotham-Bold, sans-serif;\n font-size: 16px;\n font-weight: 400;\n}\n\n.SubCollectionProductList-itemSubtitle,\n.SubCollectionProductList-itemPrice {\n font-family: 'Gotham-Book', sans-serif;\n}\n\n.SubCollectionProductList-itemPrice {\n display: inline-block;\n margin-top: 4px;\n}\n\n.SubCollectionProductList-itemPrice.is-strikethrough {\n margin-right: 5px;\n text-decoration: line-through;\n}\n\n.SubCollectionProductList-itemSaleLabel {\n color: #D02D2D;\n font-family: 'Gotham-Bold', sans-serif;\n margin-top: 4px;\n}\n\n.SubCollectionProductList-itemShipDate {\n color: #848484;\n}\n\n.SubCollectionProductList-cta {\n margin-bottom: 30px;\n}\n\n.SubCollectionProductList-separator {\n background-color: #DEDEDE;\n border: 0;\n height: 1px;\n margin: 0;\n}\n\n@media (max-width: 767px) {\n .SubCollectionProductList {\n padding-top: 40px;\n }\n\n .SubCollectionProductList-title {\n font-size: 26px;\n margin-bottom: 20px;\n }\n\n .SubCollectionProductList-list {\n grid-template-columns: repeat(2, 1fr);\n row-gap: 20px;\n column-gap: 22px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductBox", | |
| "code": "import React, { useEffect } from 'react'\nimport { useHistory, useLocation } from 'react-router-dom'\nimport queryString from 'query-string'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport AddToCart from 'Components/AddToCart'\nimport Carousel from 'Components/Carousel'\nimport Accordions from 'Components/Accordions'\nimport StarRating from 'Components/StarRating'\nimport RichText from 'Components/RichText'\n\nimport './styles.css'\n\nconst ProductBox = ({\n variants = [],\n tags,\n images,\n productId,\n productName,\n reviewsCount,\n reviewsRating,\n tipHTML,\n description,\n info,\n faq,\n}) => {\n console.log('# ProductBox # productName =>', productName)\n console.log('# ProductBox # images =>', images)\n console.log('# ProductBox # variants =>', variants)\n\n const history = useHistory()\n const location = useLocation()\n\n const productSubTitle = getProductSubtitle(tags)\n const accordionItems = [\n {\n title: 'Description',\n content: description,\n },\n {\n title: 'Info',\n content: info,\n },\n {\n title: 'Faq',\n content: faq,\n },\n ]\n\n const variantId = queryString.parse(location.search).variant\n const variant = variants.length ? variants.find(v => v.remote_id == variantId) || variants[0] : []\n\n console.log(variant)\n console.log(images)\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.dataLayer === 'undefined') return\n if (!variant) return\n\n window.dataLayer.push({\n event: 'productDetailView',\n ecommerce: {\n currencyCode: 'USD',\n detail: {\n products: [\n {\n name: productName,\n productId: getRemoteId(productId),\n category: productSubTitle,\n\n id: variant.sku,\n variantId: getRemoteId(variant.id),\n variant: variant.name,\n price: variant.originalPrice,\n compareAtPrice: variant.price,\n inventoryCount: variant.quantity,\n\n brand: 'Nomad Goods',\n },\n ],\n },\n },\n })\n }, [variantId])\n\n const handleVariantClick = v => () => {\n history.push({ search: `?variant=${v.remote_id}` })\n }\n \n return (\n <div className=\"ProductBox\">\n <PageWidth className=\"ProductBox-container\">\n {images && <Carousel images={images} />}\n\n <div className=\"ProductBox-content\">\n <h2 className=\"ProductBox-title\">{productName}</h2>\n <p className=\"ProductBox-desc\">{productSubTitle}</p>\n\n <hr className=\"ProductBox-divider\" />\n\n {variant.originalPrice && variant.originalPrice > variant.price && (\n <span className=\"ProductBox-price is-strikethrough\">${variant.originalPrice}</span>\n )}\n <span className=\"ProductBox-price\">${variant.price}</span>\n\n <div className=\"ProductBox-reviews\">\n {reviewsRating && <StarRating rate={reviewsRating} />}\n {reviewsCount && <p className=\"ProductBox-reviews-count\">{reviewsCount} Reviews</p>}\n </div>\n\n {variant.sale_label && <p className=\"ProductBox-saleLabel\">{variant.sale_label}</p>}\n\n {variants && variants.length > 1 && (\n <div className=\"ProductBox-variants-wrapper\">\n {variants.map(v => (\n <div\n key={v.remote_id}\n className={cx('ProductBox-variant', { active: v === variant })}\n onClick={handleVariantClick(v)}\n >\n ${v.price}\n </div>\n ))}\n </div>\n )}\n\n <AddToCart variantId={variant.id}>Add to Cart</AddToCart>\n\n {tipHTML && (\n <div className=\"ProductBox-tip\">\n <RichText source={tipHTML} />\n </div>\n )}\n\n <Accordions items={accordionItems} />\n </div>\n </PageWidth>\n </div>\n )\n}\n\nfunction getRemoteId(storefrontID) {\n console.log('# ProductBox # storefrontID =>', storefrontID)\n return\n const IdSegments = atob(storefrontID).split('/')\n const lastIdx = IdSegments.length - 1\n\n return IdSegments[lastIdx]\n}\n\nfunction getProductSubtitle(tags) {\n const key = '_sub_title_'\n const subtitleTag = tags && tags.find(tag => tag.includes(key))\n if (!subtitleTag) return ''\n\n return subtitleTag.replace(key, '')\n}\n\nexport default ProductBox\n", | |
| "style": ".ProductBox {\n padding: 60px 0;\n margin-left: -30px;\n background-color: #f3f3f3;\n}\n\n.ProductBox-container {\n display: grid;\n grid-template-columns: 3fr 2fr;\n}\n\n.ProductBox-content {\n margin: 25px 0 0 75px;\n}\n\n.ProductBox-title {\n font-size: 30px;\n}\n\n.ProductBox-desc {\n font-size: 17px;\n font-family: 'Gotham-Book';\n}\n\n.ProductBox-divider {\n margin: 25px 0;\n border: 1px solid #dedede;\n}\n\n.ProductBox-price {\n display: inline-block;\n font-size: 24px;\n font-family: 'Gotham-Bold';\n}\n\n.ProductBox-price.is-strikethrough {\n margin-right: 15px;\n text-decoration: line-through;\n}\n\n.ProductBox-reviews {\n display: flex;\n font-family: 'Gotham-Book';\n font-size: 12px;\n margin-bottom: 25px;\n}\n\n.ProductBox-reviews-count {\n margin-left: 15px;\n}\n\n.ProductBox-saleLabel {\n margin: 15px 0px 25px 0px;\n font-size: 18px;\n font-family: \"Gotham-Bold\";\n padding: 0px;\n color: #d02d2d;\n}\n\n.ProductBox-variants-wrapper {\n margin-bottom: 20px;\n}\n\n.ProductBox-variant {\n position: relative;\n display: inline-block;\n padding: 7px 15px 7px;\n margin: 0 15px 12px 0;\n background-color: #fff;\n cursor: pointer;\n}\n.ProductBox-variant:after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 1px solid #dedede;\n z-index: 1;\n box-sizing: border-box;\n}\n\n.ProductBox-variant.active:after {\n border: 2px solid #000;\n}\n\n.ProductBox-tip {\n margin-top: 20px;\n}\n\n@media (max-width: 767px) {\n .ProductBox {\n padding: 20px 0;\n margin-left: 0;\n }\n\n .ProductBox-container {\n grid-template-columns: 1fr;\n }\n\n .ProductBox-content {\n margin: 20px 0 0;\n }\n\n .ProductBox-desc {\n font-size: 14px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "NotFoundPage", | |
| "code": "import React from 'react'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst NotFoundPage = ({\n backgroundImage,\n title,\n subTitle,\n description,\n ctaHomeHref,\n ctaHomeText,\n ctaSearchHref,\n ctaSearchText,\n ctaHref,\n ctaText,\n}) => {\n return (\n <div className=\"NotFoundPage\" style={{ backgroundImage: `url('${backgroundImage}')` }}>\n <PageWidth>\n <h1 className=\"NotFoundPage-title\">{title}</h1>\n <h2 className=\"NotFoundPage-subTitle\">{subTitle}</h2>\n <p>{description}</p>\n <div>\n {ctaHomeHref && ctaHomeText && (\n <Button to={ctaHomeHref} className=\"Btn--default NotFoundPage-button\">\n {ctaHomeText}\n </Button>\n )}\n {ctaSearchHref && ctaSearchText && (\n <Button to={ctaSearchHref} className=\"Btn--default NotFoundPage-button\">\n {ctaSearchText}\n </Button>\n )}\n </div>\n {ctaHref && ctaText && (\n <Button to={ctaHref} className=\"Btn--default NotFoundPage-lastButton\">\n {ctaText}\n </Button>\n )}\n </PageWidth>\n </div>\n )\n}\n\nexport default NotFoundPage\n", | |
| "style": ".NotFoundPage {\n background: white no-repeat center center;\n background-size: cover;\n min-height: 800px;\n padding-top: 40px;\n}\n\n.NotFoundPage-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 1.7em;\n line-height: 1.6;\n padding: 20px 0 20px;\n}\n\n.NotFoundPage-subTitle {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 1.5em;\n line-height: 1.6;\n padding: 30px 0;\n}\n\n.NotFoundPage-button {\n background-color: #000;\n color: #fff;\n font-size: 0.75em;\n margin: 40px 40px 0 0;\n}\n\n.NotFoundPage-lastButton {\n font-size: 0.75em;\n margin-top: 40px;\n border-width: 1px;\n}\n\n\n.NotFoundPage h2, .NotFoundPage p {\n width: 100%;\n}\n\n@media (min-width: 590px) {\n .NotFoundPage h2, .NotFoundPage p {\n max-width: 500px;\n }\n .NotFoundPage-title {\n font-size: 2em;\n }\n .NotFoundPage-subTitle {\n font-size: 1.75em;\n }\n}\n\n\n@media (min-width: 768px) {\n .NotFoundPage {\n padding-top: 80px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "PageDescription", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport './styles.css'\n\nconst PageDescription = ({ description, title, verticalPadding, grayBackground, large }) => {\n if (!description && !title) return null\n\n return (\n <div\n className={cx(\n 'PageDescription',\n { 'PageDescription-verticalPadding': verticalPadding },\n { 'PageDescription-large': large },\n { 'PageDescription-grayBackground': grayBackground },\n )}\n >\n <PageWidth>\n <div className=\"PageDescription-content\">\n {title && <h3 className=\"PageDescription-title\">{title}</h3>}\n {description && <p className=\"PageDescription-description\">{description}</p>}\n </div>\n </PageWidth>\n </div>\n )\n}\n\nexport default PageDescription\n", | |
| "style": ".PageDescription {\n padding-top: 60px;\n}\n\n.PageDescription-verticalPadding {\n padding-top: 60px;\n padding-bottom: 60px;\n}\n\n.PageDescription-grayBackground {\n background-color: #f3f3f3;\n}\n\n.PageDescription-content {\n max-width: 500px;\n}\n\n.PageDescription-title {\n display: block;\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 1.375rem;\n line-height: 1.6;\n margin-bottom: 1rem;\n}\n\n.PageDescription-large {\n padding-top: 80px;\n padding-bottom: 80px;\n}\n\n@media (max-width: 767px) {\n .PageDescription {\n padding-top: 40px;\n }\n\n .PageDescription-title {\n font-size: 1.125rem;\n }\n \n .PageDescription-large {\n padding: 60px 0 20px 0;\n }\n}\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "PageTitleHero", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst PageTitleHero = ({\n image,\n title,\n subtitle,\n compact,\n centerBackground,\n dark = false,\n gradient = false,\n}) => {\n if (!image && !title && !subtitle) return (\n <div className=\"PageTitleHero-empty\"></div>\n )\n\n return (\n <div className={cx('PageTitleHero', { 'PageTitleHero--compact': compact })}>\n <div\n className={cx('PageTitleHero-image', { 'PageTitleHero-image--center': centerBackground })}\n style={{ backgroundImage: `url('${image}')` }}\n >\n <div\n className={cx('PageTitleHero-effect', {\n 'PageTitleHero-effect--dark': dark,\n 'PageTitleHero-effect--gradient': gradient,\n })}\n >\n <PageWidth className=\"PageTitleHero-content\">\n {title && <h1 className=\"PageTitleHero-title\">{title}</h1>}\n {subtitle && <h2 className=\"PageTitleHero-subtitle\">{subtitle}</h2>}\n </PageWidth>\n </div>\n </div>\n </div>\n )\n}\n\nexport default PageTitleHero\n", | |
| "style": ".PageTitleHero {\n width: 100%;\n height: 550px;\n position: relative;\n}\n\n.PageTitleHero-empty {\n background-color: #000;\n height: 60px;\n position: fixed;\n width: 100%;\n}\n\n.PageTitleHero-image {\n background-repeat: no-repeat;\n background-position: 50% 0;\n background-size: cover;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n opacity: 1;\n}\n\n.PageTitleHero-image--center {\n background-position: 50% 50%;\n}\n\n.PageTitleHero-content {\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n align-items: flex-start;\n color: #fff;\n height: 100%;\n}\n\n.PageTitleHero-title {\n font-size: 70px;\n font-family: 'Gotham-Bold';\n line-height: 1.1;\n}\n\n.PageTitleHero-title:last-child {\n margin-bottom: 60px;\n}\n\n.PageTitleHero-subtitle {\n font-size: 33px;\n font-family: 'Gotham-Book';\n margin-bottom: 60px;\n}\n\n.PageTitleHero-effect {\n width: 100%;\n height: 100%;\n}\n\n.PageTitleHero-effect--gradient {\n background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 40%, rgba(0, 0, 0, 0.5) 100%);\n}\n\n.PageTitleHero-effect--dark:before {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n opacity: 1;\n background: rgba(0, 0, 0, 0.25);\n}\n\n.PageTitleHero--compact {\n height: 360px;\n}\n\n.PageTitleHero--compact .PageTitleHero-content {\n padding-bottom: 10px;\n}\n\n.PageTitleHero--compact .PageTitleHero-title {\n font-size: 60px;\n}\n\n.PageTitleHero--compact .PageTitleHero-title:last-child {\n margin-bottom: 20px;\n}\n\n.PageTitleHero--compact .PageTitleHero-subtitle {\n font-size: 30px;\n margin-bottom: 20px;\n}\n\n@media (max-width: 767px) {\n .PageTitleHero {\n height: 330px;\n }\n\n .PageTitleHero-empty {\n height: 40px;\n }\n\n .PageTitleHero-title {\n font-size: 40px;\n }\n\n .PageTitleHero-title:last-child {\n margin-bottom: 27px;\n }\n\n .PageTitleHero-subtitle {\n font-size: 22px;\n margin-bottom: 27px;\n }\n\n .PageTitleHero--compact {\n height: 200px;\n }\n\n .PageTitleHero--compact .PageTitleHero-content {\n padding-bottom: 10px;\n }\n\n .PageTitleHero--compact .PageTitleHero-title {\n font-size: 36px;\n }\n\n .PageTitleHero--compact .PageTitleHero-title:last-child {\n margin-bottom: 10px;\n }\n\n .PageTitleHero--compact .PageTitleHero-subtitle {\n font-size: 22px;\n margin-bottom: 10px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductImageComparisonSlider", | |
| "code": "import React, { useEffect, useRef, useState } from 'react'\nimport { ResizeSensor } from 'css-element-queries'\nimport { ResponsiveImage } from 'frontend-ui'\n\nimport './styles.css'\n\nconst HANDLE_SIZE = 44\nconst LINE_WIDTH = 2\n\nconst ProductImageComparisonSlider = ({ src, comparisonSrc }) => {\n const [sliderPosition, setSliderPosition] = useState(0.5)\n const [containerWidth, setContainerWidth] = useState(0)\n const [containerHeight, setContainerHeight] = useState(0)\n const [leftImgLoaded, setLeftImgLoaded] = useState(false)\n const [rightImgLoaded, setRightImgLoaded] = useState(false)\n\n const containerRef = useRef()\n const rightImageRef = useRef()\n const leftImageRef = useRef()\n\n useEffect(() => {\n const updateContainerWidth = () => {\n const currentContainerWidth = containerRef.current.getBoundingClientRect().width\n setContainerWidth(currentContainerWidth)\n }\n\n updateContainerWidth()\n\n const containerElement = containerRef.current\n const resizeSensor = new ResizeSensor(containerElement, () => {\n updateContainerWidth()\n })\n\n return () => {\n resizeSensor.detach(containerElement)\n }\n }, [])\n\n useEffect(() => {\n const alreadyDone = leftImageRef.current.complete\n alreadyDone && setLeftImgLoaded(true)\n\n return () => {\n setLeftImgLoaded(false)\n }\n }, [src])\n\n useEffect(() => {\n const alreadyDone = rightImageRef.current.complete\n alreadyDone && setRightImgLoaded(true)\n\n return () => {\n setRightImgLoaded(false)\n }\n }, [comparisonSrc])\n\n const allImagesLoaded = rightImgLoaded && leftImgLoaded\n\n useEffect(() => {\n const handleSliding = event => {\n const e = event || window.event\n\n const cursorXfromViewport = e.touches ? e.touches[0].pageX : e.pageX\n const cursorXfromWindow = cursorXfromViewport - window.pageXOffset\n const imagePosition = rightImageRef.current.getBoundingClientRect()\n let pos = cursorXfromWindow - imagePosition.left\n\n const minPos = 0 + LINE_WIDTH / 2\n const maxPos = containerWidth - LINE_WIDTH / 2\n\n if (pos < minPos) pos = minPos\n if (pos > maxPos) pos = maxPos\n\n setSliderPosition(pos / containerWidth)\n }\n\n const startSliding = e => {\n if (!('touches' in e)) {\n e.preventDefault()\n }\n\n handleSliding(e)\n\n window.addEventListener('mousemove', handleSliding)\n window.addEventListener('touchmove', handleSliding)\n }\n\n const finishSliding = () => {\n window.removeEventListener('mousemove', handleSliding)\n window.removeEventListener('touchmove', handleSliding)\n }\n\n const containerElement = containerRef.current\n\n if (allImagesLoaded) {\n containerElement.addEventListener('touchstart', startSliding)\n window.addEventListener('touchend', finishSliding)\n\n containerElement.addEventListener('mousedown', startSliding)\n window.addEventListener('mouseup', finishSliding)\n\n const leftImageWidthHeightRatio =\n leftImageRef.current.naturalHeight / leftImageRef.current.naturalWidth\n const rightImageWidthHeightRatio =\n rightImageRef.current.naturalHeight / rightImageRef.current.naturalWidth\n\n const idealWidthHeightRatio = Math.max(leftImageWidthHeightRatio, rightImageWidthHeightRatio)\n\n const idealContainerHeight = containerWidth * idealWidthHeightRatio\n\n setContainerHeight(idealContainerHeight)\n }\n\n return () => {\n containerElement.removeEventListener('touchstart', startSliding)\n window.removeEventListener('touchend', finishSliding)\n containerElement.removeEventListener('mousemove', handleSliding)\n containerElement.removeEventListener('mouseleave', finishSliding)\n containerElement.removeEventListener('mousedown', startSliding)\n window.removeEventListener('mouseup', finishSliding)\n window.removeEventListener('mousemove', handleSliding)\n window.removeEventListener('touchmove', handleSliding)\n }\n }, [allImagesLoaded, containerHeight, containerWidth])\n\n return (\n <div\n className=\"ProductImageComparisonSlider-container\"\n ref={containerRef}\n style={{\n height: `${containerHeight}px`,\n display: allImagesLoaded ? 'block' : 'none',\n }}\n >\n <ResponsiveImage\n className=\"ProductImageComparisonSlider-image\"\n ref={rightImageRef}\n src={comparisonSrc}\n style={{\n clip: `rect(auto, auto, auto, ${containerWidth * sliderPosition}px)`,\n }}\n onLoad={() => setRightImgLoaded(true)}\n />\n <ResponsiveImage\n className=\"ProductImageComparisonSlider-image\"\n ref={leftImageRef}\n src={src}\n style={{\n clip: `rect(auto, ${containerWidth * sliderPosition}px, auto, auto)`,\n }}\n onLoad={() => setLeftImgLoaded(true)}\n />\n <div\n className=\"ProductImageComparisonSlider-slider\"\n style={{ left: `${containerWidth * sliderPosition - HANDLE_SIZE / 2}px` }}\n >\n <div className=\"ProductImageComparisonSlider-line\" />\n <span className=\"ProductImageComparisonSlider-handle\" />\n <div className=\"ProductImageComparisonSlider-line\" />\n </div>\n </div>\n )\n}\n\nexport default ProductImageComparisonSlider\n", | |
| "style": ".ProductImageComparisonSlider-container {\n position: relative;\n width: 100%;\n box-sizing: border-box;\n overflow: hidden;\n}\n\n.ProductImageComparisonSlider-image {\n position: absolute;\n display: block;\n height: 100%;\n width: 100%;\n object-fit: cover;\n}\n\n.ProductImageComparisonSlider-slider {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n position: absolute;\n top: 0;\n width: 44px;\n height: 100%;\n}\n\n.ProductImageComparisonSlider-line {\n flex: 0 1 auto;\n height: 100%;\n width: 2px;\n background: black;\n}\n\n.ProductImageComparisonSlider-handle {\n flex: 1 0 auto;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n background: #000 url(https://cdn.shopify.com/s/files/1/0384/6721/files/cd-arrows.svg) no-repeat center center;\n cursor: move;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartDrawer", | |
| "code": "import React, { useEffect } from 'react'\nimport AppearAnimation from 'Components/AppearAnimation'\nimport CheckoutButton from 'Components/CheckoutButton'\nimport CartDrawerHeader from 'Components/CartDrawerHeader'\nimport CartDrawerItem from 'Components/CartDrawerItem'\nimport CartSubtotal from 'Components/CartSubtotal'\n\nimport { useCart } from 'frontend-checkout'\n\nimport './styles.css'\n\nconst STAGGERING_ANIMATION_DELAY = 75\n\nconst CartDrawer = () => {\n const [{ items, isCartShown, cart }, { hideCart, getProductTrackingData }] = useCart()\n\n useEffect(() => {\n document.body.style.overflow = isCartShown ? 'hidden' : 'unset'\n if (typeof window === 'undefined' || typeof window.dataLayer === 'undefined' || !isCartShown)\n return\n window.dataLayer.push({\n ecommerce: {\n currencyCode: cart.currencyCode,\n actionField: { list: 'Shopping Cart' },\n impressions: items.map((item, position) => ({\n position,\n ...getProductTrackingData(item),\n })),\n },\n })\n }, [isCartShown])\n\n return (\n <>\n <div className={`CartDrawer-overlay ${isCartShown ? 'CartDrawer-overlay--active' : ''}`} />\n <div className={`CartDrawer-container ${isCartShown ? 'CartDrawer-main--opened' : ''}`}>\n {isCartShown && (\n <>\n <AppearAnimation>\n <CartDrawerHeader isCartShown={isCartShown} hideCart={hideCart} />\n </AppearAnimation>\n {items.length > 0 ? (\n <>\n <ul className=\"CartDrawer-itemsContainer\">\n {items.map((item, i) => (\n <AppearAnimation\n key={item.id}\n as=\"li\"\n delayInMs={(i + 1) * STAGGERING_ANIMATION_DELAY}\n >\n <CartDrawerItem item={item} animationOrderNumber={i + 1} />\n </AppearAnimation>\n ))}\n </ul>\n <AppearAnimation delayInMs={2 * STAGGERING_ANIMATION_DELAY}>\n <CartSubtotal\n inDrawer\n subtotalPrice={cart.subtotalPrice}\n currencyCode={cart.currencyCode}\n />\n <CheckoutButton>Checkout</CheckoutButton>\n </AppearAnimation>\n </>\n ) : (\n <AppearAnimation delayInMs={STAGGERING_ANIMATION_DELAY}>\n Your cart is currently empty.\n </AppearAnimation>\n )}\n </>\n )}\n </div>\n </>\n )\n}\n\nexport default CartDrawer\n", | |
| "style": ".CartDrawer-overlay {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1000;\n background: #aeb1b8;\n opacity: 0;\n transition: opacity 0.3 linear;\n pointer-events: none;\n}\n\n.CartDrawer-overlay--active {\n opacity: 0.6;\n}\n\n.CartDrawer-container {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n display: flex;\n flex-direction: column;\n transform: translateX(400px);\n z-index: 2000;\n width: 400px;\n padding: 0 40px 40px;\n background: #f3f3f3;\n transition: transform 0.3s cubic-bezier(0.165, 0.84, 0.44, 1);\n}\n\n.CartDrawer-main--opened {\n transform: translateX(0px);\n}\n\n.CartDrawer-itemsContainer {\n padding: 0 40px 20px;\n border-bottom: 1px solid #dedede;\n flex: 1;\n overflow: auto;\n margin: 0 -40px;\n}\n\n.CartDrawer-itemsContainer > li:not(:last-child) {\n border-bottom: 1px solid #dedede;\n}\n\n@media (max-width: 767px) {\n .CartDrawer-container {\n width: 300px;\n }\n\n .CartDrawer-container {\n padding: 0 20px 20px;\n }\n\n .CartDrawer-itemsContainer {\n padding: 0 20px;\n margin: 0 -20px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ItemQuantityInput", | |
| "code": "import React from 'react'\nimport { useCartActions } from 'frontend-checkout'\n\nimport './styles.css'\n\nconst IDLE = 'idle'\nconst LOADING = 'loading'\n\nconst ItemQuantityInput = ({ itemId, variantId, quantity = 0, onRemove, onUpdate }) => {\n const [inputState, setInputState] = React.useState(IDLE)\n const [inputValue, setInputValue] = React.useState(quantity)\n const { updateItem, removeItem } = useCartActions()\n\n React.useEffect(\n function syncQuantityPropWithInputValue() {\n if (quantity !== inputValue) {\n setInputValue(quantity)\n }\n },\n [quantity, setInputValue],\n )\n\n async function handleItemQuantityChange(requestedQtyChange) {\n const newQuantity = quantity + requestedQtyChange\n\n if (newQuantity === quantity) return\n\n setInputState(LOADING)\n try {\n if (newQuantity <= 0) {\n await removeItem({ itemId })\n\n if (onRemove) onRemove()\n } else {\n await updateItem({ itemId: variantId, quantity: requestedQtyChange })\n setInputState(IDLE)\n\n if (onUpdate) onUpdate(requestedQtyChange)\n }\n } catch (e) {\n setInputValue(quantity)\n setInputState(IDLE)\n }\n }\n\n const inputRef = React.useRef(null)\n const handleKeyPress = event => {\n if (event.key === 'Enter') {\n inputRef.current && inputRef.current.blur()\n }\n }\n\n return (\n <div className=\"ItemQuantityInput\">\n <label htmlFor={`adjust_quantity_${itemId}`} className=\"visually-hidden\">\n Quantity\n </label>\n <button\n className=\"ItemQuantityInput-btn ItemQuantityInput-btn-minus\"\n type=\"button\"\n disabled={inputState === LOADING}\n aria-label=\"Reduce item quantity by one\"\n onClick={() => handleItemQuantityChange(-1)}\n >\n -\n </button>\n <input\n type=\"number\"\n id={`adjust_quantity_${itemId}`}\n className=\"ItemQuantityInput-input\"\n disabled={inputState === LOADING}\n min={0}\n value={inputValue}\n ref={inputRef}\n onKeyPress={handleKeyPress}\n onChange={e => setInputValue(e.target.value)}\n onBlur={e => handleItemQuantityChange(Number(e.target.value) - quantity)}\n />\n <button\n className=\"ItemQuantityInput-btn ItemQuantityInput-btn-plus\"\n type=\"button\"\n disabled={inputState === LOADING}\n label=\"Increase item quantity by one\"\n onClick={() => handleItemQuantityChange(1)}\n >\n +\n </button>\n </div>\n )\n}\n\nexport default ItemQuantityInput\n", | |
| "style": ".ItemQuantityInput {\n display: flex;\n max-width: 80px;\n border: 1px solid #dedede;\n}\n\n.ItemQuantityInput-input {\n width: 100%;\n max-width: 36px;\n min-width: 32px;\n text-align: center;\n background: transparent;\n border: none;\n}\n\n/* Removing default browsers number input up and down buttons,\nsince we are using custom ones */\n.ItemQuantityInput-input::-webkit-inner-spin-button,\n.ItemQuantityInput-input::-webkit-outer-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\ninput[type='number'] {\n -moz-appearance: textfield;\n}\n\n.ItemQuantityInput-btn {\n background: transparent;\n border: none;\n font-size: 1.3rem;\n line-height: 1;\n padding: 5px;\n user-select: none;\n cursor: pointer;\n transition: all 0.2s ease-out;\n}\n\n.ItemQuantityInput-btn-minus {\n border-right: 1px solid #dedede;\n}\n\n.ItemQuantityInput-btn-plus {\n border-left: 1px solid #dedede;\n}\n\n.ItemQuantityInput-btn:active {\n color: #f3f3f3;\n background: #000000;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .ItemQuantityInput-btn:hover {\n color: #f3f3f3;\n background: #000000;\n }\n\n .ItemQuantityInput-btn:active {\n color: #000000;\n background: #c5c5c5;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Pagination", | |
| "code": "import React, { cloneElement, useRef } from 'react'\nimport cx from 'classnames'\nimport Icons from 'Components/Icons'\nimport './styles.css'\n\nconst Pager = ({ page, active, onClick }) => (\n <li\n className={cx('Pagination-item', { 'Pagination-item-active': active })}\n onClick={() => onClick(page)}\n >\n {page}\n </li>\n)\n\nconst Pagination = ({ current = 1, countPerPage = 10, total, onChange, scrollToRef }) => {\n const paginationNode = useRef()\n const totalPages = Math.floor((total - 1) / countPerPage) + 1\n const pageBufferSize = 1\n const hasPrev = current > 1\n const hasNext = current < totalPages\n\n if (total <= countPerPage) return null\n\n const handleChange = p => {\n if (p === current) return\n\n let page = p\n if (page > totalPages) {\n page = totalPages\n } else if (page < 1) {\n page = 1\n }\n\n onChange(page)\n\n if (scrollToRef) {\n const { top } = scrollToRef.current.getBoundingClientRect()\n window.scrollBy({\n top: top - 60,\n behavior: 'smooth',\n })\n return\n }\n\n window.scrollTo({\n top: scrollTo || 0,\n behavior: 'smooth',\n })\n }\n\n const jumpPrev = () => {\n const prevPage = Math.max(1, current - 3)\n handleChange(prevPage)\n }\n\n const jumpNext = () => {\n const nextPage = Math.min(totalPages, current + 3)\n handleChange(nextPage)\n }\n\n const pagerList = []\n\n if (totalPages <= 3 + pageBufferSize * 2) {\n for (let i = 1; i <= totalPages; i += 1) {\n const active = current === i\n pagerList.push(<Pager key={i} page={i} active={active} onClick={handleChange} />)\n }\n } else {\n let left = Math.max(1, current - pageBufferSize)\n let right = Math.min(current + pageBufferSize, totalPages)\n\n if (current - 1 <= pageBufferSize) {\n right = 1 + pageBufferSize * 2\n }\n\n if (totalPages - current <= pageBufferSize) {\n left = totalPages - pageBufferSize * 2\n }\n\n for (let i = left; i <= right; i += 1) {\n const active = current === i\n pagerList.push(<Pager key={i} page={i} active={active} onClick={handleChange} />)\n }\n\n if (current - 1 >= pageBufferSize * 2 && current !== 1 + 2) {\n pagerList[0] = cloneElement(pagerList[0])\n const jumpPrevNode = (\n <li key={-1} onClick={jumpPrev} className=\"Pagination-jump-prev\">\n <span>…</span>\n </li>\n )\n pagerList.unshift(jumpPrevNode)\n }\n if (totalPages - current >= pageBufferSize * 2 && current !== totalPages - 2) {\n pagerList[pagerList.length - 1] = cloneElement(pagerList[pagerList.length - 1])\n const jumpNextNode = (\n <li key={-2} onClick={jumpNext} className=\"Pagination-jump-next\">\n <span>…</span>\n </li>\n )\n pagerList.push(jumpNextNode)\n }\n\n if (left !== 1) {\n const firstPager = <Pager key={1} page={1} onClick={handleChange} />\n pagerList.unshift(firstPager)\n }\n if (right !== totalPages) {\n const lastPager = <Pager key={totalPages} page={totalPages} onClick={handleChange} />\n pagerList.push(lastPager)\n }\n }\n\n return (\n <ul className=\"Pagination\" ref={paginationNode}>\n {hasPrev && (\n <li className=\"Pagination-prev\" onClick={() => handleChange(current - 1)}>\n <Icons name=\"BtnPrev\" white xs />\n </li>\n )}\n {pagerList}\n {hasNext && (\n <li className=\"Pagination-next\" onClick={() => handleChange(current + 1)}>\n <Icons name=\"BtnNext\" white xs />\n </li>\n )}\n </ul>\n )\n}\n\nexport default Pagination\n", | |
| "style": ".Pagination {\n display: flex;\n justify-content: center;\n font-size: 0.9375em;\n}\n\n.Pagination-item {\n cursor: pointer;\n width: 45px;\n height: 45px;\n text-align: center;\n line-height: 45px;\n}\n\n.Pagination-item-active {\n opacity: 0.3;\n}\n\n.Pagination-jump-prev,\n.Pagination-jump-next {\n display: flex;\n align-items: center;\n cursor: pointer;\n}\n\n.Pagination-prev,\n.Pagination-next {\n display: flex;\n justify-content: center;\n align-items: center;\n background: #111;\n width: 45px;\n height: 45px;\n border-radius: 50%;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CollectionStickySubCollectionSelector", | |
| "code": "import React, { useEffect, useState } from 'react'\nimport useWindowScroll from 'react-use/lib/useWindowScroll'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst LIST_TOP_SPACING = 100\nconst PAGE_TOP_SPACING = 400\n\nconst CollectionStickySubCollectionSelector = ({ selector = '' }) => {\n let [showFilter, setShowFilter] = useState(false)\n let [showDropdown, setShowDropdown] = useState(false)\n const [productList, setProductList] = useState([])\n let [productSelected, setProductSelected] = useState('')\n\n useEffect(() => {\n if (!selector) return\n\n const pList = Array.from(document.querySelectorAll(`.${selector}`), el => ({\n label: el.querySelector(`.${selector}-title`).innerText,\n topHeight: el.offsetTop,\n }))\n setProductList(pList)\n }, [])\n\n const selectItem = topHeight => () => {\n if (typeof window === 'undefined') return\n\n window.scrollTo({\n top: topHeight - LIST_TOP_SPACING,\n behavior: 'smooth',\n })\n }\n\n const { y: pageYOffset } = useWindowScroll()\n useEffect(() => {\n if (PAGE_TOP_SPACING > pageYOffset) {\n setShowDropdown(false)\n setShowFilter(false)\n setProductSelected(null)\n return\n }\n\n let productSelected\n productList.forEach(({ label, topHeight }) => {\n if (topHeight - LIST_TOP_SPACING < pageYOffset) productSelected = label\n })\n\n setShowDropdown(false)\n setShowFilter(!!productSelected)\n setProductSelected(productSelected)\n }, [pageYOffset])\n\n return (\n <div\n className={cx('CollectionStickySubCollectionSelector', {\n 'is-visible': showFilter,\n 'is-open': showDropdown,\n })}\n onMouseLeave={() => setShowDropdown(false)}\n >\n <PageWidth>\n <div\n className=\"CollectionStickySubCollectionSelector-trigger\"\n onMouseEnter={() => setShowDropdown(true)}\n >\n {productSelected}\n </div>\n <ul className=\"CollectionStickySubCollectionSelector-list\">\n {productList.map(({ label, topHeight }) => (\n <li key={topHeight} className=\"CollectionStickySubCollectionSelector-item\">\n <button type=\"button\" onClick={selectItem(topHeight)}>\n {label}\n </button>\n </li>\n ))}\n </ul>\n </PageWidth>\n </div>\n )\n}\n\nexport default CollectionStickySubCollectionSelector\n", | |
| "style": ".CollectionStickySubCollectionSelector {\n background-color: rgba(0, 0, 0, 0.75);\n color: #FFF;\n position: fixed;\n top: -65px;\n left: 0;\n transition: top 0.5s ease;\n width: 100%;\n}\n\n.CollectionStickySubCollectionSelector.is-visible {\n top: 60px;\n z-index: 1;\n}\n\n.CollectionStickySubCollectionSelector-list {\n background-color: #FFF;\n box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.09);\n color: #000;\n left: 0;\n margin: 0;\n min-width: 225px;\n padding: 30px 35px;\n position: absolute;\n opacity: 0;\n pointer-events: none;\n transform: translate3d(-10px, 0, 0);\n transition: all 250ms;\n}\n\n.CollectionStickySubCollectionSelector-trigger {\n position: relative;\n display: inline-block;\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 17px;\n padding: 8px 55px 8px 35px;\n margin-left: -40px;\n transition: all .25s;\n}\n\n.CollectionStickySubCollectionSelector-trigger:after {\n content: '';\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 40px;\n background-size: 10px;\n margin-right: 15px;\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/t/110/assets/ico-select-white.svg?v=12333309450058243960);\n background-repeat: no-repeat;\n background-position: center center;\n}\n\n.CollectionStickySubCollectionSelector-item button {\n position: relative;\n padding-bottom: 5px;\n margin-bottom: 10px;\n cursor: pointer;\n outline: none;\n}\n\n.CollectionStickySubCollectionSelector-item button:after {\n border-bottom: 2px solid black;\n content: '';\n display: block;\n position: absolute;\n box-sizing: border-box;\n width: 0%;\n height: 0;\n bottom: 3px;\n transition: width 0.5s ease;\n}\n\n.CollectionStickySubCollectionSelector-item button:hover:after {\n width: calc(100% - 5px);\n}\n\n.CollectionStickySubCollectionSelector.is-open .CollectionStickySubCollectionSelector-list {\n pointer-events: initial;\n opacity: 1;\n transform: translate3d(0, 0, 0);\n}\n\n.CollectionStickySubCollectionSelector.is-open .CollectionStickySubCollectionSelector-trigger {\n background-color: #FFF;\n border-bottom: 1px solid #e4e4e4;\n color: #000;\n}\n.CollectionStickySubCollectionSelector.is-open .CollectionStickySubCollectionSelector-trigger:after {\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/t/110/assets/ico-select.svg?v=12971857141580430712);\n}\n\n@media (max-width: 768px) {\n .CollectionStickySubCollectionSelector {\n top: -45px;\n }\n\n .CollectionStickySubCollectionSelector.is-visible {\n top: 40px;\n }\n\n .CollectionStickySubCollectionSelector-trigger {\n font-size: 17px;\n padding: 8px 40px 8px 20px;\n margin-left: -20px;\n }\n\n .CollectionStickySubCollectionSelector-trigger:after {\n margin-right: 10px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ImageMagnifier", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport ReactInputPosition, { TOUCH_ACTIVATION, MOUSE_ACTIVATION } from 'react-input-position'\nimport './styles.css'\n\nconst ImageRenderer = ({\n imageSrc,\n largeImageSrc,\n imageAlt,\n active,\n itemRef,\n itemPosition: { x, y },\n elementDimensions: { width, height },\n itemDimensions,\n}) => {\n const legalSize = itemDimensions.width > width\n const cursor = !legalSize ? 'default' : active ? 'zoom-out' : 'zoom-in'\n const transform = `translate(${x}px, ${y}px)`\n const visibility = legalSize && active ? 'visible' : 'hidden'\n\n return (\n <div className=\"ImageMagnifier-container\" style={{ cursor }}>\n <ResponsiveImage className=\"ImageMagnifier-default\" src={imageSrc} alt={imageAlt} />\n <div\n className=\"ImageMagnifier-zoom-container\"\n style={{ width: `${width}px`, height: `${height}px` }}\n >\n <ResponsiveImage\n ref={itemRef}\n className=\"ImageMagnifier-large-image\"\n style={{ transform, visibility }}\n src={largeImageSrc || imageSrc}\n loading=\"lazy\"\n alt={imageAlt}\n />\n </div>\n </div>\n )\n}\n\nconst ImageMagnifier = ({ imageSrc, largeImageSrc, imageAlt }) => (\n <ReactInputPosition\n touchActivationMethod={TOUCH_ACTIVATION.TAP}\n mouseActivationMethod={MOUSE_ACTIVATION.CLICK}\n trackItemPosition\n alignItemOnActivePos\n itemPositionLimitBySize\n >\n <ImageRenderer imageSrc={imageSrc} largeImageSrc={largeImageSrc} imageAlt={imageAlt} />\n </ReactInputPosition>\n)\n\nexport default ImageMagnifier\n", | |
| "style": ".ImageMagnifier-container {\n position: relative;\n padding-bottom: 100%;\n height: 0;\n}\n\n.ImageMagnifier-default {\n display: block;\n width: 100%;\n}\n\n.ImageMagnifier-zoom-container {\n position: absolute;\n top: 0;\n left: 0;\n box-sizing: border-box;\n pointer-events: none;\n overflow: hidden;\n}\n\n.ImageMagnifier-large-image {\n position: absolute;\n top: 0;\n left: 0;\n width: auto;\n box-sizing: border-box;\n display: block;\n z-index: 1;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "RichText", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\n\nimport PageWidth from 'Components/PageWidth'\nimport './styles.css'\n\nconst RichText = ({ source, pageWidth, marginTop, seperator }) => {\n if (pageWidth) {\n return (\n <PageWidth\n className={cx('RichText', {\n 'RichText--marginTop': marginTop,\n 'RichText--seperator': seperator,\n })}\n dangerouslySetInnerHTML={{ __html: source }}\n />\n )\n }\n\n return (\n <div\n className={cx('RichText', {\n 'RichText--marginTop': marginTop,\n 'RichText--seperator': seperator,\n })}\n dangerouslySetInnerHTML={{ __html: source }}\n />\n )\n}\n\nexport default RichText\n", | |
| "style": ".RichText--marginTop {\n margin-top: 80px;\n}\n\n.RichText--seperator {\n padding-bottom: 80px;\n margin-bottom: 100px;\n border-bottom: 1px solid #dedede;\n}\n\n.RichText a {\n position: relative;\n color: #000;\n text-decoration: none;\n border-bottom: 2px solid rgba(0, 0, 0, 0.1);\n}\n.RichText a::after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 0%;\n border-bottom: 2px solid #000;\n transition: width 0.5s ease;\n}\n.RichText a:hover::after {\n width: 100%;\n}\n\n.RichText h3 {\n font-family: 'Gotham-Bold';\n font-size: 1.375em;\n}\n\n.RichText h4 {\n font-family: 'Gotham-Bold';\n font-size: 1.125em;\n}\n\n.RichText h5 {\n font-family: 'Gotham-Bold';\n font-size: 1em;\n}\n\n.RichText h1,\n.RichText .h1,\n.RichText h2,\n.RichText .h2,\n.RichText h3,\n.RichText .h3,\n.RichText h4,\n.RichText .h4,\n.RichText h5,\n.RichText .h5,\n.RichText h6,\n.RichText .h6 {\n margin-top: 2.5em;\n margin-bottom: 1em;\n}\n\n.RichText h1:first-child,\n.RichText .h1:first-child,\n.RichText h2:first-child,\n.RichText .h2:first-child,\n.RichText h3:first-child,\n.RichText .h3:first-child,\n.RichText h4:first-child,\n.RichText .h4:first-child,\n.RichText h5:first-child,\n.RichText .h5:first-child,\n.RichText h6:first-child,\n.RichText .h6:first-child {\n margin-top: 0;\n}\n\n.RichText p {\n margin-bottom: 10px;\n}\n\n.RichText ul {\n margin: 0 0 20px 10px;\n padding-inline-start: 35px;\n list-style-type: square;\n}\n\n@media (max-width: 767px) {\n .RichText h3 {\n font-size: 1.125em;\n margin-top: 2.5em;\n }\n .RichText h4 {\n font-size: 1em;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Button", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport Link from 'frontend-link'\n\nimport './styles.css'\n\nconst Button = ({ children, as = Link, className = '', ...restProps }) => {\n const Component = as\n\n return (\n <Component className={cx('Btn', className)} {...restProps}>\n {children}\n </Component>\n )\n}\n\nexport default Button\n", | |
| "style": ".Btn {\n display: inline-block;\n font-family: 'Gotham-Bold';\n font-size: 14px;\n padding: 8px 30px;\n line-height: 1.42;\n}\n\n.Btn,\n.Btn:hover,\n.Btn:active,\n.Btn:visited {\n text-decoration: none;\n}\n\n.Btn--default {\n color: #000;\n border: 2px solid #000;\n}\n\n.Btn--inverted {\n color: #fff;\n border: 2px solid #fff;\n}\n\n.Btn--hero {\n padding: 10px 22px;\n font-size: 18px;\n line-height: 1;\n border-width: 1px;\n}\n\n.Btn--add-to-cart {\n display: block;\n\n width: 100%;\n height: 48px;\n line-height: 24px;\n text-align: center;\n\n background: black;\n color: white !important;\n}\n\n.Btn--black {\n padding: 9px 20px;\n font-size: 1em;\n line-height: 1.6;\n min-width: 90px;\n color: #FFF;\n background-color: #000;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductStickyAddToCart", | |
| "code": "import React, { useEffect, useState } from 'react'\nimport useWindowScroll from 'react-use/lib/useWindowScroll'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport AddToCart from 'Components/AddToCart'\n\nimport './styles.css'\n\nconst ProductStickyAddToCart = ({ selector, variantId }) => {\n let [showFilter, setShowFilter] = useState(false)\n const [productDetail, setProductDetail] = useState({})\n\n useEffect(() => {\n const el = document.querySelector(`.${selector}`)\n const detail = {\n title: el.querySelector(`.${selector}-title`).innerText,\n desc: el.querySelector(`.${selector}-desc`).innerText,\n price: el.querySelector(`.${selector}-price`).innerText,\n triggerPoint: el.querySelector('.AddToCart-btn').offsetTop,\n }\n setProductDetail(detail)\n }, [])\n\n const { y: pageYOffset } = useWindowScroll()\n useEffect(() => {\n setShowFilter(productDetail.triggerPoint < pageYOffset)\n }, [pageYOffset])\n\n return (\n <div className={cx('ProductStickyAddToCart', { 'is-visible': showFilter })}>\n <PageWidth className=\"ProductStickyAddToCart-container\">\n <div className=\"ProductStickyAddToCart-detail\">\n <h3 className=\"ProductStickyAddToCart-title\">{productDetail.title}</h3>\n <h5 className=\"ProductStickyAddToCart-desc\">\n {productDetail.desc} - {productDetail.price}\n </h5>\n </div>\n <AddToCart className=\"ProductStickyAddToCart-btn\" variantId={variantId}>\n Add to Cart\n </AddToCart>\n </PageWidth>\n </div>\n )\n}\n\nexport default ProductStickyAddToCart\n", | |
| "style": ".ProductStickyAddToCart {\n background-color: rgba(0, 0, 0, 0.75);\n color: #FFF;\n position: fixed;\n top: -70px;\n left: 0;\n transition: top 0.5s ease;\n width: 100%;\n z-index: 1;\n}\n\n.ProductStickyAddToCart.is-visible {\n top: 60px;\n}\n\n.ProductStickyAddToCart-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.ProductStickyAddToCart-detail {\n display: flex;\n align-items: center;\n}\n\n.ProductStickyAddToCart-title {\n font-family: 'Gotham-Bold';\n font-size: 1em;\n line-height: 1.6;\n}\n\n.ProductStickyAddToCart-desc {\n margin-left: 15px;\n font-family: 'Gotham-Book';\n font-size: 1em;\n}\n\n.ProductStickyAddToCart-btn {\n width: 16.66667%;\n height: 40px;\n margin: 10px;\n background-color: #eee;\n outline: none;\n color: #000;\n}\n\n@media (max-width: 768px) {\n .ProductStickyAddToCart {\n top: -45px;\n height: 39px;\n }\n \n .ProductStickyAddToCart.is-visible {\n top: 40px;\n }\n\n .ProductStickyAddToCart-detail {\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n }\n \n .ProductStickyAddToCart-title {\n padding: 0;\n font-size: 0.75em;\n line-height: 9px;\n }\n \n .ProductStickyAddToCart-desc {\n padding: 0;\n margin-left: 0;\n font-size: 0.75em;\n }\n\n .ProductStickyAddToCart-btn {\n width: 33%;\n height: 24px;\n padding: 1px 10px;\n margin: 0;\n font-size: 12px;\n }\n\n .ProductStickyAddToCart-btn .LoadingSpinner-lds-ring,\n .ProductStickyAddToCart-btn .LoadingSpinner-lds-ring div {\n width: 20px;\n height: 20px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Icons", | |
| "code": "import React from 'react'\nimport './styles.css'\n\nconst fillColors = props => {\n return `${props.white ? 'Icon--white' : ''}${props.black ? ' Icon--black' : ''}`\n}\n\nconst iconSize = props => {\n return `${props.small ? 'Icon-size--small' : ''}${props.large ? ' Icon-size--lg' : ''}${\n props.xs ? 'Icon-size--xs' : ''\n }`\n}\n\nconst Icons = props => {\n const name = props.name ? props.name : null\n if (!name) return null\n return (\n <>\n {\n {\n ArrowLeft: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 50 15\"\n >\n <path d=\"M50 5.38v4.25H15V15L0 7.5 15 0v5.38z\"></path>\n </svg>\n ),\n BtnPrev: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n fill=\"white\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 284.49 498.98\"\n >\n <path d=\"M249.49 0a35 35 0 0 1 24.75 59.75L84.49 249.49l189.75 189.74a35.002 35.002 0 1 1-49.5 49.5L10.25 274.24a35 35 0 0 1 0-49.5L224.74 10.25A34.89 34.89 0 0 1 249.49 0z\"></path>\n </svg>\n ),\n BtnNext: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n fill=\"white\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 284.49 498.98\"\n >\n <path d=\"M35 498.98a35 35 0 0 1-24.75-59.75l189.74-189.74L10.25 59.75a35.002 35.002 0 0 1 49.5-49.5l214.49 214.49a35 35 0 0 1 0 49.5L59.75 488.73A34.89 34.89 0 0 1 35 498.98z\"></path>\n </svg>\n ),\n Cart: (\n <svg\n aria-hidden=\"true\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n focusable=\"false\"\n role=\"presentation\"\n viewBox=\"0 0 64 64\"\n stroke=\"#fff\"\n strokeWidth={5}\n fill=\"none\"\n style={props.style}\n >\n <path d=\"M14 17.44h46.79l-7.94 25.61H20.96l-9.65-35.1H3\"></path>\n <circle cx=\"27\" cy=\"53\" r=\"2\"></circle>\n <circle cx=\"47\" cy=\"53\" r=\"2\"></circle>\n </svg>\n ),\n Menu: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n viewBox=\"0 0 64 64\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n strokeWidth={5}\n style={props.style}\n >\n <path fill=\"currentColor\" d=\"M7 15h51M7 32h43M7 49h51\"></path>\n </svg>\n ),\n Close: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 64 64\"\n style={props.style}\n >\n <path\n fill=\"none\"\n stroke=\"#000\"\n strokeWidth={5}\n d=\"M19 17.61l27.12 27.13m0-27.12L19 44.74\"\n ></path>\n </svg>\n ),\n Search: (\n <svg\n aria-hidden=\"true\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n focusable=\"false\"\n role=\"presentation\"\n viewBox=\"0 0 64 64\"\n strokeWidth={5}\n fill=\"none\"\n style={props.style}\n >\n <path d=\"M44 27a17 17 0 1 1-17-17 17 17 0 0 1 17 17zm9.85 26.92L39.23 39.29\"></path>\n </svg>\n ),\n Twitter: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 32 32\"\n style={props.style}\n >\n <path\n fill=\"currentColor\"\n d=\"M31.281 6.733q-1.304 1.924-3.13 3.26 0 .13.033.408t.033.408q0 2.543-.75 5.086t-2.282 4.858-3.635 4.108-5.053 2.869-6.341 1.076q-5.282 0-9.65-2.836.913.065 1.5.065 4.401 0 7.857-2.673-2.054-.033-3.668-1.255t-2.266-3.146q.554.13 1.206.13.88 0 1.663-.261-2.184-.456-3.619-2.184t-1.435-3.977v-.065q1.239.652 2.836.717-1.271-.848-2.021-2.233t-.75-2.983q0-1.63.815-3.195 2.38 2.967 5.754 4.678t7.319 1.907q-.228-.815-.228-1.434 0-2.608 1.858-4.45t4.532-1.842q1.304 0 2.51.522t2.054 1.467q2.152-.424 4.01-1.532-.685 2.217-2.771 3.488 1.989-.261 3.619-.978z\"\n ></path>\n </svg>\n ),\n Facebook: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 32 32\"\n style={props.style}\n >\n <path\n fill=\"currentColor\"\n d=\"M18.56 31.36V17.28h4.48l.64-5.12h-5.12v-3.2c0-1.28.64-2.56 2.56-2.56h2.56V1.28H19.2c-3.84 0-7.04 2.56-7.04 7.04v3.84H7.68v5.12h4.48v14.08h6.4z\"\n ></path>\n </svg>\n ),\n Pinterest: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 32 32\"\n >\n <path\n fill=\"#444\"\n d=\"M27.52 9.6c-.64-5.76-6.4-8.32-12.8-7.68-4.48.64-9.6 4.48-9.6 10.24 0 3.2.64 5.76 3.84 6.4 1.28-2.56-.64-3.2-.64-4.48-1.28-7.04 8.32-12.16 13.44-7.04 3.2 3.84 1.28 14.08-4.48 13.44-5.12-1.28 2.56-9.6-1.92-11.52-3.2-1.28-5.12 4.48-3.84 7.04-1.28 4.48-3.2 8.96-1.92 15.36 2.56-1.92 3.84-5.76 4.48-9.6 1.28.64 1.92 1.92 3.84 1.92 6.4-.64 10.24-7.68 9.6-14.08z\"\n ></path>\n </svg>\n ),\n Instagram: (\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n role=\"presentation\"\n className={`Icon ${props.className || ''} ${fillColors(props)} ${iconSize(props)}`}\n viewBox=\"0 0 32 32\"\n style={props.style}\n >\n <path\n fill=\"currentColor\"\n d=\"M16 3.094c4.206 0 4.7.019 6.363.094 1.538.069 2.369.325 2.925.544.738.287 1.262.625 1.813 1.175s.894 1.075 1.175 1.813c.212.556.475 1.387.544 2.925.075 1.662.094 2.156.094 6.363s-.019 4.7-.094 6.363c-.069 1.538-.325 2.369-.544 2.925-.288.738-.625 1.262-1.175 1.813s-1.075.894-1.813 1.175c-.556.212-1.387.475-2.925.544-1.663.075-2.156.094-6.363.094s-4.7-.019-6.363-.094c-1.537-.069-2.369-.325-2.925-.544-.737-.288-1.263-.625-1.813-1.175s-.894-1.075-1.175-1.813c-.212-.556-.475-1.387-.544-2.925-.075-1.663-.094-2.156-.094-6.363s.019-4.7.094-6.363c.069-1.537.325-2.369.544-2.925.287-.737.625-1.263 1.175-1.813s1.075-.894 1.813-1.175c.556-.212 1.388-.475 2.925-.544 1.662-.081 2.156-.094 6.363-.094zm0-2.838c-4.275 0-4.813.019-6.494.094-1.675.075-2.819.344-3.819.731-1.037.4-1.913.944-2.788 1.819S1.486 4.656 1.08 5.688c-.387 1-.656 2.144-.731 3.825-.075 1.675-.094 2.213-.094 6.488s.019 4.813.094 6.494c.075 1.675.344 2.819.731 3.825.4 1.038.944 1.913 1.819 2.788s1.756 1.413 2.788 1.819c1 .387 2.144.656 3.825.731s2.213.094 6.494.094 4.813-.019 6.494-.094c1.675-.075 2.819-.344 3.825-.731 1.038-.4 1.913-.944 2.788-1.819s1.413-1.756 1.819-2.788c.387-1 .656-2.144.731-3.825s.094-2.212.094-6.494-.019-4.813-.094-6.494c-.075-1.675-.344-2.819-.731-3.825-.4-1.038-.944-1.913-1.819-2.788s-1.756-1.413-2.788-1.819c-1-.387-2.144-.656-3.825-.731C20.812.275 20.275.256 16 .256z\"\n ></path>\n <path\n fill=\"currentColor\"\n d=\"M16 7.912a8.088 8.088 0 0 0 0 16.175c4.463 0 8.087-3.625 8.087-8.088s-3.625-8.088-8.088-8.088zm0 13.338a5.25 5.25 0 1 1 0-10.5 5.25 5.25 0 1 1 0 10.5zM26.294 7.594a1.887 1.887 0 1 1-3.774.002 1.887 1.887 0 0 1 3.774-.003z\"\n ></path>\n </svg>\n ),\n }[name]\n }\n </>\n )\n}\n\nexport default Icons\n", | |
| "style": ".Icon {\n width: 22px;\n height: 22px;\n}\n\n.Icon svg {\n width: 100%;\n height: 100%;\n}\n.Icon path {\n stroke: currentColor;\n}\n\n.Icon--white {\n color: #fff;\n}\n\n.Icon--black {\n color: #000;\n}\n\n.Icon-size--xs {\n width: 18px;\n height: 18px;\n}\n\n.Icon-size--small {\n width: 20px;\n height: 20px;\n}\n\n.Icon-size--lg {\n width: 25px;\n height: 25px;\n}\n\n@media (min-width: 768px) {\n .Icon {\n width: 25px;\n height: 25px;\n }\n .Icon-size--small {\n width: 25px;\n height: 25px;\n }\n .Icon-size--lg {\n width: 30px;\n height: 30px;\n }\n .Icon-size--xs {\n width: 18px;\n height: 18px;\n }\n}\n\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartPageItem", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport { useCartActions } from 'frontend-checkout'\n\nimport ItemQuantityInput from 'Components/ItemQuantityInput'\nimport Button from 'Components/Button'\n\nimport './styles.css'\n\nconst currencyFormatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n})\n\nconst CartPageItem = ({ item }) => {\n const { removeItem, getProductTrackingData } = useCartActions()\n\n function trackEvent(eventName) {\n const keys = {\n addToCart: 'add',\n removeFromCart: 'remove',\n }\n\n window.dataLayer.push({\n event: eventName,\n ecommerce: {\n [keys[eventName]]: {\n products: [getProductTrackingData(item)],\n },\n },\n })\n }\n\n return (\n <div className=\"CartPageItem\">\n <div className=\"CartPageItem-details\">\n <a className=\"CartPageItem-img\" href={`/${item.variant.product.handle}`}>\n <ResponsiveImage\n alt={item.variant.image.altText || item.title}\n src={item.variant.image.src}\n />\n </a>\n <div className=\"CartPageItem-detail\">\n <a className=\"CartPageItem-title\" href={`/${item.variant.product.handle}`}>\n <p>{item.title}</p>\n </a>\n <p className=\"CartPageItem-description\">\n {item.description}iPhone 11 Pro Max / Rustic Brown / Moment\n </p>\n <div className=\"CartPageItem-stock\"></div>\n <Button\n className=\"Btn--black CartPageItem-btnRemove\"\n as=\"button\"\n onClick={() => removeItem({ itemId: item.id })}\n >\n Remove\n </Button>\n </div>\n </div>\n <div className=\"CartPageItem-quantity\">\n <div className=\"CartPageItem-qty-price-container\">\n <ItemQuantityInput\n itemId={item.id}\n variantId={item.variant.id}\n quantity={item.quantity}\n onRemove={() => trackEvent('removeFromCart')}\n onUpdate={quantityChange =>\n trackEvent(quantityChange > 0 ? 'addToCart' : 'removeFromCart')\n }\n />\n </div>\n </div>\n <div className=\"CartPageItem-total\">\n <span className=\"CartPageItem-price\">\n {currencyFormatter.format(item.variant.priceV2.amount)}\n </span>\n </div>\n </div>\n )\n}\n\nexport default CartPageItem\n", | |
| "style": ".CartPageItem {\n display: flex;\n margin: 40px 0;\n}\n\n.CartPageItem-details {\n flex: 4.5;\n display: flex;\n}\n\n.CartPageItem-quantity {\n flex: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.CartPageItem-total {\n flex: 2;\n display: flex;\n justify-content: flex-end;\n align-items: center;\n}\n\n.CartPageItem-img {\n display: block;\n width: 160px;\n height: 160px;\n}\n\n.CartPageItem-img img {\n display: block;\n margin: 0 auto;\n max-width: 100%;\n width: auto;\n height: auto;\n}\n\n.CartPageItem-detail {\n padding-left: 30px;\n}\n.CartPageItem-title {\n font-family: \"Gotham-Bold\";\n font-size: 1.0625em;\n color: inherit;\n text-decoration: none;\n}\n\n.CartPageItem-stock {\n margin: 15px 0px 25px 0px;\n}\n\n.CartPageItem-btnRemove {\n margin: 20px 0;\n padding: 6px 12px;\n font-size: 0.875em;\n}\n\n.CartPageItem-qty-price-container {\n display: flex;\n flex: 1;\n justify-content: center;\n align-items: center;\n}\n\n@media (max-width: 767px) {\n .CartPageItem {\n display: block;\n margin: 30px 0 40px;\n }\n\n .CartPageItem-quantity {\n width: 33%;\n float: left;\n }\n\n .CartPageItem-total {\n line-height: 40px;\n }\n\n .CartPageItem-img {\n width: 25%;\n }\n\n .CartPageItem-detail {\n padding-left: 22px;\n }\n\n .CartPageItem-title {\n font-size: 0.875em;\n }\n\n .CartPageItem-btnRemove {\n padding: 5px 11px;\n font-size: 0.75em;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "AnimatedAirPods", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\n\nimport './styles.css'\n\nconst AnimatedAirPods = ({ isPro, resources: [topSrc, bottomSrc, bodySrc, litSrc] }) => {\n return (\n <div className={cx('AnimatedAirPods', { 'AnimatedAirPods--pro': isPro })}>\n <div className=\"AnimatedAirPods-top\">\n <ResponsiveImage className=\"AnimatedAirPods-image\" src={topSrc} alt=\"\" />\n </div>\n <div className=\"AnimatedAirPods-bottom\">\n <ResponsiveImage className=\"AnimatedAirPods-image\" src={bottomSrc} alt=\"\" />\n </div>\n <div className=\"AnimatedAirPods-body\">\n <ResponsiveImage className=\"AnimatedAirPods-image\" src={bodySrc} alt=\"\" />\n </div>\n {litSrc && (\n <div className=\"AnimatedAirPods-lit\">\n <ResponsiveImage className=\"AnimatedAirPods-image\" src={litSrc} alt=\"\" />\n </div>\n )}\n </div>\n )\n}\n\nexport default AnimatedAirPods\n", | |
| "style": "@keyframes top_motion {\n 0% {top: 150px;-webkit-transform: rotate(0deg);transform: rotate(0deg);}\n 45% {top: 150px;-webkit-transform: rotate(0deg);transform: rotate(0deg);}\n 100% {top: 20px;-webkit-transform: rotate(4deg);transform: rotate(4deg);-webkit-transform-origin: bottom right;transform-origin: bottom right;}\n}\n\n@keyframes bot_motion {\n 0% {top: 200px;-webkit-transform: rotate(0deg);transform: rotate(0deg);}\n 45% {top: 200px;-webkit-transform: rotate(0deg);transform: rotate(0deg);}\n 100% {top: 305px;-webkit-transform: rotate(-2deg);transform: rotate(-2deg);-webkit-transform-origin: top right;transform-origin: top right;}\n}\n\n@keyframes case_motion {\n 0% {top: 150px;}\n 45% {top: 150px;}\n 100% {top: 90px;}\n}\n\n@keyframes lit_motion {\n 0% {top: 200px;-webkit-transform: rotate(0deg);transform: rotate(0deg); z-index: 35; opacity: 1;}\n 30% {top: 200px;-webkit-transform: rotate(0deg);transform: rotate(0deg); z-index: 35; opacity: 1;}\n 45% {top: 200px;-webkit-transform: rotate(0deg);transform: rotate(0deg); opacity: 0;}\n 100% {top: 305px;-webkit-transform: rotate(-2deg);transform: rotate(-2deg);-webkit-transform-origin: top right;transform-origin: top right; opacity:0;}\n}\n\n@keyframes bot_motion_pro {\n 0% {top: 210px;-webkit-transform: rotate(0deg);transform: rotate(0deg);}\n 45% {top: 210px;-webkit-transform: rotate(0deg);transform: rotate(0deg);}\n 100% {top: 305px;-webkit-transform: rotate(-2deg);transform: rotate(-2deg);-webkit-transform-origin: top right;transform-origin: top right;}\n}\n\n@keyframes case_motion_pro {\n 0% {top: 150px;}\n 45% {top: 150px;}\n 100% {top: 105px;}\n}\n\n@keyframes lit_motion_pro {\n 0% {top: 210px;-webkit-transform: rotate(0deg);transform: rotate(0deg); z-index: 35; opacity: 1;}\n 30% {top: 210px;-webkit-transform: rotate(0deg);transform: rotate(0deg); z-index: 35; opacity: 1;}\n 45% {top: 210px;-webkit-transform: rotate(0deg);transform: rotate(0deg); opacity: 0;}\n 100% {top: 305px;-webkit-transform: rotate(-2deg);transform: rotate(-2deg);-webkit-transform-origin: top right;transform-origin: top right; opacity:0;}\n}\n\n.AnimatedAirPods {\n max-width: 170px;\n position: relative;\n height: 450px;\n}\n\n.AnimatedAirPods-top {\n width: auto;\n position: absolute;\n top: 0;\n left: 0;\n animation: top_motion 1.5s infinite;\n animation-direction: alternate;\n z-index: 30;\n}\n\n.AnimatedAirPods-bottom {\n width: auto;\n position: absolute;\n top: 0;\n left: 0;\n animation: bot_motion 1.5s infinite;\n animation-direction: alternate;\n z-index: 30;\n}\n\n.AnimatedAirPods-body {\n width: auto;\n position: absolute;\n top: 0;\n left: 0;\n animation: case_motion 1.5s infinite;\n animation-direction: alternate;\n}\n\n.AnimatedAirPods-lit {\n width: auto;\n position: absolute;\n top: 0;\n left: 0;\n animation: lit_motion 1.5s infinite;\n animation-direction: alternate;\n}\n\n.AnimatedAirPods img {\n width: 100%;\n}\n\n.AnimatedAirPods--pro {\n max-width: 240px;\n}\n\n.AnimatedAirPods--pro .AnimatedAirPods-bottom {\n animation: bot_motion_pro 1.5s infinite;\n animation-direction: alternate;\n}\n\n.AnimatedAirPods--pro .AnimatedAirPods-body {\n animation: case_motion_pro 1.5s infinite;\n animation-direction: alternate;\n}\n\n.AnimatedAirPods--pro .AnimatedAirPods-lit {\n animation: lit_motion_pro 1.5s infinite;\n animation-direction: alternate;\n}\n\n@media (max-width: 767px) {\n .AnimatedAirPods {\n margin: auto;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "MedicalSection", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\nimport RichText from 'Components/RichText'\nimport Accordions from 'Components/Accordions'\n\nimport './styles.css'\n\nconst MedicalSection = ({ headerHTML, contentHTML, covidSign, teamPic, horizontal }) => {\n const renderContent = () => {\n if (horizontal) {\n return (\n <div className=\"MedicalSection-content\">\n {contentHTML.map(({ content, ctaText1, ctaHref1, ctaText2, ctaHref2 }, index) => (\n <div key={index} className=\"MedicalSection-column\">\n <RichText source={content} />\n <div className=\"MedicalSection-actions\">\n <Button to={ctaHref1} className=\"Btn--default\">\n {ctaText1}\n </Button>\n <Button to={ctaHref2} className=\"Btn--default\">\n {ctaText2}\n </Button>\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n const contents = contentHTML.map(({ header, content, whiteBackground }) => ({\n title: header,\n content: (\n <>\n <RichText source={content} />\n {covidSign && (\n <div className=\"MedicalSection-sign\">\n <ResponsiveImage src={covidSign[0]} />\n <ResponsiveImage className=\"MedicalSection-sign-big\" src={covidSign[1]} />\n </div>\n )}\n {teamPic && <ResponsiveImage src={teamPic} />}\n </>\n ),\n whiteBackground,\n }))\n return <Accordions items={contents} />\n }\n\n return (\n <div className=\"MedicalSection\">\n <PageWidth className=\"MedicalSection-wrapper\">\n <RichText className=\"MedicalSection-header\" source={headerHTML} />\n {renderContent()}\n </PageWidth>\n </div>\n )\n}\n\nexport default MedicalSection\n", | |
| "style": ".MedicalSection:nth-child(even) {\n background-color: #ffffff;\n}\n\n.MedicalSection:nth-child(odd) {\n background-color: #f3f3f3;\n}\n\n.MedicalSection-wrapper {\n padding: 80px 0;\n width: 100%;\n max-width: 1220px;\n}\n\n.MedicalSection-content {\n display: flex;\n justify-content: space-between;\n}\n\n.MedicalSection-column {\n width: calc(50% - 45px);\n margin: auto 0;\n}\n\n.MedicalSection-actions {\n margin-top: 40px;\n}\n\n.MedicalSection-actions .Btn {\n padding: 9px 20px;\n}\n\n.MedicalSection-actions .Btn:last-child {\n margin-left: 10px;\n}\n\n.MedicalSection-sign {\n display: flex;\n padding: 10px 0 40px;\n}\n\n.MedicalSection-sign img {\n width: auto;\n max-height: 60px;\n object-fit: contain;\n}\n\n.MedicalSection-sign-big {\n padding-left: 30px;\n}\n\n.MedicalSection .RichText h3 {\n font-size: 27px;\n}\n\n.MedicalSection .RichText a {\n border: none;\n}\n\n.MedicalSection .RichText a::after {\n content: none;\n}\n\n@media (max-width: 767px) {\n .MedicalSection-wrapper {\n flex-direction: column;\n padding: 50px 20px 0;\n }\n \n .MedicalSection-content {\n flex-direction: column;\n }\n\n .MedicalSection-column {\n width: 100%;\n }\n\n .MedicalSection .RichText h3 {\n font-size: 23px;\n margin-bottom: 10px;\n }\n\n .MedicalSection .RichText h4 {\n font-size: 14px;\n }\n\n .MedicalSection-actions {\n margin: 40px 0 60px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogsFooter", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport Link from 'Components/BuiltIn/Link'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\nimport Icons from 'Components/Icons'\n\nimport './styles.css'\n\nconst BlogsFooter = ({ backUrl, showSocialLinks = false, className }) => {\n return (\n <PageWidth>\n <div className={cx('BlogsFooter', className)}>\n <div className=\"BlogsFooter-form\">\n <div>\n Want to join us on our journey? Stay up to date with the latest from The Nomadic.\n </div>\n <div>\n <form action=\"#\" method=\"POST\">\n <input type=\"email\" placeholder=\"Eenter your email\" />\n <Button as=\"button\" type=\"submit\" value=\"submit\">\n Adnevture On\n </Button>\n </form>\n </div>\n </div>\n {showSocialLinks && (\n <div className=\"BlogsFooter-socialLinks\">\n <ul>\n <li>\n <Link to=\"#\">\n <Icons name=\"Facebook\" black xs />\n <span>Share</span>\n </Link>\n </li>\n <li>\n <Link to=\"#\">\n <Icons name=\"Twitter\" black xs />\n <span>Tweet</span>\n </Link>\n </li>\n <li>\n <Link to=\"#\">\n <Icons name=\"Pinterest\" black xs />\n <span>Pin it</span>\n </Link>\n </li>\n </ul>\n </div>\n )}\n </div>\n {backUrl && (\n <div className=\"BlogsFooter-bottom\">\n <Link to={backUrl}>\n <Icons name=\"ArrowLeft\" black large />\n <span>Back to The Nomadic</span>\n </Link>\n </div>\n )}\n </PageWidth>\n )\n}\n\nexport default BlogsFooter\n", | |
| "style": ".BlogsFooter {\n width: 60%;\n margin: 30px auto 0;\n padding: 50px 0 100px;\n border-top: 1px solid #dedede;\n}\n\n.BlogsFooter-form { \n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n}\n\n.BlogsFooter-form div { \n width: calc(50% - 15px);\n padding-left: 60px;\n}\n\n.BlogsFooter-form div:first-child {\n font-size: 18px;\n}\n\n.BlogsFooter-form input {\n font-family: 'Gotham-Book', sans-serif;\n font-size: 14px;\n max-width: 210px;\n padding: 12px 20px;\n width: 100%;\n outline: none;\n border: 1px solid #dedede;\n display: block;\n}\n\n.BlogsFooter-form button {\n font-family: 'Gotham-Bold', sans-serif;\n background: #000;\n padding: 12px 20px;\n color: #fff;\n margin-top: 10px;\n}\n\n\n.BlogsFooter-socialLinks {\n padding-top: 40px;\n}\n\n.BlogsFooter-socialLinks ul {\n list-style-type: none;\n margin: 0;\n display: flex;\n font-size: 14px;\n justify-content: center;\n}\n\n.BlogsFooter-socialLinks li {\n padding: 0 12px;\n}\n\n.BlogsFooter-socialLinks a {\n border: none;\n display: flex;\n align-content: center;\n text-decoration: none;\n color: #000;\n}\n\n.BlogsFooter-socialLinks a:after {\n content: none;\n}\n\n.BlogsFooter-socialLinks svg {\n margin-right: 7px;\n}\n\n.BlogsFooter-bottom {\n border-top: 2px solid #dedede;\n padding: 40px 0 20px;\n}\n\n.BlogsFooter-bottom svg {\n margin-right: 8px;\n}\n\n.BlogsFooter-bottom a {\n border-bottom: none;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 1.25em;\n font-family: Gotham-Bold, sans-serif;\n text-decoration: none;\n color: #000;\n}\n\n.BlogsFooter-bottom a:after {\n content: none;\n}\n\n@media (max-width: 767px) {\n .BlogsFooter {\n width: 100%;\n padding: 40px 0 60px;\n margin-top: 20px;\n }\n \n .BlogsFooter-form div { \n width: 100%;\n padding-left: 0;\n }\n\n .BlogsFooter-form div:first-child {\n padding-bottom: 20px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Stickers", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\nimport ImageSlider from 'Components/ImageSlider'\nimport StickersForm from 'Components/StickersForm'\nimport './styles.css'\n\nconst stickerResources = [\n {\n src:\n 'https://i.shgcdn.com/03007c33-4b42-45f9-9642-95ae4cf6069d/-/format/auto/-/preview/3000x3000/-/quality/best/',\n alt: '',\n },\n {\n src:\n 'https://i.shgcdn.com/15272297-3e09-444c-8140-d7b9b54b7e4a/-/format/auto/-/preview/3000x3000/-/quality/best/',\n alt: '',\n },\n {\n src:\n 'https://i.shgcdn.com/f7d33a14-17b8-40c5-b7a6-e0f5163ba3a6/-/format/auto/-/preview/3000x3000/-/quality/best/',\n alt: '',\n },\n {\n src:\n 'https://i.shgcdn.com/9f3016cb-2328-402d-a4c8-7e9706674151/-/format/auto/-/preview/3000x3000/-/quality/lighter/',\n alt: '',\n },\n]\n\nconst Stickers = () => {\n return (\n <div className=\"Stickers\">\n <PageWidth className=\"Stickers-container\">\n <div className=\"Stickers-images-container\">\n <ImageSlider resources={stickerResources} />\n </div>\n <div className=\"Stickers-form-container\">\n <StickersForm />\n </div>\n </PageWidth>\n </div>\n )\n}\n\nexport default Stickers\n", | |
| "style": ".Stickers {\n padding: 60px 0 40px;\n background-color: #f3f3f3;\n}\n\n.Stickers-container {\n display: flex;\n}\n\n.Stickers-images-container {\n width: 60%;\n float: left;\n}\n\n.Stickers-form-container {\n width: 40%;\n max-width: 450px;\n padding: 0 20px 0 40px;\n}\n\n@media (max-width: 767px) {\n .Stickers-container {\n flex-direction: column;\n padding: 0;\n }\n \n .Stickers-images-container {\n width: 100%;\n }\n \n .Stickers-form-container {\n width: 100%;\n padding: 0 20px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Story2", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst Story2 = ({\n image,\n title,\n description,\n short_description,\n ctaHref,\n ctaText,\n subscribe = false,\n}) => {\n return (\n <div className=\"Story2\">\n <ResponsiveImage src={image} alt=\"\" className=\"Story2-image\" />\n\n <PageWidth className=\"Story2-content\">\n <h2 className=\"Story2-title\">{title}</h2>\n <p className=\"Story2-description\">{description}</p>\n <p className=\"Story2-shortDescription\">{short_description || description}</p>\n\n {ctaHref && ctaText && (\n <Button href={ctaHref} className=\"Story2-cta Btn--inverted\">\n {ctaText}\n </Button>\n )}\n\n {subscribe && (\n <form className=\"Story2-subscribe\">\n <input\n type=\"email\"\n aria-label=\"Enter email for updates\"\n placeholder=\"Enter email for updates\"\n className=\"Story2-subscribe-input\"\n />\n <Button as=\"button\" type=\"submit\" className=\"Story2-subscribe-button\">\n Subscribe\n </Button>\n </form>\n )}\n </PageWidth>\n </div>\n )\n}\n\nexport default Story2\n", | |
| "style": ".Story2 {\n display: flex;\n height: 625px;\n position: relative;\n justify-content: center;\n}\n\n.Story2-content {\n height: auto;\n margin-bottom: 50px;\n margin-top: 130px;\n position: absolute;\n text-align: center;\n}\n\n.Story2-title {\n color: #fff;\n font-size: 40px;\n line-height: 1.3;\n margin-bottom: 20px;\n}\n\n.Story2-description,\n.Story2-shortDescription {\n color: #fff;\n line-height: 1.5;\n margin: 0 auto;\n}\n\n.Story2-description {\n display: none;\n font-size: 20px;\n max-width: 1100px;\n}\n\n.Story2-shortDescription {\n font-size: 16px;\n padding: 0 8px;\n}\n\n.Story2-image {\n height: 100%;\n object-fit: cover;\n object-position: 50% 50%;\n width: 100%;\n}\n\n.Story2-cta {\n margin-top: 20px;\n}\n\n.Story2-subscribe {\n display: flex;\n justify-content: center;\n margin-top: 15px;\n}\n\n.Story2-subscribe-input {\n background-color: #000;\n border: 1px solid #fff;\n color: #fff;\n font-size: 14px;\n padding: 8px 20px;\n width: 250px;\n}\n\n.Story2-subscribe-button {\n background-color: #fff;\n margin-left: 8px;\n padding: 8px 16px;\n}\n\n@media (min-width: 768px) {\n .Story2 {\n height: 600px;\n }\n\n .Story2-content {\n padding: 0 20px;\n }\n\n .Story2-description {\n display: block;\n font-size: 20px;\n }\n\n .Story2-shortDescription {\n display: none;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Carousel", | |
| "code": "import React, { useState, useRef, useEffect } from 'react'\nimport Slider from 'react-slick'\nimport { ResponsiveImage } from 'frontend-ui'\nimport ImageMagnifier from 'Components/ImageMagnifier'\n\nimport './styles.css'\n\nconst Carousel = ({ images = [] }) => {\n const [mainCarousel, setMainCarousel] = useState(null)\n const [navCarousel, setNavCarousel] = useState(null)\n\n const mainCarouselRef = useRef(null)\n const navCarouselRef = useRef(null)\n\n useEffect(() => {\n setMainCarousel(mainCarouselRef.current)\n setNavCarousel(navCarouselRef.current)\n }, [])\n\n return (\n <div className=\"Carousel-wrapper\">\n <Slider className=\"Carousel-main\" ref={mainCarouselRef} asNavFor={navCarousel} arrows={false}>\n {images.map(({ src, alt }) => (\n <ImageMagnifier\n key={src}\n imageSrc={getUrl(src, 720)}\n largeImageSrc={getUrl(src, 1080)}\n imageAlt={alt}\n />\n ))}\n </Slider>\n\n <Slider\n className=\"Carousel-nav\"\n ref={navCarouselRef}\n asNavFor={mainCarousel}\n slidesToShow={Math.min(5, images.length)}\n arrows={false}\n focusOnSelect={true}\n >\n {images.map(({ src, alt }) => (\n <ResponsiveImage key={src} src={src} width=\"60\" height=\"60\" alt={alt} />\n ))}\n </Slider>\n </div>\n )\n}\n\nfunction getUrl(src, size) {\n let urlWithSize = src\n const imageExtensions = ['.gif', '.jpg', '.jpeg', '.tiff', '.png']\n for (const imgExt of imageExtensions) {\n const re = new RegExp(imgExt, 'i')\n if (re.test(src)) {\n urlWithSize = src.replace(re, `_${size}x${imgExt}`)\n break\n }\n }\n\n return urlWithSize\n}\n\nexport default Carousel\n", | |
| "style": ".Carousel-wrapper {\n width: 100%;\n overflow: hidden;\n}\n\n.Carousel-nav .slick-slide {\n margin-top: 20px;\n}\n\n.Carousel-nav .slick-slide.slick-current > div {\n border-bottom: 4px solid black;\n}\n\n.Carousel-nav .slick-slide > div {\n margin-right: 20px;\n padding: 0 5px 10px;\n}\n\n.Carousel-wrapper .slick-slide {\n display: none;\n float: left;\n height: 100%;\n min-height: 1px\n}\n\n.Carousel-wrapper .slick-slide img {\n object-fit: contain;\n}\n\n.Carousel-nav .slick-slide img {\n height: 100%;\n}\n\n.Carousel-wrapper .slick-initialized .slick-slide {\n display: block\n}\n\n.Carousel-wrapper .slick-list,\n.Carousel-wrapper .slick-track {\n touch-action: pan-y;\n}\n.Carousel-wrapper .slick-track:before,\n.Carousel-wrapper .slick-track:after {\n display: table;\n content: \"\";\n}\n.Carousel-wrapper .slick-track:after {\n clear: both;\n}\n\n@media (max-width: 767px) {\n .Carousel-wrapper {\n padding: 0;\n }\n\n .Carousel-nav .slick-slide {\n margin-top: 11px;\n }\n \n .Carousel-nav .slick-slide.slick-current > div {\n border-bottom: 4px solid black;\n }\n \n .Carousel-nav .slick-slide > div {\n margin-right: 11px;\n padding: 0 5px 10px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleImageRow", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst BlogArticleImageRow = ({ rowHeight, imageColumns, images = [] }) => (\n <PageWidth className=\"BlogArticleImageRow\">\n {images.map((image, i) => (\n <div\n key={i}\n className={`BlogArticleImageRow-image-wrapper BlogArticleImageRow-col--${(imageColumns &&\n imageColumns[i]) ||\n 12 / images.length} BlogArticleImageRow-m-col--${(imageColumns && imageColumns[i] / 2) ||\n 12 / images.length / 2}`}\n >\n <ResponsiveImage\n src={image.src}\n alt={image.alt || image.caption}\n loading=\"lazy\"\n style={{ height: rowHeight || 'auto' }}\n />\n <span>{image.caption}</span>\n </div>\n ))}\n </PageWidth>\n)\n\nexport default BlogArticleImageRow\n", | |
| "style": ".BlogArticleImageRow {\n display: grid;\n grid-gap: 60px;\n grid-template-columns: repeat(12, 1fr);\n margin-top: 35px;\n margin-bottom: 50px;\n}\n\n.BlogArticleImageRow-image-wrapper {\n text-align: center;\n}\n\n.BlogArticleImageRow-image-wrapper img {\n width: 100%;\n}\n\n.BlogArticleImageRow-col--1 {\n grid-column: span 1;\n}\n\n.BlogArticleImageRow-col--2 {\n grid-column: span 2;\n}\n\n.BlogArticleImageRow-col--3 {\n grid-column: span 3;\n}\n\n.BlogArticleImageRow-col--4 {\n grid-column: span 4;\n}\n\n.BlogArticleImageRow-col--5 {\n grid-column: span 5;\n}\n\n.BlogArticleImageRow-col--6 {\n grid-column: span 6;\n}\n\n.BlogArticleImageRow-col--7 {\n grid-column: span 7;\n}\n\n.BlogArticleImageRow-col--8 {\n grid-column: span 8;\n}\n\n.BlogArticleImageRow-col--9 {\n grid-column: span 9;\n}\n\n.BlogArticleImageRow-col--10 {\n grid-column: span 10;\n}\n\n.BlogArticleImageRow-col--11 {\n grid-column: span 11;\n}\n\n.BlogArticleImageRow-col--12 {\n grid-column: span 12;\n}\n\n@media (max-width: 767px) {\n .BlogArticleImageRow {\n grid-gap: 30px;\n grid-template-columns: repeat(6, 1fr);\n margin-top: 25px;\n margin-bottom: 40px;\n }\n\n .BlogArticleImageRow-image-wrapper img {\n height: auto !important;\n }\n\n .BlogArticleImageRow-m-col--1 {\n grid-column: span 1;\n }\n\n .BlogArticleImageRow-m-col--2 {\n grid-column: span 2;\n }\n\n .BlogArticleImageRow-m-col--3 {\n grid-column: span 3;\n }\n\n .BlogArticleImageRow-m-col--4 {\n grid-column: span 4;\n }\n\n .BlogArticleImageRow-m-col--5 {\n grid-column: span 5;\n }\n\n .BlogArticleImageRow-m-col--6 {\n grid-column: span 6;\n }\n\n .BlogArticleImageRow-m-col--7 {\n grid-column: span 7;\n }\n\n .BlogArticleImageRow-m-col--8 {\n grid-column: span 8;\n }\n\n .BlogArticleImageRow-m-col--9 {\n grid-column: span 9;\n }\n\n .BlogArticleImageRow-m-col--10 {\n grid-column: span 10;\n }\n\n .BlogArticleImageRow-m-col--11 {\n grid-column: span 11;\n }\n\n .BlogArticleImageRow-m-col--12 {\n grid-column: span 12;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Navbar", | |
| "code": "import React, { useEffect } from 'react'\nimport cx from 'classnames'\nimport Link from 'frontend-link'\nimport Icons from 'Components/Icons'\nimport SocialLinks from 'Components/SocialLinks'\nimport './styles.css'\n\nconst Navbar = ({ menu, isOpen, closeNavbar }) => {\n useEffect(() => {\n const animatedElements = document.querySelectorAll('.appear-animation')\n animatedElements.forEach((item, index) => {\n const delay = index == 0 ? 0.12 : 0.12 + index * 0.06\n item.style.transitionDelay = `${delay}s`\n })\n })\n const toggleSubmenu = element => {\n const menuItem = element.target.closest('.Navbar-menuItem')\n const [submenu] = menuItem.getElementsByTagName('ul')\n const submenuItems = submenu.getElementsByTagName('li')\n let submenuHeight = 0\n\n menuItem.classList.toggle('is-open')\n\n if (menuItem.className.includes('is-open')) {\n for (let i = submenuItems.length - 1; i >= 0; i--) {\n submenuHeight += submenuItems[i].offsetHeight\n }\n }\n\n submenu.style.height = `${submenuHeight}px`\n }\n\n return (\n <>\n <div className={cx('Navbar-overlay', { 'Navbar-overlay--is-active': isOpen })}></div>\n <nav className={cx('Navbar', { 'Navbar--is-open': isOpen })}>\n <ul>\n <li className=\"Navbar-menuItem appear-animation\">\n <button type=\"button\" className=\"Navbar-CloseButton\" onClick={() => closeNavbar()}>\n <Icons name=\"Close\" black className=\"Navbar-CloseIcon\" />\n </button>\n </li>\n {menu.map(({ ...menuItem }, key) => (\n <li className=\"Navbar-menuItem appear-animation\" key={key}>\n <div>\n <Link to={menuItem.url} className=\"Navbar-menuLink\" onClick={() => closeNavbar()}>\n {menuItem.text}\n </Link>\n <button\n type=\"button\"\n className=\"Navbar-menuButton\"\n onClick={element => toggleSubmenu(element)}\n >\n <span className=\"Navbar-menuArrowIcon\"></span>\n </button>\n </div>\n <ul className=\"Navbar-submenu\">\n {menuItem.submenu.map(({ ...submenuItem }, key) => (\n <li className=\"Navbar-submenuItem\" key={key}>\n <Link\n to={submenuItem.url}\n className=\"Navbar-submenuLink\"\n onClick={() => closeNavbar()}\n >\n {submenuItem.text}\n </Link>\n </li>\n ))}\n </ul>\n </li>\n ))}\n </ul>\n <div className=\"Navbar-menuItem appear-animation Navbar-social\">\n <SocialLinks />\n </div>\n </nav>\n </>\n )\n}\n\nexport default Navbar\n", | |
| "style": ".Navbar {\n background-color: #F3F3F3;\n bottom: 0;\n color: #000;\n height: 100%;\n overflow: auto;\n padding: 0 20px 20px;\n position: fixed;\n right: -300px;\n transition: right .3s ease;\n width: 300px;\n z-index: 2;\n}\n\n.Navbar--is-open {\n right: 0;\n}\n\n.Navbar-overlay {\n position: fixed;\n left: 0;\n top: 0;\n bottom: 0;\n right: 0;\n background: #aeb1b8;\n opacity: 0;\n pointer-events: none;\n}\n\n.Navbar-overlay--is-active {\n opacity: 0.6;\n transition: opacity 0.3s linear;\n}\n\n.Navbar-menuItem {\n border-bottom: 1px solid #DEDEDE;\n margin-bottom: 4px;\n}\n\n.Navbar-menuItem:first-child {\n padding: 20px 0 16px;\n text-align: right;\n}\n\n.Navbar-menuItem.is-open .Navbar-submenu {\n opacity: 1;\n visibility: visible;\n}\n\n.Navbar-menuItem.is-open .Navbar-menuArrowIcon:before {\n transform: rotate(-45deg);\n}\n\n.Navbar-menuItem.is-open .Navbar-menuArrowIcon:after {\n transform: rotate(45deg);\n}\n\n.Navbar-menuLink,\n.Navbar-menuButton {\n color: #000;\n display: inline-block;\n padding: 18px 0;\n width: 50%;\n}\n\n.Navbar-menuLink {\n font-family: \"Gotham-Bold\", sans-serif;\n font-weight: 400;\n line-height: 1.6;\n text-decoration: none;\n}\n\n.Navbar-menuButton {\n text-align: right;\n}\n\n.Navbar-menuButtonClose {\n margin: 20px 0;\n text-align: right;\n width: 25%;\n}\n\n.Navbar-menuArrowIcon {\n height: 16px;\n display: inline-block;\n position: relative;\n width: 16px;\n}\n\n.Navbar-CloseIcon {\n height: 28px;\n display: inline-block;\n position: relative;\n width: 20px;\n}\n\n.Navbar-menuArrowIcon:before,\n.Navbar-menuArrowIcon:after,\n.Navbar-CloseIcon:before,\n.Navbar-CloseIcon:after {\n background-color: #000;\n content: '';\n display: inline-block;\n height: 2px;\n position: absolute;\n top: 12px;\n transition: transform .2s ease;\n width: 10px;\n}\n\n.Navbar-menuArrowIcon:before,\n.Navbar-CloseIcon:before {\n left: 0;\n transform: rotate(45deg);\n}\n\n.Navbar-menuArrowIcon:after,\n.Navbar-CloseIcon:after {\n right: 0;\n transform: rotate(-45deg);\n}\n\n.Navbar-CloseIcon:before,\n.Navbar-CloseIcon:after {\n width: 20px;\n}\n\n.Navbar-submenu {\n height: 0;\n opacity: 0;\n transition: height .3s ease, opacity .3s ease;\n visibility: hidden;\n}\n\n.Navbar-submenuItem {\n padding: 4px 0 8px;\n}\n\n.Navbar-submenuLink {\n color: #000;\n font-size: 15px;\n text-decoration: none;\n}\n\n.appear-animation {\n opacity: 0;\n transform: translateY(100px);\n transition: opacity 0.4s cubic-bezier(0.165, 0.84, 0.44, 1), transform 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);\n}\n\n.appear-animation.animate {\n opacity: 1;\n transform: translateY(0);\n}\n\n.Navbar-social {\n border-bottom: 0;\n padding: 18px 0;\n}\n\n.Navbar--is-open .appear-animation {\n opacity: 1;\n transform: translateY(0px);\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Hero", | |
| "code": "import React, { useState, useEffect } from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport Link from 'frontend-link'\n\nimport './styles.css'\n\nconst Hero = ({ slides = [] }) => {\n const [active, setActive] = useState(0)\n\n const handlePrevClick = () => {\n setActive(prevActive => (prevActive + slides.length - 1) % slides.length)\n }\n const handleNextClick = () => {\n setActive(prevActive => (prevActive + 1) % slides.length)\n }\n\n useEffect(() => {\n const interval = setInterval(handleNextClick, 5000)\n\n return () => {\n clearInterval(interval)\n }\n }, [slides.length])\n\n return (\n <div className=\"Hero-wrapper\">\n <div className=\"Hero-prev\" onClick={handlePrevClick}></div>\n <div className=\"Hero-next\" onClick={handleNextClick}></div>\n {slides.map(({ title, subtitle, ctaHref, ctaText, img }, i) => {\n return (\n <div\n key={i}\n className={cx('Hero', { 'Hero-fade-in': i == active })}\n style={{ backgroundImage: `url('${img}')` }}\n >\n <article className=\"Hero-gradient\" key={title}>\n <PageWidth className=\"Hero-content\">\n <h2 className=\"Hero-title\">{title}</h2>\n <p className=\"Hero-subtitle subtitle\">{subtitle}</p>\n <Link href={ctaHref} className=\"Btn Btn--inverted Btn--hero\">\n {ctaText}\n </Link>\n </PageWidth>\n </article>\n </div>\n )\n })}\n\n <div className=\"Hero-dots\">\n {slides.map((slide, i) => (\n <div\n key={i}\n className={cx('Hero-dots-dot', { 'Hero-dots-dot--active': active === i })}\n onClick={() => setActive(i)}\n />\n ))}\n </div>\n </div>\n )\n}\n\nexport default Hero\n", | |
| "style": ".Hero-wrapper {\n width: 100%;\n height: 85vh;\n position: relative;\n}\n.Hero-prev, .Hero-next {\n width: 40px;\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 2;\n cursor: pointer;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n background-image: url('https://cdn.shopify.com/s/files/1/0384/6721/files/Arrow_Left.svg?60034');\n}\n.Hero-next {\n left: auto;\n right: 0;\n background-image: url('https://cdn.shopify.com/s/files/1/0384/6721/files/Arrow_Right.svg?60034');\n}\n\n.Hero {\n background-repeat: no-repeat;\n background-position: center center;\n background-size: cover;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n opacity: 0;\n z-index: 0;\n transition: opacity 1.5s ease;\n}\n\n.Hero-content {\n padding: 30px 40px;\n\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n align-items: flex-start;\n color: #fff;\n}\n\n.Hero-title {\n font-size: 48px;\n line-height: 1;\n margin-bottom: 8px;\n}\n\n.Hero-subtitle {\n font-family: Inconsolata;\n font-size: 26px;\n line-height: 1;\n margin-bottom: 20px;\n}\n\n.Hero-dots {\n position: absolute;\n bottom: 20px;\n left: 92%;\n z-index: 1;\n}\n\n.Hero-dots-dot {\n display: inline-block;\n height: 10px;\n width: 10px;\n border: 2px solid #cacaca;\n cursor: pointer;\n}\n\n.Hero-dots-dot:not(:last-child) {\n margin-right: 10px;\n}\n\n.Hero-dots-dot--active {\n background-color: #cacaca;\n}\n\n.Hero-fade-in {\n opacity: 1;\n z-index: 1;\n}\n\n.Hero-gradient {\n width: 100%;\n height: 100%;\n background: linear-gradient(rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 0.7));\n}\n\n@media (max-width: 767px) {\n .Hero-wrapper {\n height: 400px;\n }\n .Hero-content {\n padding: 25px 40px;\n }\n .Hero-title {\n font-size: 36px;\n }\n .Hero-subtitle {\n font-size: 20px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductBoxWithDonation", | |
| "code": "import React, { useState, useEffect } from 'react'\nimport { useHistory, useLocation } from 'react-router-dom'\nimport queryString from 'query-string'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport AddToCart from 'Components/AddToCart'\nimport Carousel from 'Components/Carousel'\nimport Accordions from 'Components/Accordions'\nimport StarRating from 'Components/StarRating'\nimport Input from 'Components/Input'\nimport Button from 'Components/Button'\n\nimport './styles.css'\n\nconst ProductBoxWithDonation = ({\n options,\n variants,\n productName,\n productSubTitle,\n productID,\n images,\n originalPrice,\n price,\n reviewsRating,\n reviewsCount,\n carbonfundInfo,\n description,\n info,\n faq,\n}) => {\n const history = useHistory()\n const location = useLocation()\n const [currentVariant, setCurrentVariant] = useState(variants[0])\n\n const accordionItems = [\n {\n title: 'Carbonfund.org',\n content: carbonfundInfo,\n },\n {\n title: 'Description',\n content: description,\n },\n {\n title: 'Info',\n content: info,\n },\n {\n title: 'FAQ',\n content: faq,\n },\n ]\n\n const variantId = queryString.parse(location.search).variant\n\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.dataLayer === 'undefined') return\n if (!currentVariant) return\n\n window.dataLayer.push({\n event: 'productDetailView',\n ecommerce: {\n currencyCode: 'USD',\n detail: {\n products: [\n {\n name: productName,\n productId: productID,\n category: productSubTitle,\n\n id: currentVariant.sku,\n variantId: currentVariant.id,\n variant: currentVariant.name,\n price: currentVariant.price,\n compareAtPrice: currentVariant.price,\n inventoryCount: currentVariant.quantity,\n\n brand: 'Nomad Goods',\n },\n ],\n },\n },\n })\n }, [variantId])\n\n const getVariant = (variants, option2) => {\n return variants.find(v => v.option2 === option2)\n }\n\n const handleVariantClick = value => () => {\n const variant = getVariant(variants, value)\n setCurrentVariant(variant)\n history.push({ search: `?variant=${variant.id}` })\n }\n\n return (\n <div className=\"ProductBoxWithDonation\">\n <PageWidth className=\"ProductBoxWithDonation-container\">\n {images && <Carousel images={images} />}\n\n <section className=\"ProductBoxWithDonation-content\">\n <h2 className=\"ProductBoxWithDonation-title\">{productName}</h2>\n <p className=\"ProductBoxWithDonation-desc\">{productSubTitle}</p>\n\n <hr className=\"ProductBoxWithDonation-divider\" />\n\n <span className=\"ProductBoxWithDonation-price is-strikethrough\">${originalPrice}</span>\n <span className=\"ProductBoxWithDonation-price\">${price}</span>\n <span className=\"ProductBoxWithDonation-free\">Free Cable</span>\n\n <span className=\"ProductBoxWithDonation-donation\">\n + ${currentVariant.price} Donation\n </span>\n\n <div className=\"ProductBoxWithDonation-reviews\">\n {reviewsRating && <StarRating rate={reviewsRating} />}\n {reviewsCount && (\n <p className=\"ProductBoxWithDonation-reviews-count\">{reviewsCount} Reviews</p>\n )}\n </div>\n\n {options &&\n options.map((option, optionsIndex) => {\n return (\n option.values.length > 1 && (\n <React.Fragment key={option.id}>\n <span>{option.name}</span>\n <div className=\"ProductBoxWithDonation-options-wrapper\">\n {option.values.map(value => (\n <div\n key={value}\n role=\"button\"\n className={cx('ProductBoxWithDonation-option', {\n active: value === currentVariant[`option${optionsIndex + 1}`],\n })}\n onClick={handleVariantClick(value)}\n >\n {value}\n </div>\n ))}\n </div>\n </React.Fragment>\n )\n )\n })}\n\n <AddToCart variantId={currentVariant.id}>Add to Cart</AddToCart>\n\n <Accordions items={accordionItems} />\n\n <div className=\"ProductBoxWithDonation-subscribe\">\n <p>Get notified for our next carbon offset event</p>\n\n <form className=\"ProductBoxWithDonation-form\" method=\"post\">\n <label className=\"visually-hidden\">Email address</label>\n <Input type=\"email\" placeholder=\"Enter your email address\" />\n <div className=\"ProductBoxWithDonation-form-actions\">\n <Button\n className=\"Btn--black ProductBoxWithDonation-form-btn\"\n as=\"button\"\n type=\"submit\"\n >\n Subscribe\n </Button>\n </div>\n </form>\n </div>\n </section>\n </PageWidth>\n </div>\n )\n}\n\nexport default ProductBoxWithDonation\n", | |
| "style": ".ProductBoxWithDonation {\n padding: 60px 0;\n background-color: #f3f3f3;\n}\n\n.ProductBoxWithDonation-container {\n display: grid;\n grid-template-columns: 3fr 2fr;\n}\n\n.ProductBoxWithDonation-content {\n margin: 45px 0 0 70px;\n}\n\n.ProductBoxWithDonation-title {\n font-size: 30px;\n}\n\n.ProductBoxWithDonation-desc {\n font-size: 17px;\n font-family: 'Gotham-Book';\n}\n\n.ProductBoxWithDonation-divider {\n margin: 25px 0;\n border: 1px solid #dedede;\n}\n\n.ProductBoxWithDonation-price {\n display: inline-block;\n font-size: 24px;\n font-family: 'Gotham-Bold';\n}\n\n.ProductBoxWithDonation-price.is-strikethrough {\n margin-right: 15px;\n text-decoration: line-through;\n}\n\n.ProductBoxWithDonation-free {\n font-family: 'Gotham-Bold';\n margin-left: 10px;\n}\n\n.ProductBoxWithDonation-donation {\n display: block;\n font-size: 24px;\n font-family: 'Gotham-Bold';\n}\n\n.ProductBoxWithDonation-reviews {\n display: flex;\n font-family: 'Gotham-Book';\n font-size: 12px;\n margin-bottom: 25px;\n}\n\n.ProductBoxWithDonation-reviews-count {\n margin-left: 15px;\n}\n\n.ProductBoxWithDonation-options-wrapper {\n margin-bottom: 20px;\n}\n\n.ProductBoxWithDonation-option {\n position: relative;\n display: inline-block;\n padding: 7px 15px 7px;\n margin: 0 15px 12px 0;\n background-color: #ffffff;\n cursor: pointer;\n}\n\n.ProductBoxWithDonation-option:after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n border: 1px solid #dedede;\n z-index: 1;\n box-sizing: border-box;\n}\n\n.ProductBoxWithDonation-option.active:after {\n border: 2px solid #000000;\n}\n\n.ProductBoxWithDonation-subscribe {\n margin-top: 50px;\n}\n\n.ProductBoxWithDonation-subscribe p {\n font-size: 14px;\n}\n\n.ProductBoxWithDonation-form {\n display: flex;\n align-items: center;\n}\n\n.ProductBoxWithDonation-subscribe .InputGroup {\n flex: 1;\n margin-right: 5px;\n}\n\n.ProductBoxWithDonation-form-btn {\n position: relative;\n top: -3px;\n padding: 6px 20px;\n}\n\n@media (max-width: 767px) {\n .ProductBoxWithDonation {\n padding-bottom: 40px;\n }\n\n .ProductBoxWithDonation-container {\n grid-template-columns: 1fr;\n }\n\n .ProductBoxWithDonation-content {\n margin: 20px 0 0;\n }\n\n .ProductBoxWithDonation-desc {\n font-size: 14px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Blogs", | |
| "code": "import React, { useState } from 'react'\nimport BlogPostItem from 'Components/BlogPostItem'\nimport PageWidth from 'Components/PageWidth'\nimport Pagination from 'Components/Pagination'\n\nimport './styles.css'\n\nconst Blogs = ({ blogs }) => {\n const [currentPage, setCurrentPage] = useState(3)\n\n return (\n <PageWidth className=\"Blogs\">\n {blogs.map((blog, index) => (\n <BlogPostItem key={index} {...blog} />\n ))}\n <Pagination current={currentPage} total={80} onChange={setCurrentPage} />\n </PageWidth>\n )\n}\n\nexport default Blogs\n", | |
| "style": ".Blogs {\n}\n\n@media (min-width: 768px) {\n .Blogs {\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Footer", | |
| "code": "import React from 'react'\nimport Link from 'frontend-link'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport SocialLinks from 'Components/SocialLinks'\nimport PageWidth from 'Components/PageWidth'\nimport './styles.css'\n\nconst menu = [\n {\n text: 'Support',\n submenu: [\n {\n text: 'Return & Exchange',\n url: '/pages/support',\n },\n {\n text: 'Shipping Info',\n url: '/pages/shipping',\n },\n {\n text: \"FAQ's\",\n url: 'https://help.hellonomad.com/',\n },\n {\n text: 'Log In',\n url: '/account/login',\n },\n ],\n },\n {\n text: 'About',\n submenu: [\n {\n text: 'About Us',\n url: 'pages/about',\n },\n {\n text: 'Press',\n url: '/pages/press',\n },\n {\n text: 'Careers',\n url: '/pages/careers',\n },\n {\n text: 'Affiliates',\n url: '/pages/affiliates',\n },\n ],\n },\n {\n text: 'Sales',\n submenu: [\n {\n text: 'Corporate Sales',\n url: '/pages/corporate',\n },\n {\n text: 'Wholesale',\n url: '/pages/wholesale-landing',\n },\n {\n text: \"Where We're Sold\",\n url: 'pages/where-we-are-sold',\n },\n {\n text: 'Assets',\n url: '/pages/assets',\n },\n ],\n },\n {\n text: 'Discover',\n submenu: [\n {\n text: 'The Nomadic',\n url: '/blogs/the-nomadic',\n },\n {\n text: 'Wallpapers',\n url: '/pages/wallpapers',\n },\n {\n text: 'Our Friends',\n url: '/pages/our-friends',\n },\n {\n text: 'Holiday Sale',\n url: 'collections/outletsale',\n },\n ],\n },\n]\n\nconst Footer = () => {\n const toggleMenu = element => {\n element.target.parentNode.classList.toggle('is-open')\n }\n\n return (\n <footer className=\"Footer\">\n <PageWidth>\n <div className=\"Footer-row\">\n <ul className=\"Footer-menu\">\n {menu.map(({ ...menuItem }, key) => (\n <li className=\"Footer-menuItem\" key={key}>\n <div className=\"Footer-menuColumnHeader--hideOnSmallScreen\">{menuItem.text}</div>\n <button\n className=\"Footer-menuColumnHeader\"\n onClick={element => toggleMenu(element)}\n >\n {menuItem.text}\n <span className=\"Footer-menuArrowIcon\"></span>\n </button>\n <ul className=\"Footer-submenu\">\n {menuItem.submenu.map(({ ...submenuItem }, key) => (\n <li className=\"Footer-submenuItem\" key={key}>\n <Link to={submenuItem.url} className=\"Footer-submenuLink\">\n {submenuItem.text}\n </Link>\n </li>\n ))}\n </ul>\n </li>\n ))}\n </ul>\n <div className=\"Footer-form\">\n <div className=\"Footer-form-copy\">New Products, Blogs, and Deals.</div>\n <form>\n <input type=\"email\" className=\"Footer-form-email\" placeholder=\"Email\" />\n <Button as=\"button\" type=\"submit\" value=\"submit\">\n Subscribe\n </Button>\n </form>\n </div>\n </div>\n <div className=\"Footer-row Footer-row--logoAndSocials\">\n <div className=\"Footer-logo\">\n <Link to=\"/\" className=\"LogoNomad\">\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo\"\n />\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo--small\"\n />\n </Link>\n </div>\n <div className=\"Footer-social\">\n <SocialLinks white />\n </div>\n </div>\n <div className=\"Footer-row\">\n <div className=\"Footer-copyright\">2020 Nomad Goods, Inc. All rights reserved.</div>\n <div className=\"Footer-privacy\">\n <Link to=\"/pages/privacy\">Privacy</Link>\n <Link to=\"/pages/terms\">Terms</Link>\n </div>\n </div>\n </PageWidth>\n </footer>\n )\n}\n\nexport default Footer\n", | |
| "style": ".Footer {\n background: url(https://cdn.shopify.com/s/files/1/0384/6721/t/101/assets/Topo_Footer_04_-_Mobile_v3.svg) no-repeat;\n background-size: cover;\n padding: 20px 0;\n background-color: #000;\n}\n\n.Footer-row {\n display: flex;\n justify-content: space-between;\n flex-direction: column;\n padding: 20px 0;\n}\n\n.Footer-logo {\n max-width: 110px;\n display: none;\n}\n\n.Footer-logo .LogoNomad-logo {\n max-width: 100%;\n display: block;\n}\n\n.Footer-logo .LogoNomad {\n display: block;\n}\n\n.Footer-row--logoAndSocials {\n padding-top: 0;\n margin-bottom: 20px;\n border-bottom: 1px solid #212121;\n align-items: center;\n justify-content: flex-start;\n}\n\n.Footer-menuItem {\n border-bottom: 1px solid #212121;\n margin-bottom: 4px;\n}\n\n.Footer-menuItem.is-open .Footer-submenu {\n height: 164px;\n opacity: 1;\n visibility: visible;\n}\n\n.Footer-menuItem.is-open .Footer-menuArrowIcon:before {\n transform: rotate(-45deg);\n}\n\n.Footer-menuItem.is-open .Footer-menuArrowIcon:after {\n transform: rotate(45deg);\n}\n\n.Footer-menuColumnHeader--hideOnSmallScreen,\n.Footer-menuColumnHeader {\n color: #fff;\n display: flex;\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 16px;\n font-weight: 400;\n justify-content: space-between;\n line-height: 1.6;\n margin: 20px 0;\n width: 100%;\n}\n\n.Footer-menuColumnHeader--hideOnSmallScreen {\n display: none;\n}\n\n.Footer-menuArrowIcon {\n display: inline-block;\n height: 14px;\n position: relative;\n width: 16px;\n pointer-events: none;\n}\n\n.Footer-menuArrowIcon:before,\n.Footer-menuArrowIcon:after {\n background-color: #efefef;\n content: '';\n display: inline-block;\n height: 2px;\n position: absolute;\n top: 12px;\n transition: transform 0.2s ease;\n width: 10px;\n}\n\n.Footer-menuArrowIcon:before {\n left: 0;\n transform: rotate(45deg);\n}\n\n.Footer-menuArrowIcon:after {\n right: 0;\n transform: rotate(-45deg);\n}\n\n.Footer-submenu {\n height: 0;\n opacity: 0;\n transition: height 0.3s ease, opacity 0.3s ease;\n visibility: hidden;\n}\n\n.Footer-submenuItem {\n padding: 4px 0 8px;\n}\n\n.Footer-submenuLink {\n color: #fff;\n font-size: 15px;\n text-decoration: none;\n}\n\n.Footer-social {\n color: #fff;\n margin: 0;\n width: 100%;\n}\n\n.Footer-privacy {\n margin-top: 10px;\n padding-bottom: 44px;\n}\n\n.Footer-copyright,\n.Footer-privacy a {\n color: #b4b4b4;\n font-size: 14px;\n text-decoration: none;\n}\n\n.Footer-privacy a:not(:last-child):after {\n content: '|';\n padding: 0 13px;\n}\n\n.Footer-form {\n color: white;\n font-size: 14px;\n margin: 20px 0;\n flex: 1;\n order: -1;\n}\n\n.Footer-form-copy {\n margin-bottom: 15px;\n}\n\n.Footer-form form {\n display: flex;\n}\n\n.Footer-form input,\n.Footer-form button {\n background: transparent;\n padding: 8px 16px;\n border: 1px solid white;\n color: white;\n line-height: 1.5;\n}\n\n.Footer-form-email {\n margin-right: 7px;\n flex: 1;\n}\n\n@media (min-width: 768px) {\n .Footer {\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/t/110/assets/Topo_Footer_03.svg);\n }\n\n .Footer-row {\n flex-direction: row;\n }\n\n .Footer-menu {\n display: flex;\n }\n\n .Footer-menuItem + .Footer-menuItem {\n margin-left: 45px;\n }\n\n .Footer-menuItem {\n border: 0;\n margin-bottom: 0;\n }\n\n .Footer-submenu {\n height: auto;\n opacity: 1;\n visibility: visible;\n }\n\n .Footer-privacy {\n margin-top: 0;\n }\n\n .Footer-menuColumnHeader {\n display: none;\n }\n\n .Footer-menuColumnHeader--hideOnSmallScreen {\n display: flex;\n }\n\n .Footer-logo {\n display: block;\n }\n\n .Footer-row--logoAndSocials {\n border-bottom: 1px solid #b4b4b4;\n margin-bottom: 0;\n padding: 20px 0;\n justify-content: space-between;\n }\n\n .Footer-social {\n width: auto;\n }\n\n .Footer-form {\n margin: 20px 0 20px 20px;\n max-width: 354px;\n order: 0;\n }\n\n .Footer-form-email {\n max-width: 250px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductImageWithComparisonOnHover", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\n\nimport './styles.css'\n\nconst ProductImageWithComparisonOnHover = ({ img, oldImg, alt = '' }) => (\n <div className=\"ProductImageWithComparisonOnHover\">\n <ResponsiveImage\n className=\"ProductImageWithComparisonOnHover-img\"\n src={oldImg || img}\n alt={alt}\n aria-hidden=\"true\"\n loading=\"lazy\"\n />\n <ResponsiveImage\n className=\"ProductImageWithComparisonOnHover-img origin\"\n src={img}\n alt={alt}\n aria-hidden=\"true\"\n />\n </div>\n)\n\nexport default ProductImageWithComparisonOnHover\n", | |
| "style": ".ProductImageWithComparisonOnHover {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n padding-top: 100%;\n background-color: #f3f3f3;\n}\n\n.ProductImageWithComparisonOnHover-img {\n position: absolute;\n top: 10px;\n left: 10px;\n width: calc(100% - 20px);\n height: calc(100% - 20px);\n}\n\n.ProductImageWithComparisonOnHover-img.origin{\n transition: opacity .5s ease;\n}\n\n.ProductImageWithComparisonOnHover-img.origin:hover {\n opacity: 0;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "LandingHero", | |
| "code": "import React from 'react'\nimport { useMedia } from 'react-use'\nimport cx from 'classnames'\nimport Slider from 'react-slick'\nimport PageWidth from 'Components/PageWidth'\nimport Link from 'frontend-link'\n\nimport './styles.css'\n\nconst Arrow = ({ next, style, onClick }) => (\n <div className={cx('LandingHero-arrow', { next: next })} style={style} onClick={onClick} />\n)\n\nconst Dots = ({ dots }) => (\n <div className=\"LandingHero-dots\">\n {dots.map(({ props, key }) => (\n <div key={key} className={cx('LandingHero-dots-dot', props.className)} />\n ))}\n </div>\n)\n\nconst SLIDER_SETTINGS = {\n dots: true,\n fade: true,\n infinite: true,\n speed: 500,\n slidesToShow: 1,\n slidesToScroll: 1,\n autoplay: true,\n autoplaySpeed: 5000,\n prevArrow: <Arrow />,\n nextArrow: <Arrow next />,\n // eslint-disable-next-line react/display-name\n appendDots: dots => <Dots dots={dots} />,\n}\n\nconst LandingHero = ({ slides = [], compact }) => (\n <Slider className={cx('LandingHero', { 'LandingHero--compact': compact })} {...SLIDER_SETTINGS}>\n {slides.map(({ title, subtitle, cta, img, imgMobile }, i) => {\n const imgUrl = useMedia('(max-width: 767px)') ? imgMobile : img\n return (\n <div key={i} className=\"LandingHero-container\">\n <div className=\"LandingHero-image\" style={{ backgroundImage: `url('${imgUrl}')` }}>\n <article className=\"LandingHero-gradient\" key={title}>\n <PageWidth className=\"LandingHero-content\">\n <div className=\"LandingHero-detail\">\n <h2 className=\"LandingHero-title\">{title}</h2>\n <p className=\"LandingHero-subtitle\">{subtitle}</p>\n <Link href={cta.href} className=\"Btn Btn--inverted Btn--hero\">\n {cta.text}\n </Link>\n </div>\n </PageWidth>\n </article>\n </div>\n </div>\n )\n })}\n </Slider>\n)\n\nexport default LandingHero\n", | |
| "style": ".LandingHero {\n position: relative;\n width: 100%;\n}\n\n.LandingHero-container {\n height: 85vh;\n}\n\n.LandingHero--compact .LandingHero-container {\n height: 65vh;\n}\n\n.LandingHero-image {\n background-repeat: no-repeat;\n background-position: center center;\n background-size: cover;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n}\n\n.LandingHero-gradient {\n width: 100%;\n height: 100%;\n background: linear-gradient(rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 0.7));\n}\n\n.LandingHero-content {\n display: flex;\n align-items: flex-end;\n color: white;\n height: 100%;\n}\n\n.LandingHero-detail {\n padding-bottom: 25px;\n}\n\n.LandingHero-title {\n font-size: 48px;\n line-height: 1;\n}\n\n.LandingHero-subtitle {\n font-size: 26px;\n line-height: 1.5;\n margin-bottom: 10px;\n}\n\n.LandingHero .slick-list {\n height: 100%;\n overflow: hidden;\n touch-action: pan-y;\n}\n\n.LandingHero .slick-slide {\n display : none;\n float : left;\n height : 100%;\n}\n\n.LandingHero.slick-initialized .slick-slide {\n display: block\n}\n\n.LandingHero-arrow {\n width: 40px;\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 2;\n cursor: pointer;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/files/Arrow_Left.svg?60034);\n}\n\n.LandingHero-arrow.next {\n left: auto;\n right: 0;\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/files/Arrow_Right.svg?60034);\n}\n\n.LandingHero-dots {\n position: absolute;\n top: 80vh;\n margin-left: 2px;\n margin-top: 0px;\n left: 91%;\n}\n\n.LandingHero--compact .LandingHero-dots {\n top: 60vh;\n}\n\n.LandingHero-dots-dot {\n display: inline-block;\n height: 10px;\n width: 10px;\n border: 2px solid #cacaca;\n cursor: pointer;\n}\n\n.LandingHero-dots-dot:not(:first-child):not(:last-child) {\n margin: 0 10px;\n}\n\n.LandingHero-dots-dot.slick-active {\n background-color: #cacaca;\n}\n\n@media (max-width: 767px) {\n .LandingHero-container {\n height: 75vh;\n }\n .LandingHero-dots {\n top: 70vh;\n left: 82%;\n }\n .LandingHero-title {\n font-size: 36px;\n }\n .LandingHero-subtitle {\n font-size: 20px;\n line-height: 1;\n margin-top: 10px;\n }\n\n .LandingHero--compact .LandingHero-container {\n height: 58vh;\n }\n .LandingHero--compact .LandingHero-dots {\n top: 54vh;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Input", | |
| "code": "import React, { useState } from 'react'\nimport cx from 'classnames'\n\nimport './styles.css'\n\nconst Input = ({ id, type, label, placeholder, isRequired, submitted }) => {\n const [value, setValue] = useState('')\n const invalid = submitted && isRequired && !value\n\n return (\n <div className=\"InputGroup\">\n <label htmlFor={id} className={cx('InputGroup-label', { required: isRequired })}>\n {label}\n </label>\n {submitted}\n {type === 'textarea' ? (\n <textarea\n rows=\"3\"\n id={id}\n placeholder={placeholder}\n className=\"InputGroup-input\"\n value={value}\n onChange={({ target }) => setValue(target.value)}\n />\n ) : (\n <input\n type={type}\n id={id}\n placeholder={placeholder}\n className=\"InputGroup-input\"\n value={value}\n onChange={({ target }) => setValue(target.value)}\n />\n )}\n {invalid && <small className=\"InputGroup-error\">This field is required</small>}\n </div>\n )\n}\n\nexport default Input\n", | |
| "style": "\n.InputGroup {\n margin-bottom: 16px;\n}\n\n.InputGroup-label {\n display: block;\n font-family: 'Gotham-Bold';\n margin-bottom: 10px;\n}\n\n.InputGroup-input {\n border: 1px solid #DEDEDE;\n font-size: 15px;\n line-height: 1.5;\n width: 100%;\n padding: 8px 10px;\n}\n\n.InputGroup-error {\n display: block;\n font-size: 15px;\n color: red;\n}\n\n.InputGroup-label.required::after {\n content: '*';\n color: red;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ImageSlider", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport Slider from 'react-slick'\nimport { ResponsiveImage } from 'frontend-ui'\n\nimport './styles.css'\n\nconst Arrow = ({ next, style, onClick }) => (\n <div className={cx('ImageSlider-arrow', { next: next })} style={style} onClick={onClick} />\n)\n\nconst SLIDER_SETTINGS = {\n infinite: true,\n slidesToShow: 1,\n slidesToScroll: 1,\n prevArrow: <Arrow />,\n nextArrow: <Arrow next />,\n}\n\nconst ImageSlider = ({ resources = [] }) => (\n <Slider className=\"ImageSlider\" {...SLIDER_SETTINGS}>\n {resources.map(({ src, alt }, i) => (\n <ResponsiveImage key={i} src={src} alt={alt} />\n ))}\n </Slider>\n)\n\nexport default ImageSlider\n", | |
| "style": ".ImageSlider {\n position: relative;\n width: 100%;\n}\n\n.ImageSlider .slick-list {\n height: 100%;\n overflow: hidden;\n touch-action: pan-y;\n}\n\n.ImageSlider .slick-slide {\n display : none;\n float : left;\n height : 100%;\n}\n\n.ImageSlider.slick-initialized .slick-slide {\n display: block\n}\n\n.ImageSlider-arrow {\n width: 40px;\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 2;\n cursor: pointer;\n background-size: contain;\n background-repeat: no-repeat;\n background-position: center;\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/files/Arrow_Left.svg?60034);\n}\n\n.ImageSlider-arrow.next {\n left: auto;\n right: 0;\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/files/Arrow_Right.svg?60034);\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Supports", | |
| "code": "import React from 'react'\nimport useWindowSize from 'react-use/lib/useWindowSize'\nimport PageWidth from 'Components/PageWidth'\nimport Tabs from 'Components/Tabs'\nimport Accordions from 'Components/Accordions'\nimport Button from 'Components/Button'\nimport RichText from 'Components/RichText'\nimport ContactForm from 'Components/ContactForm'\n\nimport './styles.css'\n\nconst desktopContent = item => {\n const { ctaText, ctaHref, innerHtml, hasContactForm, secondHtml } = item\n return (\n <>\n {ctaText && (\n <div className=\"Supports-action\">\n <Button as=\"a\" className=\"Btn--black\" href={ctaHref}>\n {ctaText}\n </Button>\n </div>\n )}\n <RichText source={innerHtml} />\n {hasContactForm && (\n <ContactForm\n button=\"Send\"\n fullWidth\n noPadding\n fields={[\n {\n id: 'name',\n type: 'text',\n label: 'Name',\n placeholder: 'Name',\n },\n {\n id: 'subject',\n type: 'subject',\n label: 'Subject',\n placeholder: 'Subject',\n isRequired: true,\n },\n {\n id: 'message',\n type: 'textarea',\n label: 'Message',\n placeholder: 'Message',\n isRequired: true,\n },\n {\n id: 'email',\n type: 'email',\n label: 'Email',\n placeholder: 'Email',\n isRequired: true,\n },\n ]}\n />\n )}\n {secondHtml && <RichText source={secondHtml} />}\n </>\n )\n}\n\nconst mobileContent = item => {\n const { ctaText, ctaHref, innerHtml, hasContactForm } = item\n return (\n <>\n <RichText source={innerHtml} />\n {hasContactForm && (\n <ContactForm\n button=\"Send\"\n fullWidth\n noPadding\n fields={[\n {\n id: 'name',\n type: 'text',\n label: 'Name',\n placeholder: 'Name',\n },\n {\n id: 'email',\n type: 'email',\n label: 'Email',\n placeholder: 'Email',\n isRequired: true,\n },\n {\n id: 'message',\n type: 'textarea',\n label: 'Message',\n placeholder: 'Message',\n },\n ]}\n />\n )}\n {ctaText && (\n <div className=\"Supports-action\">\n <Button as=\"a\" className=\"Btn--black\" href={ctaHref}>\n {ctaText}\n </Button>\n </div>\n )}\n </>\n )\n}\n\nconst Supports = ({ items, mobileItems }) => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n\n const tabItems = items.map(item => ({\n title: item.title,\n content: desktopContent(item),\n reverseContent: item.reverseContent,\n }))\n const accordionItems = (mobileItems || items).map(item => ({\n title: item.title,\n content: mobileContent(item),\n reverseContent: item.reverseContent,\n }))\n return (\n <PageWidth className=\"Supports\">\n {isMobile ? <Accordions items={accordionItems} /> : <Tabs items={tabItems} />}\n </PageWidth>\n )\n}\n\nexport default Supports\n", | |
| "style": ".Supports {\n margin-top: 40px;\n margin-bottom: 40px;\n min-height: 400px;\n}\n\n.Supports-action {\n padding: 30px 0 15px;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartPage", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\nimport CartPageEmpty from 'Components/CartPageEmpty'\nimport CartPageItem from 'Components/CartPageItem'\nimport CartPageFooter from 'Components/CartPageFooter'\n\nimport { useCart } from 'frontend-checkout'\n\nimport './styles.css'\n\nconst CartPage = () => {\n const [{ items }] = useCart()\n\n return (\n <PageWidth className=\"CartPage\">\n <h1 className=\"CartPage-title\">Cart</h1>\n {items.length > 0 ? (\n <>\n <div className=\"CartPage-header\">\n <div className=\"CartPage-header-detail\" />\n <div className=\"CartPage-header-quantity\">Quantity</div>\n <div className=\"CartPage-header-total\">Total</div>\n </div>\n <div className=\"CartPage-items\">\n {items.map((item, i) => (\n <CartPageItem key={1} item={item} animationOrderNumber={i + 1} />\n ))}\n </div>\n <CartPageFooter />\n </>\n ) : (\n <CartPageEmpty />\n )}\n </PageWidth>\n )\n}\n\nexport default CartPage\n", | |
| "style": ".CartPage {\n padding-top: 120px;\n padding-bottom: 60px;\n min-height: 700px;\n}\n\n.CartPage-title {\n font-family: \"Gotham-Bold\";\n line-height: 1.6;\n}\n\n.CartPage-header {\n display: flex;\n justify-content: flex-end;\n margin: 50px 0 20px;\n font-family: \"Gotham-Bold\";\n}\n\n.CartPage-header-detail {\n flex: 4.5;\n text-align: center;\n}\n\n.CartPage-header-quantity {\n flex: 1;\n text-align: center;\n}\n\n.CartPage-header-total {\n flex: 2;\n text-align: right;\n}\n\n.CartPage-items {\n border-top: 1px solid #dedede;\n border-bottom: 1px solid #dedede;\n}\n\n@media (max-width: 767px) {\n .CartPage {\n padding-top: 40px;\n padding-bottom: 0;\n min-height: 700px;\n }\n\n .CartPage-title {\n font-size: 1.6875em;\n }\n\n .CartPage-header {\n display: none;\n }\n\n .CartPage-items {\n border-top: none;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleImage", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst BlogArticleImage = ({ src, alt, caption }) => (\n <PageWidth className=\"BlogArticleImage\">\n <ResponsiveImage src={src} alt={alt || caption} loading=\"lazy\" />\n <span>{caption}</span>\n </PageWidth>\n)\n\nexport default BlogArticleImage\n", | |
| "style": ".BlogArticleImage {\n text-align: center;\n margin: 40px auto 75px;\n}\n\n.BlogArticleImage img {\n width: 100%;\n}\n\n@media (max-width: 767px) {\n .BlogArticleImage {\n padding: 0;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartDrawerHeader", | |
| "code": "import React from 'react'\nimport Icons from 'Components/Icons'\n\nimport './styles.css'\n\nconst CartDrawerHeader = ({ isCartShown, hideCart }) => {\n const closeButtonRef = React.useRef(null)\n\n React.useEffect(() => {\n if (closeButtonRef && isCartShown) {\n closeButtonRef.current.focus()\n }\n }, [isCartShown])\n\n const handleHideCart = () => {\n document.querySelector('.LogoNomad').focus()\n hideCart()\n }\n return (\n <div className=\"CartDrawerHeader-container\">\n <h2>Cart</h2>\n <button className=\"CartDrawerHeader-close-btn\" onClick={handleHideCart} ref={closeButtonRef}>\n <Icons name=\"Close\" black className=\"CartDrawerHeader-close-svg\" />\n </button>\n </div>\n )\n}\n\nexport default CartDrawerHeader\n", | |
| "style": ".CartDrawerHeader-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 40px 0;\n border-bottom: 1px solid #dedede;\n}\n\n.CartDrawerHeader-close-btn {\n width: 28px;\n height: 28px;\n cursor: pointer;\n}\n\n.CartDrawerHeader-close-svg {\n width: 100%;\n height: 100%;\n}\n\n@media (max-width: 767px) {\n .CartDrawerHeader-container {\n padding: 15px 0;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ContactForm", | |
| "code": "import React, { useState } from 'react'\nimport cx from 'classnames'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\nimport Input from 'Components/Input'\n\nimport './styles.css'\n\nconst ContactForm = ({ title, action, button, fields, fullWidth, noPadding }) => {\n const [submitted, setSubmitted] = useState(false)\n const onSubmit = e => {\n e.preventDefault()\n setSubmitted(true)\n console.log('---action---', action)\n }\n return (\n <PageWidth>\n <form className={cx('ContactForm', { fullWidth, noPadding })} onSubmit={onSubmit}>\n {title && <h2 className=\"ContactForm-title\">{title}</h2>}\n {fields.map(field => (\n <Input key={field.id} {...field} submitted={submitted} />\n ))}\n <Button as=\"button\" type=\"submit\" className=\"ContactForm-button\">\n {button}\n </Button>\n </form>\n </PageWidth>\n )\n}\n\nexport default ContactForm\n", | |
| "style": ".ContactForm {\n margin-bottom: 120px;\n margin-top: 100px;\n max-width: 600px;\n}\n\n.ContactForm.fullWidth {\n max-width: 100%;\n}\n\n.ContactForm.noPadding {\n margin: 0 -40px;\n}\n\n.ContactForm-title {\n font-family: 'Gotham-Bold', sans-serif;\n margin-bottom: 25px;\n}\n\n.ContactForm-button {\n background-color: #000;\n color: #FFF;\n margin-bottom: 1em;\n}\n\n@media (max-width: 767px) {\n .ContactForm.noPadding {\n margin: 25px 20px 0 40px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CheckoutButton", | |
| "code": "import React from 'react'\nimport Button from 'Components/Button'\n\nimport { useCartState } from 'frontend-checkout'\n\nimport './styles.css'\n\nconst CheckoutButton = ({ children }) => {\n const { checkoutUrl } = useCartState()\n\n return (\n <Button as=\"a\" className=\"CheckoutButton--btn\" href={checkoutUrl}>\n {children}\n </Button>\n )\n}\n\nexport default CheckoutButton\n", | |
| "style": ".CheckoutButton--btn {\n display: flex;\n align-items: center;\n justify-content: center;\n\n width: 100%;\n height: 48px;\n line-height: 24px;\n text-align: center;\n\n background: #000;\n color: #fff;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogBanner", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst BlogBanner = ({ image, date, title, ctaText, ctaHref }) => {\n return (\n <div className=\"BlogBanner\">\n <PageWidth>\n <PageWidth>\n <ResponsiveImage className=\"BlogBanner-background\" src={image} alt=\"\" />\n <div className=\"BlogBanner-info\">\n <p className=\"BlogBanner-date\">{date}</p>\n <h3 className=\"BlogBanner-title\">{title}</h3>\n <Button to={ctaHref} className=\"Btn--default BlogBanner-button\">\n {ctaText}\n </Button>\n </div>\n </PageWidth>\n </PageWidth>\n </div>\n )\n}\n\nexport default BlogBanner\n", | |
| "style": ".BlogBanner {\n padding-bottom: 80px;\n background-color: #f3f3f3;\n}\n\n.BlogBanner-background {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n.BlogBanner-info {\n position: relative;\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n height: 480px;\n color: white;\n}\n\n.BlogBanner-date {\n font-size: 18px;\n}\n\n.BlogBanner-title {\n margin-bottom: 10px;\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 30px;\n text-align: center;\n}\n\n.BlogBanner-button {\n padding: 7px 25px;\n font-family: \"Gotham-Bold\";\n font-size: 18px;\n color: white;\n border: 3px solid white;\n}\n\n@media (max-width: 767px) {\n .BlogBanner {\n height: 415px;\n } \n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "OurFriendsPage", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst OurFriendsPage = ({ friendsList = [] }) => {\n return (\n <PageWidth className=\"OurFriendsPage\">\n {friendsList.map(({ image, name, description, url }) => (\n <div key={name}>\n <a href={url}>\n <ResponsiveImage src={image} className=\"OurFriendsPage-image\" />\n </a>\n <div className=\"OurFriendsPage-info\">\n <p className=\"OurFriendsPage-name\">{name}</p>\n <p className=\"OurFriendsPage-description\">{description}</p>\n </div>\n </div>\n ))}\n </PageWidth>\n )\n}\n\nexport default OurFriendsPage\n", | |
| "style": ".OurFriendsPage {\n display: grid;\n grid-gap: 90px 40px;\n grid-template-columns: 100%;\n margin-bottom: 40px;\n margin-top: 40px;\n}\n\n.OurFriendsPage-image {\n max-width: 100%;\n}\n\n.OurFriendsPage-info {\n padding: 30px 0 40px;\n text-align: center;\n}\n\n.OurFriendsPage-name {\n font-family: 'Gotham-Bold', sans-serif;\n line-height: 1.6;\n margin-bottom: 16px;\n}\n\n@media (min-width: 768px) {\n .OurFriendsPage {\n grid-template-columns: repeat(2, calc(50.0% - 20.0px));\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartPageFooter", | |
| "code": "import React from 'react'\nimport CheckoutButton from 'Components/CheckoutButton'\nimport CartSubtotal from 'Components/CartSubtotal'\n\nimport { useCart } from 'frontend-checkout'\n\nimport './styles.css'\n\nconst CartPageFooter = () => {\n const [{ cart }] = useCart()\n\n return (\n <div className=\"CartPageFooter\">\n <CartSubtotal subtotalPrice={cart.subtotalPrice} currencyCode={cart.currencyCode} />\n <CheckoutButton>Checkout</CheckoutButton>\n </div>\n )\n}\n\nexport default CartPageFooter\n", | |
| "style": ".CartPageFooter {\n width: 40%;\n margin-left: auto;\n text-align: right;\n}\n\n.CartPageFooter .CheckoutButton--btn {\n height: 40px;\n max-width: 130px;\n margin-left: auto;\n}\n\n@media (max-width: 767px) {\n .CartPageFooter {\n width: 100%;\n margin-bottom: 60px;\n text-align: center;\n }\n\n .CartPageFooter-buttons {\n display: flex;\n justify-content: center;\n }\n\n .CartPageFooter-buttons button {\n margin-left: 10px;\n font-size: 0.875em;\n padding: 8px 18px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "StoryMedical", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\nimport RichText from 'Components/RichText'\nimport ImageSlider from 'Components/ImageSlider'\n\nimport './styles.css'\n\nconst StoryMedical = ({ resources = [], detailHTML, mediaHTML, ctaText, ctaHref = '#' }) => {\n const mediaContent = (\n <div className=\"StoryMedical-media\">\n {resources.length > 1 ? (\n <ImageSlider resources={resources} />\n ) : (\n <ResponsiveImage src={resources[0].src} alt={resources[0].alt} />\n )}\n <RichText source={mediaHTML} />\n </div>\n )\n\n const textContent = (\n <div className=\"StoryMedical-text\">\n <RichText source={detailHTML} />\n <Button href={ctaHref} className={cx('StoryMedical-cta', 'Btn--default')}>\n {ctaText}\n </Button>\n </div>\n )\n\n return (\n <div className=\"StoryMedical\">\n <PageWidth className=\"StoryMedical-wrapper\">\n <div className=\"StoryMedical-column\">{textContent}</div>\n <div className=\"StoryMedical-column\">{mediaContent}</div>\n </PageWidth>\n </div>\n )\n}\n\nexport default StoryMedical\n", | |
| "style": ".StoryMedical:nth-child(even) {\n background-color: #f3f3f3;\n}\n\n.StoryMedical:nth-child(odd) {\n background-color: #ffffff;\n}\n\n.StoryMedical-wrapper {\n display: flex;\n padding: 80px 0;\n width: 100%;\n max-width: 1220px;\n}\n\n.StoryMedical-column {\n width: 50%;\n margin: auto 0;\n}\n\n.StoryMedical-media {\n padding: 0 40px;\n}\n\n.StoryMedical-media img {\n display: block;\n}\n\n.StoryMedical-media .RichText {\n margin-top: 20px;\n opacity: 0.55;\n}\n\n.StoryMedical-text {\n padding: 0 60px 0 0;\n}\n\n.StoryMedical-text .RichText h3 {\n margin-bottom: 20px;\n font-size: 27px;\n}\n\n.StoryMedical-text .RichText p {\n margin-bottom: 20px;\n}\n\n.StoryMedical-text .RichText a {\n border: none;\n}\n\n.StoryMedical-text .RichText a::after {\n content: none;\n}\n\n.StoryMedical-cta {\n padding: 9px 20px;\n margin-top: 20px;\n}\n\n.StoryMedical:nth-child(even) .StoryMedical-wrapper {\n flex-direction: row-reverse;\n}\n\n.StoryMedical:nth-child(even) .StoryMedical-media {\n padding: 0;\n}\n\n.StoryMedical:nth-child(even) .StoryMedical-text {\n padding: 0 0 0 60px;\n}\n\n@media (max-width: 767px) {\n .StoryMedical-wrapper {\n flex-direction: column;\n padding: 20px;\n }\n .StoryMedical:nth-child(odd) .StoryMedical-wrapper {\n flex-direction: column-reverse;\n }\n .StoryMedical-column {\n width: 100%;\n }\n .StoryMedical-media {\n padding: 0;\n margin-bottom: 30px;\n }\n .StoryMedical-text .RichText h3 {\n margin-bottom: 10px;\n font-size: 23px;\n }\n .StoryMedical-text {\n padding: 0;\n }\n .StoryMedical-cta {\n margin: 20px 0 60px;\n }\n\n .StoryMedical:nth-child(even) .StoryMedical-wrapper {\n flex-direction: column-reverse;\n }\n .StoryMedical:nth-child(even) .StoryMedical-text {\n padding: 0;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartDrawerItem", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport { useCartActions } from 'frontend-checkout'\n\nimport ItemQuantityInput from 'Components/ItemQuantityInput'\n\nimport './styles.css'\n\nconst currencyFormatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n})\n\nconst CartDrawerItem = ({ item }) => {\n const { getProductTrackingData } = useCartActions()\n\n function trackEvent(eventName) {\n const keys = {\n addToCart: 'add',\n removeFromCart: 'remove',\n }\n\n window.dataLayer.push({\n event: eventName,\n ecommerce: {\n [keys[eventName]]: {\n products: [getProductTrackingData(item)],\n },\n },\n })\n }\n\n return (\n <div className=\"CartDrawerItem\">\n <a className=\"CartDrawerItem-img\" href={`/${item.variant.product.handle}`}>\n <ResponsiveImage\n alt={item.variant.image.altText || item.title}\n src={item.variant.image.src}\n />\n </a>\n <div className=\"CartDrawerItem-details\">\n <a className=\"CartDrawerItem-title\" href={`/${item.variant.product.handle}`}>\n <p>{item.title}</p>\n </a>\n <p className=\"CartDrawerItem-description\">\n {item.description}iPhone 11 Pro Max / Rustic Brown / Moment\n </p>\n <div className=\"CartDrawerItem-balances\">\n <ItemQuantityInput\n itemId={item.id}\n variantId={item.variant.id}\n quantity={item.quantity}\n onRemove={() => {\n trackEvent('removeFromCart')\n }}\n onUpdate={quantityChange =>\n trackEvent(quantityChange > 0 ? 'addToCart' : 'removeFromCart')\n }\n />\n <span className=\"CartDrawerItem-price\">\n {currencyFormatter.format(item.variant.priceV2.amount)}\n </span>\n </div>\n </div>\n </div>\n )\n}\n\nexport default CartDrawerItem\n", | |
| "style": ".CartDrawerItem {\n display: flex;\n margin: 30px 0;\n}\n\n.CartDrawerItem-img {\n flex: 1;\n min-width: 90px;\n}\n\n.CartDrawerItem-img img {\n width: 100%;\n}\n\n.CartDrawerItem-details {\n flex: 2;\n padding-left: 20px;\n}\n\n.CartDrawerItem-title {\n font-size: 1.1875em;\n color: inherit;\n text-decoration: none;\n}\n\n.CartDrawerItem-description {\n font-size: 0.9375em;\n line-height: 1.3;\n margin: 8px 0 11px;\n}\n\n.CartDrawerItem-balances {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n@media (max-width: 767px) {\n .CartDrawerItem {\n margin: 20px 0;\n }\n\n .CartDrawerItem-img {\n flex: 1;\n min-width: 73px;\n }\n\n .CartDrawerItem-title {\n font-size: 1em;\n }\n\n .CartDrawerItem-description {\n font-size: 0.8125em;\n margin: 8px 0 11px;\n }\n\n .CartDrawerItem-price {\n font-size: 0.875em;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleHeader", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst BlogArticleHeader = ({ title, date, dateTime, author }) => (\n <header className=\"BlogArticleHeader\">\n <PageWidth>\n <h1 className=\"BlogArticleHeader-title\">{title}</h1>\n <span>\n <time dateTime={dateTime}>{date}</time> | Words by {author}\n </span>\n </PageWidth>\n </header>\n)\n\nexport default BlogArticleHeader\n", | |
| "style": ".BlogArticleHeader {\n padding: 70px 0 40px 0;\n}\n\n.BlogArticleHeader-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 36px;\n}\n\n@media (max-width: 767px) {\n .BlogArticleHeader {\n padding: 30px 0;\n }\n\n .BlogArticleHeader-title {\n margin-bottom: 10px;\n line-height: 1.1;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogsHeader", | |
| "code": "import React from 'react'\nimport { useHistory } from 'react-router-dom'\nimport cx from 'classnames'\nimport Link from 'Components/BuiltIn/Link'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst data = [\n {\n text: 'The Latest',\n url: '/blogs/the-nomadic',\n },\n {\n text: 'Base Camp',\n url: '/blogs/the-nomadic/tagged/base-camp',\n },\n {\n text: 'Field Guide',\n url: '/blogs/the-nomadic/tagged/field-guide',\n },\n {\n text: 'Journeys',\n url: '/blogs/the-nomadic/tagged/journeys',\n },\n]\n\nconst BlogsHeader = ({ activeId, className }) => {\n const history = useHistory()\n return (\n <PageWidth className={cx('BlogsHeader', className)}>\n <ul>\n {data.map(({ text, url }, i) => (\n // Add active class to li\n <li key={i} className={cx({ active: activeId === i })}>\n <Link to={url}>{text}</Link>\n </li>\n ))}\n </ul>\n <select id=\"BlogTagFilter\" onChange={e => history.push(e.target.value)}>\n {data.map(({ text, url }, i) => (\n <option key={`headernavselect-${i}`} value={url}>\n {text}\n </option>\n ))}\n </select>\n </PageWidth>\n )\n}\n\nexport default BlogsHeader\n", | |
| "style": ".BlogsHeader {\n margin-top: 40px;\n margin-bottom: 50px;\n font-size: 27px;\n font-family: 'Gotham-Book', sans-serif;\n}\n\n.BlogsHeader ul {\n display: flex;\n justify-content: flex-start;\n flex-wrap: wrap;\n}\n\n.BlogsHeader li + li {\n margin-left: 30px;\n}\n\n.BlogsHeader a {\n color: black;\n text-decoration: none;\n line-height: 1.6;\n padding-bottom: 8px;\n}\n\n.BlogsHeader li.active a {\n border-bottom: 2px solid black;\n}\n\n.BlogsHeader select {\n display: none;\n border: 1px solid #dedede;\n padding: 8px 28px 8px 10px;\n font-family: Inconsolata, 'HelveticaNeue', 'Helvetica Neue', sans-serif;\n background-image: url(//cdn.shopify.com/s/files/1/0384/6721/t/110/assets/ico-select.svg?v=1297185…);\n background-repeat: no-repeat;\n background-position: right 10px center;\n background-size: 11px;\n font-size: 16px;\n line-height: 1.5;\n /* for Firefox & Chrome */\n -moz-appearance: none;\n -webkit-appearance: none;\n appearance: none;\n}\n\n/* For IE10 */\n.BlogsHeader select::-ms-expand {\n display: none;\n}\n\n@media (max-width: 767px) {\n .BlogsHeader {\n margin-top: 20px;\n margin-bottom: 30px;\n }\n .BlogsHeader select {\n display: block;\n }\n .BlogsHeader ul {\n display: none;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "StickersForm", | |
| "code": "import React, { useState } from 'react'\nimport './styles.css'\n\nvar EMAIL_PATTERN = new RegExp(\n /^((\"[\\w-\\s]+\")|([\\w-]+(?:\\.[\\w-]+)*)|(\"[\\w-\\s]+\")([\\w-]+(?:\\.[\\w-]+)*))(@((?:[\\w-]+\\.)*\\w[\\w-]{0,66})\\.([a-z]{2,6}(?:\\.[a-z]{2})?)$)|(@\\[?((25[0-5]\\.|2[0-4][0-9]\\.|1[0-9]{2}\\.|[0-9]{1,2}\\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\\]?$)/i,\n)\n\nconst INITIAL_FIELDS = {\n email: '',\n firstname: '',\n lastname: '',\n address: '',\n aprtment: '',\n city: '',\n state: '',\n zip: '',\n country: '',\n phone: '',\n}\n\nconst StickersForm = () => {\n const [fields, setFields] = useState(INITIAL_FIELDS)\n const [errors, setErrors] = useState({})\n const [touched, setTouched] = useState({})\n const [submitted, setSubmitted] = useState(false)\n const [submitSuccess, setSubmitSuccess] = useState(false)\n\n const getErrorMsg = target => {\n if (!target.value) {\n return 'This field is required'\n }\n if (target.name === 'email' && !!target.value && !EMAIL_PATTERN.test(target.value)) {\n return 'Please enter a valid email address.'\n }\n return null\n }\n\n const inputValidation = ({ target }) => {\n setErrors({\n ...errors,\n [target.name]: getErrorMsg(target),\n })\n }\n\n const validateForm = ({ target }) => {\n let formIsValid = true\n const formErrors = {}\n const formElements = [...target.elements]\n formElements.forEach(element => {\n formErrors[element.name] = getErrorMsg(element)\n if (getErrorMsg(element)) formIsValid = false\n })\n setErrors(formErrors)\n return formIsValid\n }\n\n const handleChange = ({ target }) => {\n setFields({\n ...fields,\n [target.name]: target.value,\n })\n }\n\n const handleTouch = ({ target }) => {\n if (!target.name || touched[target.name]) return\n\n setTouched({\n ...touched,\n [target.name]: true,\n })\n }\n\n const onSubmit = e => {\n e.preventDefault()\n setSubmitted(true)\n\n if (!validateForm(e)) return\n\n //TODO: Stickers Form Submitting\n setFields(INITIAL_FIELDS)\n setSubmitted(false)\n setSubmitSuccess(true)\n }\n\n return (\n <>\n <h1 className=\"StickersForm-title\">Sticker Pack</h1>\n <h4 className=\"StickersForm-subtitle\">2020</h4>\n <p className=\"StickersForm-description\">\n We ship high-quality Nomad stickers worldwide, for free. Just let us know where to send\n them.\n <br />\n <br />\n #AdventureOn\n </p>\n {submitSuccess ? (\n <div className=\"StickersForm-submitted\">\n <p className=\"StickersForm-submitted-title\">Awesome!</p>\n <p>\n We'll get these stickers out to you as soon as possible and send you an email for\n confirmation.\n </p>\n </div>\n ) : (\n <form className=\"StickersForm\" method=\"post\" onSubmit={onSubmit} noValidate>\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"email\"\n required\n value={fields.email}\n placeholder=\"Email\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.email) && errors.email && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.email}</div>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"firstname\"\n required\n value={fields.firstname}\n placeholder=\"First Name\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.firstname) && errors.firstname && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.firstname}</div>\n </div>\n )}\n </div>\n <div className=\"StickersForm-input\">\n <input\n type=\"lastname\"\n name=\"lastname\"\n value={fields.lastname}\n placeholder=\"Last Name\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.lastname) && errors.lastname && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.lastname}</div>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"address\"\n value={fields.address}\n placeholder=\"Address\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.address) && errors.address && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.address}</div>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"aprtment\"\n value={fields.aprtment}\n placeholder=\"Apartment, suite, etc. (optional)\"\n onChange={handleChange}\n />\n </div>\n </div>\n\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"city\"\n value={fields.city}\n placeholder=\"City\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.city) && errors.city && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.city}</div>\n </div>\n )}\n </div>\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"state\"\n value={fields.state}\n placeholder=\"State\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.state) && errors.state && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.state}</div>\n </div>\n )}\n </div>\n </div>\n\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"zip\"\n value={fields.zip}\n placeholder=\"ZIP code\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.zip) && errors.zip && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.zip}</div>\n </div>\n )}\n </div>\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"country\"\n value={fields.country}\n placeholder=\"Country/Region\"\n onChange={e => {\n handleChange(e)\n inputValidation(e)\n }}\n onBlur={e => {\n handleTouch(e)\n inputValidation(e)\n }}\n />\n {(submitted || touched.country) && errors.country && (\n <div className=\"StickersForm-input-error-container\">\n <div className=\"StickersForm-input-error\">{errors.country}</div>\n </div>\n )}\n </div>\n </div>\n <div className=\"StickersForm-input-group\">\n <div className=\"StickersForm-input\">\n <input\n type=\"text\"\n name=\"phone\"\n value={fields.phone}\n placeholder=\"Phone Number (for shipping purposes)\"\n onChange={handleChange}\n />\n </div>\n </div>\n <input type=\"submit\" className=\"StickersForm-submit\" value=\"Get Your Stickers\" />\n </form>\n )}\n </>\n )\n}\n\nexport default StickersForm\n", | |
| "style": "\n\n.StickersForm-title {\n font-family: \"Gotham-Bold\";\n font-size: 30px;\n}\n\n.StickersForm-subtitle {\n font-family: \"Gotham-Book\";\n font-size: 1.0625em;\n padding-bottom: 20px;\n border-bottom: 1px solid #dedede;\n}\n\n.StickersForm-description {\n margin-top: 20px;\n}\n\n.StickersForm,\n.StickersForm-submitted {\n padding: 10px 5px;\n margin-top: 20px;\n}\n\n.StickersForm-input-group {\n display: flex;\n padding-bottom: 10px;\n}\n\n.StickersForm-input {\n position: relative;\n width: 100%;\n}\n.StickersForm-input input {\n width: 100%;\n box-sizing: border-box;\n padding-left: 16px;\n height: 38px;\n color: rgb(0, 0, 0);\n font-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;\n border-radius: 2px;\n border: 1px solid rgb(180, 187, 195);\n}\n\n.StickersForm-input input:hover {\n border-color: black;\n}\n\n.StickersForm-input input::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */\n color: rgb(180, 187, 195);\n opacity: 1; /* Firefox */\n}\n\n.StickersForm-input input:-ms-input-placeholder { /* Internet Explorer 10-11 */\n color: rgb(180, 187, 195);\n}\n\n.StickersForm-input input::-ms-input-placeholder { /* Microsoft Edge */\n color: rgb(180, 187, 195);\n}\n\n.StickersForm-input-error-container {\n background-color: white;\n position: absolute;\n z-index: 1;\n top: 48px;\n right: 0px;\n border-radius: 4px;\n animation: 0.4s ease 0s 1 normal none running fadein;\n}\n\n.StickersForm-input-error {\n font-size: 14px;\n font-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;\n line-height: 14px;\n color: rgb(208, 51, 31);\n padding: 8px;\n box-shadow: rgba(0, 0, 0, 0.26) 1px 1px 4px 0px;\n background-color: rgb(248, 236, 233);\n border-radius: 4px;\n border-width: 1px;\n border-style: solid;\n border-color: rgb(208, 51, 31);\n border-image: initial;\n}\n\n.StickersForm-input-error::before,\n.StickersForm-input-error::after {\n content: \"\";\n display: block;\n position: absolute;\n width: 0px;\n height: 0px;\n border-style: solid;\n}\n\n.StickersForm-input-error::before {\n left: 7px;\n top: -17px;\n border-width: 9px;\n border-color: transparent transparent rgb(208, 51, 31);\n}\n\n.StickersForm-input-error::after {\n top: -15px;\n left: 8px;\n border-color: transparent transparent rgb(248, 236, 233);\n border-width: 8px;\n}\n\n.StickersForm-submit {\n margin: 10px 0;\n position: relative;\n padding: 11px 10px;\n color: white;\n font-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;\n font-weight: 700;\n line-height: 1;\n cursor: pointer;\n background: rgb(48, 59, 67);\n border-radius: 2px;\n border-style: none;\n}\n\n.StickersForm-submitted-title {\n font-size: 24px;\n font-weight: 700;\n margin-bottom: 15px;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "QAList", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst QAList = ({ date, title, items = [] }) => {\n return (\n <PageWidth className=\"QAList\">\n <h2 className=\"QAList-title\">{title}</h2>\n {items.map(({ subtitle, texts = [] }) => (\n <React.Fragment key={subtitle}>\n <h3 className=\"QAList-subtitle\">{subtitle}</h3>\n {texts.map((text, key) => (\n <p className=\"QAList-text\" key={key}>\n {text}\n </p>\n ))}\n </React.Fragment>\n ))}\n <p className=\"QAList-date\">{date}</p>\n </PageWidth>\n )\n}\n\nexport default QAList\n", | |
| "style": ".QAList {\n margin-bottom: 80px;\n margin-top: 80px;\n}\n\n.QAList-title {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 27px;\n margin-bottom: 20px;\n}\n\n.QAList-subtitle {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 18px;\n letter-spacing: 0;\n line-height: 1.6;\n margin: 45px 0 18px;\n}\n\n.QAList-text {\n margin-bottom: 10px;\n}\n\n@media (min-width: 768px) {\n .QAList-title {\n font-size: 32px;\n }\n\n .QAList-subtitle {\n font-size: 22px;\n margin: 55px 0 22px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SearchBar", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport SearchInput from 'Components/SearchInput'\nimport Icons from 'Components/Icons'\n\nimport './styles.css'\n\nconst SearchBar = ({ isOpen, closeSearch }) => {\n return (\n <>\n <div className={cx('SearchBar-overlay', { 'SearchBar-overlay--is-active': isOpen })}></div>\n <div className={cx('SearchBar', { 'SearchBar--is-active': isOpen })}>\n <SearchInput isOpen={isOpen} inDrawer />\n <button type=\"button\" onClick={closeSearch}>\n <Icons name=\"Close\" black large />\n </button>\n </div>\n </>\n )\n}\n\nexport default SearchBar\n", | |
| "style": ".SearchBar {\n display: flex;\n position: absolute;\n left: 0;\n right: 0;\n bottom: 100%;\n width: 100%;\n height: 100%;\n z-index: 30;\n overflow: hidden;\n transition: all 0.3s cubic-bezier(0, 0, 0.38, 1);\n background: #fff;\n}\n\n.SearchBar--is-active {\n bottom: 0;\n}\n\n.SearchBar-overlay {\n position: fixed;\n left: 0;\n top: 0;\n bottom: 0;\n right: 0;\n background: #aeb1b8;\n opacity: 0;\n pointer-events: none;\n}\n\n.SearchBar-overlay--is-active {\n opacity: 0.6;\n transition: opacity 0.3s linear;\n}\n\n.SearchBar button {\n padding: 0 20px;\n}\n\n.SearchBar button svg {\n display: block;\n}\n\n\n@media (max-width: 767px) {\n .SearchBar button {\n padding-left: 0;\n }\n}\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartPageEmpty", | |
| "code": "import React from 'react'\nimport Link from 'Components/BuiltIn/Link'\n\nimport './styles.css'\n\nconst CartPageEmpty = () => {\n return (\n <div className=\"CartPageEmpty\">\n <p className=\"CartPageEmpty-text\">Your cart is currently empty.</p>\n <p className=\"CartPageEmpty-text\">\n Continue browsing <Link to=\"/collections/all\">here</Link>.\n </p>\n </div>\n )\n}\n\nexport default CartPageEmpty\n", | |
| "style": ".CartPageEmpty-title {\n font-family: \"Gotham-Bold\";\n line-height: 1.6;\n}\n\n.CartPageEmpty-text {\n padding-bottom: 20px;\n}\n\n.CartPageEmpty-text a {\n text-decoration: none;\n border-bottom: 2px solid rgba(0, 0, 0, 0.1);\n position: relative;\n color: #000;\n -webkit-font-smoothing: antialiased;\n -webkit-text-size-adjust: 100%;\n text-rendering: optimizeSpeed;\n cursor: pointer;\n}\n\n.CartPageEmpty-text a::after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 0%;\n border-bottom: 2px solid #000;\n transition: width 0.5s ease;\n}\n\n.CartPageEmpty-text a:hover::after {\n width: 100%;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SearchBlogPostList", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport PageWidth from 'Components/PageWidth'\nimport Link from 'frontend-link'\nimport './styles.css'\n\nconst SearchBlogPostList = ({ title, blogs = [] }) => {\n return (\n <div className=\"SearchBlogPostList\">\n <PageWidth>\n <h2 className=\"SearchBlogPostList-title\">{title}</h2>\n <ul className=\"SearchBlogPostList-list\">\n {blogs.map(({ id, image, description, url = '' }) => (\n <li className=\"SearchBlogPostList-item\" key={id}>\n <Link to={url || ''} className=\"SearchBlogPostList-itemLink\">\n <div className=\"SearchBlogPostList-image\">\n <ResponsiveImage src={image} alt=\"\" />\n </div>\n <p className=\"SearchBlogPostList-itemdescription\">{description}</p>\n </Link>\n </li>\n ))}\n </ul>\n </PageWidth>\n </div>\n )\n}\n\nexport default SearchBlogPostList\n", | |
| "style": ".SearchBlogPostList {\n padding-top: 60px;\n}\n\n.SearchBlogPostList-title {\n font-family: Gotham-Bold, sans-serif;\n font-size: 32px;\n margin-bottom: 40px;\n}\n\n.SearchBlogPostList-list {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n row-gap: 20px;\n column-gap: 30px;\n padding-bottom: 40px;\n}\n\n.SearchBlogPostList-itemLink {\n text-decoration: inherit;\n color: inherit;\n width: 100%;\n}\n\n.SearchBlogPostList-image {\n height: 250px;\n}\n\n.SearchBlogPostList-image img {\n width: 100%;\n height: 100%;\n}\n\n.SearchBlogPostList-itemdescription {\n margin-top: 10px;\n}\n\n@media (max-width: 767px) {\n .SearchBlogPostList {\n padding-top: 40px;\n }\n\n .SearchBlogPostList-title {\n font-size: 26px;\n margin-bottom: 20px;\n }\n\n .SearchBlogPostList-list {\n grid-template-columns: repeat(1, 1fr);\n row-gap: 20px;\n column-gap: 22px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "AddToCart", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { useCartState, useCartActions } from 'frontend-checkout'\nimport Button from 'Components/Button'\nimport LoadingSpinner from 'Components/LoadingSpinner'\n\nimport './styles.css'\n\nconst IDLE = 'idle'\nconst LOADING = 'loading'\nconst SOLD_OUT = 'sold out'\nconst ERROR = 'error'\n\nconst THREE_SECONDS = 3 * 1000\n\nconst AddToCart = ({ variantId, className, children }) => {\n const [buttonState, setButtonState] = React.useState(IDLE)\n\n const { stock, items } = useCartState()\n const { addItem, showCart, getProductTrackingData } = useCartActions()\n\n React.useEffect(() => {\n if (stock.status === LOADING || stock.status === ERROR) return\n\n if (!stock.itemsAvailableForSale.includes(variantId)) setButtonState(SOLD_OUT)\n }, [stock.status])\n\n function clearError() {\n setButtonState(IDLE)\n }\n\n function trackAddToCartEvent() {\n const item = items.find(item => item.variant.id === variantId)\n\n if (!item) return\n\n window.dataLayer.push({\n event: 'addToCart',\n ecommerce: {\n add: {\n products: [getProductTrackingData(item)],\n },\n },\n })\n }\n\n async function handleAddItemToCart() {\n setButtonState(LOADING)\n try {\n await addItem({ itemId: variantId, quantity: 1 })\n setButtonState(IDLE)\n showCart()\n } catch (e) {\n setButtonState(ERROR)\n setTimeout(clearError, THREE_SECONDS)\n }\n trackAddToCartEvent()\n }\n\n if (buttonState === LOADING)\n return (\n <Button as=\"button\" className={cx(className, 'AddToCart-btn')} type=\"button\">\n <LoadingSpinner />\n </Button>\n )\n\n if (buttonState === SOLD_OUT)\n return (\n <Button\n as=\"button\"\n className={cx(className, 'AddToCart-btn AddToCart-btn-sold')}\n type=\"button\"\n disabled\n >\n Sold out\n </Button>\n )\n\n if (buttonState === ERROR)\n return (\n <Button\n as=\"button\"\n className={cx(className, 'AddToCart-btn')}\n type=\"button\"\n onClick={clearError}\n >\n Adding failed\n </Button>\n )\n\n return (\n <Button\n as=\"button\"\n className={cx(className, 'AddToCart-btn')}\n type=\"button\"\n onClick={handleAddItemToCart}\n >\n {children}\n </Button>\n )\n}\n\nexport default AddToCart\n", | |
| "style": ".AddToCart-btn {\n display: block;\n\n width: 100%;\n height: 48px;\n line-height: 24px;\n text-align: center;\n\n background: black;\n color: white;\n}\n\n.AddToCart-btn-sold {\n background: #adadad;\n cursor: not-allowed;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticle", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Link from 'Components/BuiltIn/Link'\nimport Button from 'Components/Button'\n\nimport './styles.css'\n\nconst BlogArticle = ({\n title,\n date,\n author,\n description,\n category,\n image,\n ctaHref = '#',\n viewAll,\n minimized,\n}) => {\n return (\n <li\n className={cx('BlogArticle', {\n 'BlogArticle--viewAll': viewAll,\n 'BlogArticle--minimized': minimized,\n })}\n >\n <Link to={viewAll ? '/blogs/the-nomadic' : ctaHref} className=\"BlogArticle-link\">\n {viewAll ? (\n 'View All'\n ) : (\n <>\n <ResponsiveImage className=\"BlogArticle-image\" src={image} alt=\"\" />\n <div className=\"BlogArticle-detail\">\n <p className=\"BlogArticle-meta\">\n {date} || {author}\n </p>\n <h3 className=\"BlogArticle-title\">{title}</h3>\n <p className=\"BlogArticle-description\">{description}</p>\n </div>\n <div className=\"BlogArticle-action\">\n <Button as=\"button\" href={ctaHref} className=\"Btn--default\">\n Read More\n </Button>\n <h4 className=\"BlogArticle-category\">{category}</h4>\n </div>\n </>\n )}\n </Link>\n </li>\n )\n}\n\nexport default BlogArticle\n", | |
| "style": ".BlogArticle {\n max-height: 450px;\n background-color: white;\n padding: 20px;\n}\n\n.BlogArticle--viewAll {\n display: flex;\n justify-content: center;\n align-items: center;\n background-image: url(https://cdn.shopify.com/s/files/1/0384/6721/files/Fake_Blurred_Box.jpg?v=1584660473);\n background-size: cover;\n background-position: center;\n}\n\n.BlogArticle-link {\n position: relative;\n display: inline-block;\n text-decoration: inherit;\n color: inherit;\n width: 100%;\n}\n\n.BlogArticle--viewAll .BlogArticle-link {\n width: auto;\n font-family: \"Gotham-Book\";\n font-size: 17px;\n border-bottom: 1px solid;\n color: #000000cf;\n}\n\n.BlogArticle img {\n display: block;\n height: 195px;\n}\n\n.BlogArticle-detail {\n padding: 15px 10px 0px 10px;\n color: inherit;\n}\n\n.BlogArticle-meta {\n margin: 0px 0px 3px 0px;\n font-size: 14px;\n}\n\n.BlogArticle-title {\n font-family: \"Gotham-Bold\";\n font-size: 20px;\n line-height: 1.5;\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n}\n\n.BlogArticle-description {\n position: relative;\n max-height: 70px;\n overflow: hidden;\n}\n\n.BlogArticle-description::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: linear-gradient( rgba(255, 255, 255, 0) 15%, rgba(255, 255, 255, 1) );\n}\n\n.BlogArticle-action {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin: 15px 0 0 10px;\n}\n\n.BlogArticle-action .Btn {\n padding: 3px 12px;\n font-family: \"Gotham-Bold\";\n font-size: 16px;\n line-height: 1.5;\n cursor: pointer;\n}\n\n.BlogArticle-category {\n color: #00000040;\n}\n\n.BlogArticle:hover .BlogArticle-image {\n width: calc(100% + 40px);\n height: 215px;\n margin-left: -20px;\n margin-top: -20px;\n transition: 0.3s;\n animation: ease;\n}\n\n@media (max-width: 767px) {\n .BlogArticle--viewAll {\n background: none;\n }\n\n .BlogArticle-title {\n font-size: 16px;\n }\n\n .BlogArticle-meta {\n font-size: 11px;\n }\n\n .BlogArticle-action .Btn {\n font-size: 13px;\n }\n\n .BlogArticle-category {\n margin: auto 0px auto auto;\n font-size: 13px;\n }\n \n .BlogArticle--minimized {\n margin: 2px -20px 0;\n padding: 15px 15px 15px 15px;\n }\n .BlogArticle--minimized .BlogArticle-link {\n display: flex;\n }\n .BlogArticle--minimized .BlogArticle-action {\n display: none;\n }\n .BlogArticle--minimized .BlogArticle-image {\n width: 120px;\n height: 100%;\n }\n .BlogArticle--minimized .BlogArticle-detail {\n padding: 0 0 0 15px;\n width: calc(100vw - 150px);\n }\n .BlogArticle--minimized .BlogArticle-description {\n font-size: 14px;\n }\n}\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Header", | |
| "code": "import React, { useState, useEffect, useRef } from 'react'\nimport cx from 'classnames'\nimport useWindowScroll from 'react-use/lib/useWindowScroll'\nimport { useCartActions } from 'frontend-checkout'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Link from 'frontend-link'\nimport Navbar from 'Components/Navbar'\nimport CartDrawer from 'Components/CartDrawer'\nimport PageWidth from 'Components/PageWidth'\nimport SearchBar from 'Components/SearchBar'\nimport Button from 'Components/Button'\nimport Icons from 'Components/Icons'\nimport './styles.css'\n\nconst featuredCollections = [\n {\n text: 'Black Horween',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/Horween_Black_-_Collection_Thumbnail_Image_-_02.jpg?v=1587068795',\n url: '/collections/black-collection',\n },\n {\n text: 'Rustic Brown Horween',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/Horween_Rustic_Brown_-_Collection_Thumbnail_Image_-_01.jpg?v=1587068796',\n url: '/collections/rustic-brown-collection',\n },\n {\n text: 'Wireless Power',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/Wireless_Power_-_Collection_Thumbnail_Image_-_01.jpg?v=1587068796',\n url: '/collections/power-wireless-chargin',\n },\n]\n\nconst featuredBlogPosts = [\n {\n text: 'COVID-19 | Our Response',\n imageUrl: 'https://cdn.shopify.com/s/files/1/0384/6721/files/Feature_-_01.jpg?v=1585157063',\n url: '/pages/medical-supplies',\n },\n {\n text: 'How to Office Anywhere',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/74435073_2568171996552528_430185643483200668_n.jpg?v=1584385603',\n url: '/blogs/the-nomadic/remote-work-tips',\n },\n {\n text: 'AirPods Pro Review | Our First Impressions',\n imageUrl:\n 'https://cdn.shopify.com/s/files/1/0384/6721/files/BSAW_AIRPODS_PRO_kraked.jpeg?56606',\n url: '/blogs/the-nomadic/airpods-pro-review',\n },\n]\n\nconst menu = [\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'AirPods Pro',\n url: '/collections/airpods-pro-collection',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'Airpods',\n url: '/collections/cases-airpods',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone 11 Pro Max',\n url: '/collections/cases-for-iphone-11-pro-max',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone 11 Pro',\n url: '/collections/cases-for-iphone-11-pro',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone 11',\n url: '/collections/cases-for-iphone-11',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'iPhone XS / XR',\n url: '/collections/new-2018-iphone-cases',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'Pixel Buds',\n url: '/collections/pixel-buds',\n },\n {\n group: 'Cases',\n collectionUrl: '/collections/cases',\n text: 'Pixel 3 / 4',\n url: '/collections/pixel-4',\n },\n\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Wireless',\n url: '/collections/power-wireless-charging',\n },\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Tesla Model 3',\n url: '/products/tesla-charger',\n },\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Apple Watch',\n url: '/collections/power-apple-watch',\n },\n {\n group: 'Power',\n collectionUrl: '/collections/power',\n text: 'Battery Packs',\n url: '/collections/power-battery-packs',\n },\n\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'Lightning',\n url: '/collections/cables-lightning',\n },\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'Universal',\n url: '/collections/cables-universal',\n },\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'USB-C',\n url: '/collections/cables-usb-c',\n },\n {\n group: 'Cables',\n collectionUrl: '/collections/cables',\n text: 'Micro USB',\n url: '/collections/cables-micro-usb',\n },\n\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Horween Leather',\n url: '/collections/straps-leather',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Active Leather',\n url: '/collections/active-leather-straps',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Metal Bands',\n url: '/collections/active-leather-straps',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Sport Straps',\n url: '/collections/straps-rugged-sport',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Slim Straps',\n url: '/collections/straps-slim',\n },\n {\n group: 'Straps',\n collectionUrl: '/collections/straps',\n text: 'Shell Cordovan',\n url: '/collections/straps-shell-cordovan',\n },\n\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Wallets',\n url: '/collections/wallets',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Passport Wallets',\n url: '/collections/passport-wallet',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Key Chains',\n url: '/collections/key-chains',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Mousepads',\n url: '/collections/mousepads',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Moment Lenses',\n url: '/collections/nomad-x-moment',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Wrist Strap',\n url: '/collections/wrist-strap',\n },\n {\n group: 'Gear',\n collectionUrl: '/collections/gear',\n text: 'Hats',\n url: '/collections/hats',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'New Products',\n url: '/collections/whatsnew',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Blackout Collection',\n url: '/collections/black',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Black Horween',\n url: '/collections/black-collection',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Rustic Brown Horween',\n url: '/collections/rustic-brown-collection',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Active Leather',\n url: '/collections/active-lifestyle',\n },\n {\n group: 'Collections',\n collectionUrl: '/collections',\n text: 'Outlet Sale',\n url: '/collections/outletsale',\n },\n\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'New Products',\n url: '/collections/whatsnew',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Outlet Sale',\n url: '/collections/outletsale',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Free Cable',\n url: '/products/free-cable-for-the-planet',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Wallpapers',\n url: '/pages/wallpapers',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Zoom Backgrounds',\n url: '/pages/wallpapers',\n },\n {\n group: 'Discover',\n collectionUrl: '/whatsnew',\n text: 'Support',\n url: '/pages/support',\n },\n].reduce((acc, item) => {\n const doesSubmenuGroupExists = acc.find(group => group.text === item.group)\n if (!doesSubmenuGroupExists) {\n acc.push({\n text: item.group,\n url: item.collectionUrl,\n submenu: [],\n })\n }\n\n acc[acc.length - 1].submenu.push({\n text: item.text,\n url: item.url,\n })\n\n return acc\n}, [])\n\nconst HeaderSubmenu = ({ menuItem }) => {\n return (\n <div className=\"MenuDropdown-column\">\n <Link to={menuItem.url} className=\"MenuDropdown-column-header\">\n {menuItem.text}\n </Link>\n <ul className=\"MenuDropdown-submenu\">\n {menuItem.submenu.map(({ ...submenuItem }, key) => (\n <li className=\"MenuDropdown-submenu-item\" key={key}>\n <Link to={submenuItem.url}>{submenuItem.text}</Link>\n </li>\n ))}\n </ul>\n </div>\n )\n}\n\nconst MenuBanner = () => (\n <div className=\"MenuDropdown-banner\">\n <Link to=\"/pages/medical-supplies\">Medical Supplies Available | Our Response to COVID-19</Link>\n </div>\n)\n\nconst Header = ({ black = false }) => {\n const { showCart } = useCartActions()\n const { y: scrollY } = useWindowScroll()\n let [isNavbarOpen, setNavbarOpen] = useState(false)\n let [isSearchOpen, setIsSearchOpen] = useState(false)\n\n const header = useRef(null)\n const opacityPoint = 300\n\n const toggleNavbar = () => {\n setNavbarOpen(!isNavbarOpen)\n }\n const toggleSearch = () => {\n setIsSearchOpen(!isSearchOpen)\n }\n\n useEffect(() => {\n if (!black && typeof window !== 'undefined') {\n header.current.style.backgroundColor = `rgba(0,0,0, ${scrollY / opacityPoint})`\n }\n }, [black, scrollY])\n\n return (\n <header ref={header} className={cx('Header', { 'Header--black': black })}>\n <div className=\"Header-top-wrap\">\n <CartDrawer />\n <Navbar menu={menu} isOpen={isNavbarOpen} closeNavbar={toggleNavbar} />\n <SearchBar isOpen={isSearchOpen} closeSearch={toggleSearch} />\n <PageWidth>\n <div className=\"Header-top\">\n <div className=\"Header-left-nav\">\n <Link to=\"/\" className=\"LogoNomad\">\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_130x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo\"\n />\n <ResponsiveImage\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221\"\n alt=\"Nomad Logo\"\n srcSet=\"https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x.png?v=1529008221 1x, https://cdn.shopify.com/s/files/1/0384/6721/files/logo_90x@2x.png?v=1529008221 2x\"\n className=\"LogoNomad-logo--small\"\n />\n </Link>\n <nav className=\"Nav-main\">\n <ul>\n <li className=\"Nav-main-item\">\n <Link to=\"#\">\n <span>Shop</span>\n </Link>\n <div className=\"Nav-main-dropdown MenuDropdown\">\n <div className=\"MenuDropdown-menu\">\n {menu\n .filter(obj => obj.text != 'Discover')\n .map(({ ...menuItem }, key) => (\n <HeaderSubmenu key={key} menuItem={menuItem} />\n ))}\n </div>\n <MenuBanner />\n </div>\n </li>\n <li className=\"Nav-main-item\">\n <Link to=\"/collections/whatsnew\">Discover</Link>\n <div className=\"Nav-main-dropdown MenuDropdown\">\n <div className=\"MenuDropdown-menu discover\">\n {menu\n .filter(obj => obj.text == 'Discover')\n .map(({ ...menuItem }, key) => (\n <HeaderSubmenu key={key} menuItem={menuItem} />\n ))}\n <div className=\"MenuDropdown-column\">\n <span className=\"MenuDropdown-column-header\">Featured Collections</span>\n <ul className=\"MenuDropdown-featured\">\n {featuredCollections.map(({ ...featuredItem }, key) => (\n <li className=\"MenuDropdown-featured-item\" key={key}>\n <Link to={featuredItem.url}>\n <ResponsiveImage\n alt={featuredItem.text}\n src={featuredItem.imageUrl}\n />\n <span>{featuredItem.text}</span>\n </Link>\n </li>\n ))}\n </ul>\n </div>\n </div>\n <MenuBanner />\n </div>\n </li>\n <li className=\"Nav-main-item\">\n <Link to=\"/pages/blog\">The Nomadic</Link>\n <div className=\"Nav-main-dropdown MenuDropdown\">\n <div className=\"MenuDropdown-menu blog\">\n <div className=\"MenuDropdown-column\">\n <div className=\"MenuDropdown-column-info\">\n <span className=\"MenuDropdown-column-header\">The Nomadic Blog</span>\n <p>\n Our blog, where you’ll find stories from behind the scenes, and get a\n glimpse of our lives as Modern Nomads.\n </p>\n <Button to=\"/pages/blog\" className=\"Btn Btn--default\">\n Explore the Blog\n </Button>\n </div>\n </div>\n\n <div className=\"MenuDropdown-column\">\n <span className=\"MenuDropdown-column-header\">Featured Blog Posts</span>\n <ul className=\"MenuDropdown-featured\">\n {featuredBlogPosts.map(({ ...featuredItem }, key) => (\n <li className=\"MenuDropdown-featured-item\" key={key}>\n <Link to={featuredItem.url}>\n <ResponsiveImage\n alt={featuredItem.text}\n src={featuredItem.imageUrl}\n />\n <span>{featuredItem.text}</span>\n </Link>\n </li>\n ))}\n </ul>\n </div>\n </div>\n <MenuBanner />\n </div>\n </li>\n <li className=\"Nav-main-item btn-medical-supplies\">\n <Link to=\"/pages/medical-supplies\">Medical Supplies</Link>\n </li>\n </ul>\n </nav>\n </div>\n <ul className=\"Header-right-nav\">\n <li>\n <button type=\"button\" onClick={toggleSearch}>\n <Icons name=\"Search\" white className=\"Header-search-svg\" />\n </button>\n </li>\n <li>\n <button type=\"button\" className=\"Header-cart\" onClick={showCart}>\n <Icons name=\"Cart\" white className=\"Header-cart-svg\" />\n </button>\n </li>\n <li className=\"ToggleNavDrawer\">\n <button type=\"button\" onClick={toggleNavbar}>\n <Icons name=\"Menu\" white className=\"Header-menuIcon\" />\n </button>\n </li>\n </ul>\n </div>\n </PageWidth>\n </div>\n </header>\n )\n}\n\nexport default Header\n", | |
| "style": ".Header {\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n z-index: 3;\n}\n\n.Header--black {\n position: sticky;\n}\n\n.Header--black {\n background: #000;\n}\n\n.Header button {\n cursor: pointer;\n}\n\n.Header:before {\n bottom: 0;\n content: '';\n display: block;\n left: 0;\n position: absolute;\n top: 0;\n width: 100%;\n background: linear-gradient(to bottom, rgba(0,0,0,0.3) 0%, rgba(0,0,0,0) 100%);\n}\n\n.Header-top-wrap {\n display: flex;\n height: 40px;\n position: relative;\n}\n\n.Header-top {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0;\n width: 100%;\n height: 100%;\n}\n.LogoNomad {\n line-height: 1;\n align-self: center;\n margin-right: 13.5px;\n}\n\n.LogoNomad-logo {\n display: none;\n width: 130px;\n}\n\n.LogoNomad-logo--small {\n width: 90px;\n}\n\n.Header-social {\n color: #000;\n margin: 28px 0 20px;\n}\n\n.Header-title {\n color: #fff;\n font-family: Gotham-Bold, sans-serif;\n font-size: 40px;\n line-height: 1.1;\n padding: 20px;\n position: relative;\n}\n\n.Header-right-nav {\n display: flex;\n align-items: center;\n margin-right: 0;\n}\n\n.Header-right-nav svg {\n display: block;\n}\n\n.Header-right-nav > li {\n padding-left: 20px;\n line-height: 1;\n font-size: 22px;\n display: inline-flex;\n}\n\n.Header-left-nav {\n display: flex;\n height: 100%;\n}\n\n.Nav-main {\n width: 100%;\n display: none;\n}\n\n.Nav-main a {\n text-decoration: none;\n}\n\n.Nav-main > ul {\n display: flex;\n height: 100%;\n box-sizing: border-box;\n padding: 10px 13.5px 0;\n}\n\n.Nav-main-item {\n margin-right: 8px;\n}\n\n.Nav-main-item > a {\n align-items: center;\n display: flex;\n justify-content: center;\n height: 100%;\n padding: 0 15px 10px;\n box-sizing: border-box;\n font-family: 'Gotham-Bold', sans-serif;\n color: white;\n transition: all 0.3s;\n}\n\n.Nav-main-item:hover > a {\n color: black;\n background: white;\n}\n.Nav-main-item:hover .Nav-main-dropdown {\n visibility: visible;\n transform: translate3d(0px, 0px, 0px);\n transition: all 300ms;\n opacity: 1;\n}\n\n.Nav-main-item.btn-medical-supplies {\n margin-bottom: 10px;\n}\n\n.Nav-main-item.btn-medical-supplies a {\n padding: 7px 15px;\n}\n\n.Nav-main-dropdown {\n display: block;\n position: absolute;\n width: 100%;\n left: 40px;\n margin: 0;\n z-index: 5;\n width: calc(100% - 80px);\n visibility: hidden;\n transform: translate3d(-10px, 0px, 0px);\n opacity: 0;\n transition: all 200ms;\n}\n\n.MenuDropdown {\n background: white;\n top: 100%;\n box-shadow: 0px 10px 20px rgba(0,0,0,0.09);\n}\n\n.MenuDropdown-menu {\n box-sizing: border-box;\n padding: 40px 20px;\n display: flex;\n max-width: 1100px;\n text-rendering: optimizeLegibility;\n margin: 0 auto;\n}\n\n.MenuDropdown-menu.discover {\n justify-content: center;\n}\n\n.MenuDropdown-menu.discover .MenuDropdown-column {\n margin-right: 67px;\n margin-left: auto;\n max-width: 180px;\n}\n\n.MenuDropdown-menu.discover .MenuDropdown-column:last-child {\n max-width: 690px;\n margin-left: 0;\n}\n\n.MenuDropdown-menu.blog {\n justify-content: center;\n}\n\n.MenuDropdown-menu.blog .MenuDropdown-column {\n margin-right: 40px;\n margin-left: auto;\n max-width: 270px;\n border: none;\n}\n\n.MenuDropdown-menu.blog .MenuDropdown-column:last-child {\n max-width: 690px;\n margin: 0;\n}\n\n.MenuDropdown-column-info p {\n margin: 3px 25px 40px 0;\n font-size: 15px;\n}\n\n.MenuDropdown-banner {\n background-color: #f3f3f3;\n font-weight: bold;\n text-align: center;\n padding: 10px 20px;\n}\n\n.MenuDropdown-banner a {\n color: #000;\n}\n\n.MenuDropdown-column {\n flex-grow: 1;\n text-align: left;\n position: relative;\n margin-right: 30px;\n max-width: 690px;\n border-right: 2px solid #f3f3f3;\n}\n\n\n.MenuDropdown-column:last-child {\n border: none;\n margin-right: 0;\n}\n\n.MenuDropdown-column:last-child {\n padding-right: 0px;\n}\n\n.MenuDropdown-column:last-child:after {\n display: none;\n}\n\n.MenuDropdown-column--withThumbnail {\n display: flex;\n max-width: 100%;\n color: #000;\n}\n\n.MenuDropdown-column--withThumbnail a {\n color: #000;\n}\n\n.MenuDropdown-column--withThumbnail .left {\n display: flex;\n}\n\n.MenuDropdown-column--withThumbnail .right {\n display: flex;\n width: 100%;\n}\n\n.Thumbnail {\n width: 220px;\n height: 162px;\n overflow: hidden;\n flex-shrink: 0;\n}\n\n.Thumbnail img {\n object-fit: cover;\n min-width: 100%;\n max-height: 100%;\n z-index: -1;\n pointer-events: none;\n}\n\n.MenuDropdown-submenu {\n padding-right: 30px;\n}\n\n.MenuDropdown-submenu-item a {\n color: #000;\n display: inline-block;\n padding: 5px 0;\n font-size: 1em;\n position: relative;\n}\n\n.MenuDropdown-submenu-item a:after {\n border-bottom: 2px solid #000;\n content: ' ';\n display: block;\n position: absolute;\n box-sizing: border-box;\n width: 0%;\n transition: width 0.5s ease;\n height: 0px;\n bottom: 3px;\n}\n\n.MenuDropdown-submenu-item a:hover:after {\n width: 80%;\n}\n\n.MenuDropdown-column-header {\n display: block;\n font-family: Gotham-Bold, sans-serif;\n color: #000;\n font-size: 16px;\n line-height: 1.6;\n padding: 5px 0 10px;\n}\n\n.MenuDropdown-featured {\n display: flex;\n justify-content: space-between;\n width: 100%;\n flex-wrap: wrap;\n}\n\n.MenuDropdown-featured-item {\n position: relative;\n display: block;\n width: 220px;\n height: 162px;\n overflow: hidden;\n cursor: pointer;\n margin-top: 10px;\n}\n\n.MenuDropdown-featured-item:hover {\n opacity: 0.7;\n transition: 0.1s;\n}\n\n.MenuDropdown-featured-item a:before {\n content: \"\";\n display: block;\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n background: linear-gradient(rgba(0, 0, 0, 0) 70%, rgba(0, 0, 0, 0.7));\n z-index: 1;\n}\n\n.MenuDropdown-featured-item a {\n display: block;\n position: relative;\n width: 100%;\n height: 100%;\n}\n\n.MenuDropdown-featured-item img {\n object-fit: cover;\n max-width: 100%;\n height: 100%;\n z-index: -1;\n pointer-events: none;\n}\n\n.MenuDropdown-featured-item span {\n position: absolute;\n bottom: 0px;\n left: 0;\n padding: 0px 0px 6px 12px;\n color: #fff;\n font-size: 14px;\n z-index: 1;\n}\n\n@media (min-width: 768px) {\n .Header-top-wrap {\n height: 60px;\n }\n\n .LogoNomad-logo {\n display: block;\n }\n\n .LogoNomad-logo--small {\n display: none;\n }\n\n .Nav-main {\n display: block;\n }\n\n .Header-right-nav {\n margin-right: 25px;\n }\n\n .Header-right-nav li.ToggleNavDrawer {\n display: none;\n }\n\n .Header-search-form input {\n font-size: 1.5em;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "LoadingSpinner", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst LoadingSpinner = () => {\n return (\n <div className=\"LoadingSpinner-lds-ring\">\n <div></div>\n <div></div>\n <div></div>\n <div></div>\n </div>\n )\n}\n\nexport default LoadingSpinner\n", | |
| "style": ".LoadingSpinner-lds-ring {\n display: inline-block;\n position: relative;\n width: 30px;\n height: 30px;\n}\n\n.LoadingSpinner-lds-ring div {\n box-sizing: border-box;\n display: block;\n position: absolute;\n width: 26px;\n height: 26px;\n border: 4px solid #fff;\n border-radius: 50%;\n animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n border-color: #fff transparent transparent transparent;\n}\n\n.LoadingSpinner-lds-ring div:nth-child(1) {\n animation-delay: -0.45s;\n}\n\n.LoadingSpinner-lds-ring div:nth-child(2) {\n animation-delay: -0.3s;\n}\n\n.LoadingSpinner-lds-ring div:nth-child(3) {\n animation-delay: -0.15s;\n}\n\n@keyframes lds-ring {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartSubtotal", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\n\nimport './styles.css'\n\nlet language\n\nif (typeof window !== 'undefined') {\n language = window.navigator.userLanguage || window.navigator.language\n}\n\nconst CartSubtotal = ({ subtotalPrice, currencyCode, inDrawer }) => {\n const currencyFormatter = new Intl.NumberFormat(language, {\n style: 'currency',\n currency: currencyCode || 'USD',\n })\n\n return (\n <div className={cx('CartSubtotal', { 'CartSubtotal--inDrawer': inDrawer })}>\n <div className=\"CartSubtotal-flex\">\n <span className=\"CartSubtotal-subtotal\">Subtotal</span>\n <span className=\"CartSubtotal-price\">\n {subtotalPrice && currencyCode\n ? currencyFormatter.format(Number(subtotalPrice))\n : subtotalPrice}\n </span>\n </div>\n <p className=\"CartSubtotal-disclaimer\">\n Shipping, taxes, and discounts calculated at checkout.\n </p>\n </div>\n )\n}\n\nexport default CartSubtotal\n", | |
| "style": ".CartSubtotal {\n margin: 20px 0;\n}\n\n.CartSubtotal-flex {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n font-size: 1.0625em;\n}\n\n.CartSubtotal--inDrawer .CartSubtotal-flex {\n margin-bottom: 10px;\n font-size: 1em;\n}\n\n.CartSubtotal-subtotal {\n flex: 2;\n font-family: 'Gotham-Bold';\n text-align: center;\n}\n\n.CartSubtotal--inDrawer .CartSubtotal-subtotal {\n text-align: left;\n}\n\n.CartSubtotal-price {\n flex: 1;\n font-family: 'Gotham-Bold';\n}\n\n.CartSubtotal--inDrawer .CartSubtotal-price {\n text-align: right;\n font-family: unset;\n}\n\n.CartSubtotal-disclaimer {\n font-size: 0.9em;\n}\n\n.CartSubtotal--inDrawer .CartSubtotal-disclaimer {\n font-size: 0.75em;\n opacity: 0.8;\n}\n\n\n@media (max-width: 767px) {\n .CartSubtotal-flex {\n font-size: 0.875em;\n }\n\n .CartSubtotal-subtotal {\n flex: 1;\n }\n\n .CartSubtotal--inDrawer .CartSubtotal-subtotal,\n .CartSubtotal--inDrawer .CartSubtotal-price {\n font-size: 0.8125em;\n }\n\n .CartSubtotal--inDrawer .CartSubtotal-disclaimer {\n font-size: 0.625em;\n opacity: 0.8;\n }\n}\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleSection", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport Link from 'Components/BuiltIn/Link'\nimport PageWidth from 'Components/PageWidth'\nimport BlogArticle from 'Components/BlogArticle'\n\nimport './styles.css'\n\nconst BlogArticleSection = ({ category, href, blogs, viewAll }) => {\n return (\n <div className={cx('BlogArticleSection', { 'BlogArticleSection--viewAll': viewAll })}>\n <PageWidth>\n <h1\n className={cx('BlogArticleSection-title', {\n 'BlogArticleSection-title--noPadding': !viewAll,\n })}\n >\n {category}\n <Link to={href} className=\"BlogArticleSection-category-link\">\n View All\n </Link>\n </h1>\n <ul className=\"BlogArticleSection-list\">\n {blogs.slice(0, viewAll ? 6 : 3).map((blog, index) => (\n <BlogArticle\n key={blog.id}\n {...blog}\n minimized={!viewAll}\n viewAll={viewAll && index === 5}\n />\n ))}\n </ul>\n </PageWidth>\n </div>\n )\n}\n\nexport default BlogArticleSection\n", | |
| "style": ".BlogArticleSection {\n padding-bottom: 60px;\n background-color: #f3f3f3;\n}\n\n.BlogArticleSection--viewAll {\n padding-top: 60px;\n}\n\n.BlogArticleSection-title {\n margin-bottom: 20px;\n font-family: Gotham-Bold, sans-serif;\n font-size: 1.75em;\n}\n\n.BlogArticleSection-category-link {\n margin-left: 15px;\n border-bottom: 1px solid;\n font-family: \"Gotham-Book\";\n font-size: 14px;\n color: #000000cf;\n text-decoration: none;\n}\n\n.BlogArticleSection-list {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n row-gap: 20px;\n column-gap: 30px;\n}\n\n@media (max-width: 767px) {\n .BlogArticleSection-list {\n grid-template-columns: repeat(1, 1fr);\n row-gap: 0;\n }\n\n .BlogArticleSection-title--noPadding {\n margin-bottom: 0;\n }\n\n .BlogArticleSection--viewAll .BlogArticleSection-list {\n grid-template-columns: repeat(1, 1fr);\n row-gap: 20px;\n column-gap: 22px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "GeneralSnippet", | |
| "code": "import React from 'react'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst GeneralSnippet = ({ type, title, text, ctaHref, ctaText, separator = false }) => {\n switch (type) {\n case 'SimpleBlock':\n return (\n <PageWidth className=\"GeneralSnippet-SimpleBlock\">\n <h3 className=\"GeneralSnippet-SimpleBlock-title\">{title}</h3>\n <p className=\"GeneralSnippet-SimpleBlock-text\">\n {text && text.split('\\n').map((i, key) => <span key={key}>{i}</span>)}\n </p>\n {ctaHref && ctaText && (\n <Button to={ctaHref} className=\"GeneralSnippet-SimpleBlock-button\">\n {ctaText}\n </Button>\n )}\n {separator && <hr className=\"GeneralSnippet-SimpleBlock-separator\" />}\n </PageWidth>\n )\n\n default:\n return null\n }\n}\n\nexport default GeneralSnippet\n", | |
| "style": ".GeneralSnippet-SimpleBlock {\n margin-bottom: 80px;\n margin-top: 80px;\n}\n\n.GeneralSnippet-SimpleBlock-title {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 18px;\n line-height: 28px;\n margin-bottom: 18px;\n}\n\n.GeneralSnippet-SimpleBlock-text span {\n display: inline-block;\n}\n\n.GeneralSnippet-SimpleBlock-text span:not(:first-child) {\n margin-top: 10px;\n}\n\n\n.GeneralSnippet-SimpleBlock-button {\n background-color: #000;\n color: #FFF;\n margin-top: 50px;\n}\n\n.GeneralSnippet-SimpleBlock-separator {\n border: 0;\n border-top: 1px solid #DEDEDE;\n margin: 80px 0;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleQuote", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst BlogArticleQuote = ({ quote, author }) => (\n <div className=\"BlogArticleQuote-wrapper\">\n <div className=\"BlogArticleQuote-hr\">\n <hr />\n </div>\n <blockquote className=\"BlogArticleQuote\">\n <p className=\"BlogArticleQuote-text\">{quote}</p>\n <footer className=\"BlogArticleQuote-author\">- {author}</footer>\n </blockquote>\n <div className=\"BlogArticleQuote-hr\">\n <hr />\n </div>\n </div>\n)\n\nexport default BlogArticleQuote\n", | |
| "style": ".BlogArticleQuote-wrapper {\n max-width: 1220px;\n text-align: center;\n margin: auto;\n padding: 8px 0 40px;\n}\n\n.BlogArticleQuote {\n padding: 0 0 30px;\n}\n\n.BlogArticleQuote::before {\n content: \" \";\n display: table;\n}\n\n.BlogArticleQuote-text {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 22px;\n margin-bottom: 10px;\n padding: 35px 40px 0;\n}\n\n.BlogArticleQuote-text::before {\n content: '\\201C';\n}\n\n.BlogArticleQuote-text::after {\n content: '\\201D';\n}\n\n.BlogArticleQuote-hr {\n padding: 0;\n color: #dedede;\n height: 1px;\n display: inline-block;\n width: 100%;\n}\n\n.BlogArticleQuote-hr hr {\n border: 0;\n width: 720px;\n max-width: 100%;\n border-top: 1px solid #ddd;\n}\n\n@media (max-width: 767px) {\n .BlogArticleQuote-wrapper {\n padding: 0 20px;\n }\n\n .BlogArticleQuote-text {\n font-size: 24px;\n line-height: 1.3;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "AppearAnimation", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst AppearAnimation = ({ children, as = 'div', delayInMs = 0, ...restProps }) => {\n const Component = as\n\n const [appearAnimationClassName, setAppearAnimationClassName] = React.useState('')\n React.useEffect(() => {\n setTimeout(() => {\n setAppearAnimationClassName('AppearAnimation-container--enter')\n }, delayInMs)\n }, [setAppearAnimationClassName])\n\n return (\n <Component className={`AppearAnimation-container ${appearAnimationClassName}`} {...restProps}>\n {children}\n </Component>\n )\n}\n\nexport default AppearAnimation\n", | |
| "style": ".AppearAnimation-container {\n opacity: 0;\n transform: translateY(50px);\n}\n\n.AppearAnimation-container--enter {\n opacity: 1;\n transform: translateY(0px);\n transition: transform 0.3s cubic-bezier(0.165, 0.84, 0.44, 1) 0.18s,\n opacity 0.3s cubic-bezier(0.165, 0.84, 0.44, 1) 0.18s;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "StarRating", | |
| "code": "import React from 'react'\nimport './styles.css'\n\nconst StarRating = ({ rate }) => {\n const width = `${(rate * 100) / 5}%`\n return (\n <div className=\"StarRating\">\n <div className=\"StarRating-active\" style={{ width }} />\n </div>\n )\n}\n\nexport default StarRating\n", | |
| "style": ".StarRating {\n position: relative;\n width: 75px;\n height: 15px;\n overflow: hidden;\n}\n\n.StarRating-active {\n position: absolute;\n height: 100%;\n background-image: url('data:image/svg+xml;charset=UTF-8, %3Csvg%20width%3D%2280%22%20height%3D%2214%22%20viewBox%3D%220%200%2080%2014%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cg%20fill%3D%22%23FFB829%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M71.996%2011.368l-3.94%202.42c-.474.292-.756.096-.628-.443l1.074-4.53-3.507-3.022c-.422-.363-.324-.693.24-.74l4.602-.37%201.778-4.3c.21-.51.55-.512.762%200l1.78%204.3%204.602.37c.552.046.666.37.237.74l-3.507%203.02%201.075%204.532c.127.536-.147.74-.628.444l-3.94-2.422zM55.996%2011.368l-3.94%202.42c-.474.292-.756.096-.628-.443l1.074-4.53-3.507-3.022c-.422-.363-.324-.693.24-.74l4.602-.37%201.778-4.3c.21-.51.55-.512.762%200l1.78%204.3%204.602.37c.552.046.666.37.237.74l-3.507%203.02%201.075%204.532c.127.536-.147.74-.628.444l-3.94-2.422zM40.123%2011.368l-3.94%202.42c-.475.292-.756.096-.63-.443l1.076-4.53-3.508-3.022c-.422-.363-.324-.693.24-.74l4.602-.37%201.778-4.3c.21-.51.55-.512.762%200l1.778%204.3%204.603.37c.554.046.667.37.24.74l-3.508%203.02%201.075%204.532c.127.536-.147.74-.628.444l-3.94-2.422zM24.076%2011.368l-3.94%202.42c-.475.292-.757.096-.63-.443l1.076-4.53-3.507-3.022c-.422-.363-.324-.693.238-.74l4.603-.37%201.78-4.3c.21-.51.55-.512.76%200l1.78%204.3%204.602.37c.554.046.667.37.24.74l-3.508%203.02%201.074%204.532c.127.536-.146.74-.628.444l-3.94-2.422zM8.123%2011.368l-3.94%202.42c-.475.292-.756.096-.63-.443l1.076-4.53L1.12%205.792c-.422-.363-.324-.693.24-.74l4.602-.37%201.778-4.3c.21-.51.55-.512.762%200l1.778%204.3%204.603.37c.554.046.667.37.24.74l-3.508%203.02%201.075%204.532c.127.536-.147.74-.628.444l-3.94-2.422z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E');\n background-size: 75px 15px;\n filter: brightness(0);\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SearchPage", | |
| "code": "import React from 'react'\nimport useWindowSize from 'react-use/lib/useWindowSize'\nimport SearchInput from 'Components/SearchInput'\nimport SubCollectionProductList from 'Components/SubCollectionProductList'\nimport SearchBlogPostList from 'Components/SearchBlogPostList'\n\nimport './styles.css'\n\nconst Mock_Product_Result = {\n title: 'Products',\n products: [\n {\n id: 1,\n image:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018539_A_2e81099b-a9a3-403a-9178-3be4c895080a_540x.jpg?v=1578963577',\n ageImage:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018539_B_96261028-e4b3-4946-adc7-5c389861ba73_540x.jpg?v=1580193331',\n price: '$34.95',\n subtitle: 'AirPods Pro',\n title: 'Rugged Case',\n },\n {\n id: 2,\n image:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018546_A_540x.jpg?v=1578962949',\n ageImage:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018546_B_540x.jpg?v=1580193314',\n price: '$34.95',\n subtitle: 'AirPods Pro',\n title: 'Rugged Case',\n },\n {\n id: 3,\n image:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018560_A_540x.jpg?v=1584478797',\n ageImage:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018560_J_540x.jpg?v=1584478797',\n price: '$34.95',\n subtitle: 'AirPods Pro',\n title: 'Active Rugged Case',\n },\n {\n id: 4,\n image:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018553_A_540x.jpg?v=1584478544',\n ageImage:\n 'https://cdn.shopify.com/s/files/1/0384/6721/products/856500018553_J_540x.jpg?v=1584478544',\n price: '$34.95',\n subtitle: 'AirPods Pro',\n title: 'Active Rugged Case',\n },\n ],\n separator: false,\n}\nconst Mock_Blog_Post_Result = {\n title: 'Blog posts',\n blogs: [\n {\n id: 1,\n image:\n 'https://cdn.shopify.com/s/files/1/0384/6721/articles/unnamed_5911256e-1419-48e4-8ee1-c4bdb9a5e5af_540x.jpg?v=1568305661',\n description: 'iPhone 11 | Our Favorite New Features test',\n },\n {\n id: 2,\n image:\n 'https://cdn.shopify.com/s/files/1/0384/6721/articles/unnamed_bcbd8579-df2f-436f-be8c-73a6ef4ec803_540x.jpg?v=1568148639',\n description: 'Our Five Favorite Accessories for the iPhone 11 test',\n },\n ],\n}\n\nconst SearchPage = () => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n\n return (\n <>\n {!isMobile && <SearchInput />}\n <SubCollectionProductList {...Mock_Product_Result} withPagination />\n <SearchBlogPostList {...Mock_Blog_Post_Result} />\n </>\n )\n}\n\nexport default SearchPage\n", | |
| "style": "", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SocialLinks", | |
| "code": "import React, { useEffect } from 'react'\nimport Icons from 'Components/Icons'\n\nimport './styles.css'\n\nconst SocialLinks = ({ white = false }) => {\n useEffect(() => {\n const animatedElements = document.querySelectorAll('.SocialLinks-item.appear-animation')\n animatedElements.forEach((item, index) => {\n const delay = index == 0 ? 0.12 : 0.12 + index * 0.06\n item.style.transitionDelay = `${delay}s`\n item.classList.add('animate')\n })\n }, [])\n return (\n <ul>\n <li className=\"SocialLinks-item appear-animation\">\n <a\n href=\"https://www.instagram.com/nomad/\"\n title=\"Nomad on Instagram\"\n className=\"SocialLinks-link\"\n >\n <Icons name=\"Instagram\" white={white} className=\"SocialLinks-icon\" />\n </a>\n </li>\n <li className=\"SocialLinks-item appear-animation\">\n <a\n href=\"https://www.facebook.com/nomadgoods\"\n title=\"Nomad on Facebook\"\n className=\"SocialLinks-link\"\n >\n <Icons name=\"Facebook\" white={white} className=\"SocialLinks-icon\" />\n </a>\n </li>\n <li className=\"SocialLinks-item appear-animation\">\n <a\n href=\"https://twitter.com/nomadgoods\"\n title=\"Nomad on Twitter\"\n className=\"SocialLinks-link\"\n >\n <Icons name=\"Twitter\" white={white} className=\"SocialLinks-icon\" />\n </a>\n </li>\n </ul>\n )\n}\n\nexport default SocialLinks\n", | |
| "style": ".SocialLinks-item {\n display: inline-block;\n margin: 0 23px 0 0;\n}\n\n.SocialLinks-link {\n color: inherit;\n}\n\n.SocialLinks-icon {\n height: 22px;\n width: 22px;\n display: block;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SellingLocations", | |
| "code": "import React from 'react'\nimport useWindowSize from 'react-use/lib/useWindowSize'\nimport PageWidth from 'Components/PageWidth'\nimport Tabs from 'Components/Tabs'\nimport Accordions from 'Components/Accordions'\nimport RichText from 'Components/RichText'\n\nimport './styles.css'\n\nconst content = innerHtmls => {\n return (\n <div className=\"SellingLocations-content\">\n {innerHtmls.map((html, index) => (\n <RichText key={index} source={html} />\n ))}\n </div>\n )\n}\n\nconst SellingLocations = ({ items, footerHtml }) => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n\n const contents = items.map(({ title, innerHtmls }) => ({\n title,\n content: content(innerHtmls),\n }))\n\n return (\n <PageWidth className=\"SellingLocations\">\n {isMobile ? <Accordions items={contents} /> : <Tabs items={contents} />}\n <div className=\"SellingLocations-footer\">\n <RichText source={footerHtml} />\n </div>\n </PageWidth>\n )\n}\n\nexport default SellingLocations\n", | |
| "style": ".SellingLocations {\n margin-top: 40px;\n margin-bottom: 40px;\n min-height: 400px;\n}\n\n.SellingLocations-content {\n margin: 0 20px;\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n row-gap: 20px;\n column-gap: 30px;\n}\n\n.SellingLocations-footer {\n margin: 80px 0 60px;\n min-height: 50px;\n max-width: 600px;\n}\n\n@media (max-width: 767px) {\n .SellingLocations-content {\n grid-template-columns: repeat(1, 1fr);\n row-gap: 0;\n margin: 0;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ExtenalLink", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\n\nimport './styles.css'\n\nconst ExtenalLink = ({ url, title, animation }) => {\n return (\n <a\n href={url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={cx('external-link', { 'link-animation': animation })}\n >\n {title}\n </a>\n )\n}\n\nexport default ExtenalLink\n", | |
| "style": ".external-link {\n text-decoration: none;\n border-bottom: 2px solid rgba(0, 0, 0, 0.1);\n position: relative;\n color: #000;\n -webkit-font-smoothing: antialiased;\n -webkit-text-size-adjust: 100%;\n text-rendering: optimizeSpeed;\n cursor: pointer;\n}\n\n.external-link::after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 0%;\n border-bottom: 2px solid #000;\n transition: width 0.5s ease;\n}\n\n.link-animation:hover::after {\n width: 100%;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductFeaturedInfo", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst ProductFeaturedInfo = ({ text, image, textColor = '#ffffff' }) => (\n <div className=\"ProductFeaturedInfo\" style={{ backgroundImage: `url('${image}')` }}>\n <PageWidth className=\"ProductFeaturedInfo-content\" style={{ color: textColor }}>\n <p className=\"ProductFeaturedInfo-text\">{text}</p>\n </PageWidth>\n </div>\n)\n\nexport default ProductFeaturedInfo\n", | |
| "style": ".ProductFeaturedInfo {\n position: relative;\n height: 615px;\n background-repeat: no-repeat;\n background-size: cover;\n background-position: center center;\n}\n\n.ProductFeaturedInfo-content {\n display: flex;\n align-items: center;\n}\n\n.ProductFeaturedInfo-text {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 27px;\n line-height: 1.6;\n}\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "WholesaleList", | |
| "code": "import React from 'react'\nimport { ResponsiveImage } from 'frontend-ui'\nimport PageWidth from 'Components/PageWidth'\nimport ExtenalLink from 'Components/ExtenalLink'\n\nimport './styles.css'\n\nconst WholesaleList = ({ items = {} }) => {\n return (\n <PageWidth className=\"wholesale-container\">\n {items.map((item, index) => (\n <div className=\"wholesale-item\" key={index}>\n <div className=\"wholesale-image\">\n <ResponsiveImage src={item.imgUrl} />\n </div>\n <div className=\"wholesale-text\">\n <ExtenalLink url={item.link} title={item.title} animation={true} />\n </div>\n </div>\n ))}\n </PageWidth>\n )\n}\n\nexport default WholesaleList\n", | |
| "style": ".wholesale-assets {\n margin-top: 0;\n}\n\n.wholesale-item {\n padding: 30px 20px 30px 20px;\n width: 16.666%;\n display: inline-block;\n}\n\n.wholesale-image {\n filter: grayscale(100%) brightness(70%) contrast(500%);\n max-height: 150px;\n display: flex;\n align-items: center;\n height: 100px;\n}\n\n.wholesale-image img {\n padding: 0px 20px;\n max-width: 100%;\n max-height: -webkit-fill-available;\n}\n\n.wholesale-text {\n padding: 15px 0px 0px 0px;\n text-align: center;\n}\n\n@media (max-width: 1270px) {\n}\n\n@media (max-width: 991px) {\n .wholesale-item {\n width: 33.333%;\n }\n\n .wholesale-image img {\n padding: 0px 80px;\n }\n}\n@media (max-width: 790px) {\n .wholesale-image img {\n padding: 0px 20px;\n }\n}\n\n@media (max-width: 495px) {\n .wholesale-item {\n width: 50%;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Tabs", | |
| "code": "import React, { useState } from 'react'\nimport cx from 'classnames'\n\nimport './styles.css'\n\nconst Tabs = ({ items }) => {\n const [activeTab, setActiveTab] = useState(items[0])\n const { reverseContent, content } = activeTab\n return (\n <div className=\"Tabs\">\n <ul className=\"Tabs-header\">\n {items.map((tab, index) => (\n <li\n key={index}\n className={cx('Tabs-header-item', { 'Tabs-header-item--active': activeTab === tab })}\n onClick={() => setActiveTab(tab)}\n >\n {tab.title}\n </li>\n ))}\n </ul>\n <div className={cx('Tabs-body', { 'Tabs-body--reverse': reverseContent })}>{content}</div>\n </div>\n )\n}\n\nexport default Tabs\n", | |
| "style": ".Tabs {\n margin-top: 40px;\n margin-bottom: 40px;\n min-height: 400px;\n}\n\n.Tabs-header {\n display: flex;\n border-bottom: 1px solid #dedede;\n}\n\n.Tabs-header-item {\n position: relative;\n padding: 10px 0 20px;\n margin-right: 34px;\n font-family: 'Gotham-Bold';\n line-height: 1.42857143;\n cursor: pointer;\n}\n.Tabs-header-item--active:before {\n position: absolute;\n content: '';\n bottom: 0;\n left: 0;\n right: 0;\n height: 3px;\n background-color: #000;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n\n.Tabs-body {\n padding: 20px 0px 0px 3px;\n}\n.Tabs-body--reverse {\n display: flex;\n flex-direction: column-reverse;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "SearchInput", | |
| "code": "import React, { useState } from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport Icons from 'Components/Icons'\nimport Button from 'Components/Button'\n\nimport './styles.css'\n\nconst SearchInput = ({ isOpen, inDrawer }) => {\n let [searchValue, setSearchValue] = useState('')\n const updateSearchValue = e => {\n setSearchValue(e.target.value)\n }\n\n return (\n <PageWidth>\n <form\n action=\"/search\"\n method=\"get\"\n className={cx('SearchInput-form', { 'SearchInput-form--inDrawer': inDrawer })}\n role=\"search\"\n >\n <input\n type=\"search\"\n name=\"q\"\n value={searchValue}\n ref={input => input && isOpen && input.focus()}\n onChange={updateSearchValue}\n placeholder=\"Search our store\"\n aria-label=\"Search our store\"\n />\n <Button as=\"button\" type=\"submit\" className={cx({ 'Btn--black': !inDrawer })}>\n <Icons name=\"Search\" black={inDrawer} large={inDrawer} />\n </Button>\n </form>\n </PageWidth>\n )\n}\n\nexport default SearchInput\n", | |
| "style": ".SearchInput-form {\n display: flex;\n align-items: center;\n max-width: 300px;\n height: 45px;\n margin-top: 40px;\n}\n\n.SearchInput-form--inDrawer {\n flex-grow: 1;\n flex-direction: row-reverse;\n max-width: unset;\n height: 100%;\n margin-top: 0;\n}\n\n.SearchInput-form input {\n width: 100%;\n height: 100%;\n padding: 8px 10px;\n font-size: 16px;\n line-height: 1.5;\n border: 1px solid #dedede;\n outline: none;\n}\n\n.SearchInput-form--inDrawer input {\n font-size: 1.5em;\n border: none;\n outline: none;\n}\n\ninput[type=search]::-ms-reveal,\ninput[type=search]::-ms-clear {\n display: none;\n width: 0;\n height: 0;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-results-button,\ninput[type=\"search\"]::-webkit-search-results-decoration {\n display: none;\n}\n\n.SearchInput-form button {\n height: 100%;\n}\n\n.SearchInput-form button svg {\n display: inline-block;\n}\n\n.SearchInput-form--inDrawer .SearchInput button {\n padding: 0 20px;\n}\n\n@media (max-width: 767px) {\n .SearchInput-form--inDrawer input {\n font-size: 16px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductTitleHero", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst ProductTitleHero = ({ title, image, titleColor = '#ffffff' }) => (\n <div className={'ProductTitleHero'}>\n <div className=\"ProductTitleHero-image\" style={{ backgroundImage: `url('${image}')` }}>\n <PageWidth className=\"ProductTitleHero-content\" style={{ color: titleColor }}>\n {title && <h1 className=\"ProductTitleHero-title\">{title}</h1>}\n </PageWidth>\n </div>\n </div>\n)\n\nexport default ProductTitleHero\n", | |
| "style": ".ProductTitleHero {\n position: relative;\n}\n\n.ProductTitleHero--margin-top {\n margin-top: 40px;\n}\n\n.ProductTitleHero-image {\n height: 100px;\n background-repeat: no-repeat;\n background-position: 50% 50%;\n background-size: cover;\n position: relative;\n top: 0;\n bottom: 0;\n left: 0;\n right: 0;\n opacity: 1;\n}\n\n.ProductTitleHero-content {\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n align-items: flex-start;\n}\n\n.ProductTitleHero-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 1.4375em;\n margin-bottom: 10px;\n}\n\n@media (min-width: 767px) {\n .ProductTitleHero--margin-top {\n margin-top: 60px;\n }\n\n .ProductTitleHero-image {\n height: 215px;\n }\n\n .ProductTitleHero-title {\n font-size: 1.6875em;\n margin-bottom: 20px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "PageWidth", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport './styles.css'\n\nconst PageWidth = ({\n children,\n className = '',\n fullWidth = false,\n large = false,\n ...restProps\n}) => {\n return (\n <div\n className={cx('PageWidth', className, {\n 'PageWidth--fullWidth': fullWidth,\n 'PageWidth--large': large,\n })}\n {...restProps}\n >\n {children}\n </div>\n )\n}\n\nexport default PageWidth\n", | |
| "style": ".PageWidth {\n position: relative;\n max-width: 1300px;\n margin: 0 auto;\n padding: 0 20px;\n width: 100%;\n}\n\n.PageWidth--large {\n max-width: 2560px;\n padding: 0 10px;\n margin: 10px auto;\n}\n\n.PageWidth--fullWidth {\n max-width: none;\n margin: auto;\n padding: unset;\n}\n\n@media (min-width: 590px) {\n .PageWidth {\n padding: 0 40px;\n }\n\n .PageWidth--fullWidth {\n padding: unset;\n }\n\n .PageWidth--large {\n padding: 0 10px;\n margin: 20px auto;\n }\n}\n\n@media (min-width: 768px) {\n .PageWidth--large {\n padding: 0 20px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleRichText", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst BlogArticleRichText = ({ source }) => (\n <div className=\"BlogArticleRichText\" dangerouslySetInnerHTML={{ __html: source }} />\n)\n\nexport default BlogArticleRichText\n", | |
| "style": ".BlogArticleRichText {\n max-width: 720px;\n margin-left: auto;\n margin-right: auto;\n}\n\n.BlogArticleRichText p {\n font-size: 18px;\n line-height: 1.7;\n margin-bottom: 30px;\n}\n\n.BlogArticleRichText a {\n position: relative;\n color: #000;\n text-decoration: none;\n border-bottom: 2px solid rgba(0, 0, 0, 0.1);\n}\n\n.BlogArticleRichText a::after {\n content: '';\n position: absolute;\n bottom: -2px;\n left: 0;\n width: 0;\n border-bottom: 2px solid #000;\n transition: width 0.5s ease;\n}\n\n.BlogArticleRichText a:hover::after {\n width: 100%;\n}\n\n.BlogArticleRichText h1:first-child,\n.BlogArticleRichText .h1:first-child,\n.BlogArticleRichText h2:first-child,\n.BlogArticleRichText .h2:first-child,\n.BlogArticleRichText h3:first-child,\n.BlogArticleRichText .h3:first-child,\n.BlogArticleRichText h4:first-child,\n.BlogArticleRichText .h4:first-child,\n.BlogArticleRichText h5:first-child,\n.BlogArticleRichText .h5:first-child,\n.BlogArticleRichText h6:first-child,\n.BlogArticleRichText .h6:first-child {\n margin-top: 0;\n}\n\n.BlogArticleRichText h2 {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 27px;\n padding: 20px 0 30px;\n}\n\n.BlogArticleRichText ul {\n margin: 0 0 20px 10px;\n padding-inline-start: 35px;\n list-style-type: square;\n}\n\n@media (max-width: 767px) {\n .BlogArticleRichText {\n padding: 0 20px;\n }\n\n .BlogArticleRichText h2 {\n font-size: 26px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogPostItem", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst BlogPostItem = ({ image, title, date, description, ctaText, ctaHref = '#', reverse }) => {\n const imageContent = (\n <div className=\"BlogPostItem-image\">\n <ResponsiveImage src={image} alt=\"\" />\n </div>\n )\n\n const textContent = (\n <div className=\"BlogPostItem-text\">\n {date && <p className=\"BlogPostItem-date\">{date}</p>}\n <h2 className=\"BlogPostItem-title\">{title}</h2>\n <p className=\"BlogPostItem-description\">{description}</p>\n {ctaText && (\n <Button href={ctaHref} className=\"BlogPostItem-cta Btn--black\">\n {ctaText}\n </Button>\n )}\n </div>\n )\n\n return (\n <div className=\"BlogPostItem\">\n <PageWidth\n className={cx('BlogPostItem-wrapper', { 'BlogPostItem-wrapper--reverse': reverse })}\n >\n <div className=\"BlogPostItem-column\">{imageContent}</div>\n <div className=\"BlogPostItem-column\">{textContent}</div>\n </PageWidth>\n </div>\n )\n}\n\nexport default BlogPostItem\n", | |
| "style": ".BlogPostItem {\n background-color: #fff;\n}\n\n.BlogPostItem-wrapper {\n display: flex;\n padding: 0 0 120px 0;\n width: 100%;\n max-width: 1220px;\n}\n\n.BlogPostItem-column {\n width: 50%;\n margin: auto 0;\n}\n\n.BlogPostItem-image {\n height: 450px;\n padding: 0 40px 0 0;\n}\n\n.BlogPostItem-image img {\n height: 100%;\n object-fit: cover;\n}\n\n.BlogPostItem-text {\n min-height: 450px;\n width: 95%;\n padding: 70px 0 0 20%;\n}\n\n.BlogPostItem-date {\n margin-bottom: 10px;\n font-size: 0.8125em;\n}\n\n.BlogPostItem-title {\n margin-bottom: 10px;\n font-size: 1.6875em;\n}\n\n.BlogPostItem-description {\n margin-bottom: 30px;\n}\n\n.BlogPostItem-wrapper--reverse {\n flex-direction: row-reverse;\n}\n\n.BlogPostItem-wrapper--reverse .BlogPostItem-image {\n padding: 0 0 0 40px;\n}\n\n.BlogPostItem-wrapper--reverse .BlogPostItem-text {\n width: 75%;\n padding: 70px 0 0 0;\n}\n\n@media (max-width: 767px) { \n .BlogPostItem-wrapper {\n flex-direction: column;\n padding: 0 0 60px 0;\n }\n\n .BlogPostItem-column .BlogPostItem-image,\n .BlogPostItem-column .BlogPostItem-text {\n padding: 0;\n }\n\n .BlogPostItem-wrapper .BlogPostItem-image {\n height: 200px;\n }\n\n .BlogPostItem-wrapper .BlogPostItem-text,\n .BlogPostItem-wrapper--reverse .BlogPostItem-text {\n min-height: auto;\n width: 100%;\n }\n\n .BlogPostItem-title {\n margin: 0 0 5px;\n font-size: 1.4375em;\n }\n \n .BlogPostItem-date {\n margin-top: 20px;\n margin-bottom: 10px;\n font-size: 0.6875em;\n }\n \n .BlogPostItem-cta {\n font-size: 0.875em;\n padding: 8px 18px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "WholesalePageLinks", | |
| "code": "import React from 'react'\nimport PageWidth from 'Components/PageWidth'\nimport cx from 'classnames'\n\nimport './styles.css'\n\nconst WholesalePageLinks = ({ links = [], separator = false, compact = false }) => {\n return (\n <PageWidth className={cx('WholesalePage-Links', { 'WholesalePage-Links-compact': compact })}>\n {links.map((link, index) => (\n <div key={index} className=\"WholesalePage-Links-block\">\n <h3 className=\"WholesalePage-Links-title\">{link.title}</h3>\n <p className=\"WholesalePage-Links-content\">{link.content}</p>\n <a\n href={link.href}\n className={cx('WholesalePage-Links-button')}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {link.text}\n </a>\n </div>\n ))}\n {separator && <hr className=\"WholesalePage-Links-separator\" />}\n </PageWidth>\n )\n}\n\nexport default WholesalePageLinks\n", | |
| "style": ".WholesalePage-Links {\n margin: 80px 0px 200px 0;\n max-width: 600px;\n}\n\n.WholesalePage-Links-title {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 18px;\n line-height: 28px;\n margin-bottom: 18px;\n}\n\n.WholesalePage-Links-block:not(:first-child) {\n margin-top: 43px;\n}\n\n.WholesalePage-Links-button {\n background-color: #000;\n color: #fff;\n margin-top: 50px;\n font-family: 'Gotham-Bold', sans-serif;\n font-weight: 400;\n line-height: 1.6;\n display: inline-block;\n padding: 10px 20px;\n min-width: 90px;\n line-height: 1.42;\n font-size: 1em;\n background-size: 29px;\n text-decoration: none;\n}\n\n.WholesalePage-Links-separator {\n border: 0;\n border-top: 1px solid #dedede;\n margin: 80px 0;\n}\n\n.WholesalePage-Links-compact {\n margin-top: 0px;\n margin-bottom: 80px;\n}\n\n@media (max-width: 589px) {\n .WholesalePage-Links-button {\n font-size: 0.875em;\n padding: 9px 20px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Shipping", | |
| "code": "import React from 'react'\nimport useWindowSize from 'react-use/lib/useWindowSize'\nimport PageWidth from 'Components/PageWidth'\nimport Tabs from 'Components/Tabs'\nimport Accordions from 'Components/Accordions'\nimport RichText from 'Components/RichText'\n\nimport './styles.css'\n\nconst Shipping = ({ items, mobileItems }) => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n\n const contents = (isMobile ? mobileItems : items).map(({ title, innerHtml }) => ({\n title,\n content: <RichText source={innerHtml} />,\n }))\n\n return (\n <PageWidth className=\"Shipping\">\n {isMobile ? <Accordions items={contents} /> : <Tabs items={contents} />}\n </PageWidth>\n )\n}\n\nexport default Shipping\n", | |
| "style": ".Shipping {\n margin-top: 40px;\n margin-bottom: 40px;\n min-height: 400px;\n}\n\n.Shipping .RichText ul {\n margin: 0 0 20px 18px;\n padding-inline-start: 0;\n}\n\n.Shipping .RichText .where-we-ship h3 {\n margin: 0;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "WallpaperBox", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\nimport useWindowSize from 'react-use/lib/useWindowSize'\n\nimport PageWidth from 'Components/PageWidth'\nimport ExtenalLink from 'Components/ExtenalLink'\n\nimport './styles.css'\n\nconst WallpaperBox = ({ imgUrl, title, darkBlock, links = [] }) => {\n const { width } = useWindowSize()\n const isMobile = width < 768\n\n return (\n <div className={cx('WallpaperBox', { 'WallpaperBox-dark-block': darkBlock })}>\n <PageWidth className=\"wallpaper-card-block\">\n <ResponsiveImage\n className=\"WallpaperBox-img\"\n src={isMobile ? imgUrl.mobile : imgUrl.desktop}\n alt=\"\"\n />\n <div className=\"WallpaperBox-text-block\">\n <div className=\"WallpaperBox-title-block\">\n <h1>{title}</h1>\n </div>\n <div className=\"WallpaperBox-link-block\">\n <p>\n <strong>Download:</strong>\n {links.map(\n (link, index) =>\n !(link.title.includes('Desktop') && isMobile) && (\n <span className=\"wallpaper-link\" key={index}>\n <ExtenalLink url={link.url} title={link.title} animation={true} />\n </span>\n ),\n )}\n </p>\n </div>\n </div>\n </PageWidth>\n </div>\n )\n}\n\nexport default WallpaperBox\n", | |
| "style": ".WallpaperBox {\n background-color: #f3f3f3;\n color: black;\n font-size: 18px;\n}\n\n.WallpaperBox-img {\n width: 100%;\n}\n\n.wallpaper-card-block {\n padding: 50px 0px 0px 0px;\n}\n\n.WallpaperBox-dark-block {\n background-color: #0d0d0d;\n}\n\n.WallpaperBox-dark-block h1,\n.WallpaperBox-dark-block a,\n.WallpaperBox-dark-block p {\n color: #e8e8e8 !important;\n border-color: #d4d4d426 !important;\n}\n\n.WallpaperBox-dark-block .external-link::after {\n border-color: #e8e8e8 !important;\n}\n\n.WallpaperBox-link-block strong {\n padding-right: 150px;\n font-family: \"Gotham-Bold\",sans-serif;\n font-weight: 400;\n letter-spacing: 0em;\n}\n\n\n.WallpaperBox-title-block h1 {\n font-size: 48px !important;\n line-height: 1 !important;\n margin-bottom: 35px !important;\n font-family: 'Gotham-Bold', sans-serif;\n}\n\n\n.WallpaperBox-link-block {\n padding: 0px 30px 90px 0px !important;\n}\n\n.wallpaper-link {\n padding-right: 6rem;\n display: inline-block;\n line-height: 2;\n}\n\n@media (max-width: 1270px) {\n .WallpaperBox-title-block {\n padding: 80px 30px 40px 30px !important;\n }\n .WallpaperBox-link-block {\n padding: 50px 30px 80px 30px !important;\n }\n}\n\n@media (max-width: 768px) {\n .wallpaper-card-block {\n padding: 70px 0px 0px 0px;\n }\n\n\n .WallpaperBox-title-block {\n padding: 40px 20px 0px 20px !important;\n }\n\n .WallpaperBox-title-block h1 {\n font-size: 30px !important;\n line-height: 1 !important;\n }\n\n .WallpaperBox-link-block {\n padding: 10px 20px 60px 20px !important;\n }\n\n .WallpaperBox-link-block strong {\n font-size: 16px;\n margin-bottom: 1em;\n display: block;\n }\n\n .wallpaper-link {\n font-size: 14px;\n line-height: 1.5;\n display: block;\n border-bottom: 0;\n margin-bottom: 10px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "AnimatedPower", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\n\nimport './styles.css'\n\nconst AnimatedPower = ({ isPro, resources: [topSrc, bottomSrc] }) => {\n return (\n <div className={cx('AnimatedPower', { 'AnimatedPower--pro': isPro })}>\n <ResponsiveImage className=\"AnimatedPower-bottom\" src={bottomSrc} alt=\"\" />\n <ResponsiveImage className=\"AnimatedPower-top\" src={topSrc} alt=\"\" />\n </div>\n )\n}\n\nexport default AnimatedPower\n", | |
| "style": "@keyframes AniFadeInOut {\n 0% {\n opacity:1;\n }\n 45% {\n opacity:1;\n }\n 60% {\n opacity:0;\n }\n 100% {\n opacity:0;\n }\n}\n\n.AnimatedPower {\n position: relative;\n width: 530px;\n height: 560px;\n}\n\n.AnimatedPower-top {\n position: absolute;\n top: 0;\n left: 0;\n animation: AniFadeInOut ease-in-out infinite 2.5s alternate;\n}\n\n\n@media (max-width: 767px) {\n .AnimatedPower {\n width: 350px;\n height: 350px;\n margin: 50px 0px;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "HomeSnippet", | |
| "code": "import React from 'react'\nimport useMedia from 'react-use/lib/useMedia'\nimport { ResponsiveImage } from 'frontend-ui'\nimport Button from 'Components/Button'\nimport Link from 'frontend-link'\nimport PageWidth from 'Components/PageWidth'\n\nimport './styles.css'\n\nconst HomeSnippet = ({\n content = [],\n cta = [],\n image,\n imageMobile,\n text,\n title,\n type,\n videos = [],\n}) => {\n const productVideos = (\n <PageWidth large className=\"HomeSnippet-productVideos\">\n {videos.map(({ poster, source, title, text, url }) => (\n <Link to={url} key={title} className=\"HomeSnippet-link\">\n <video className=\"HomeSnippet-video\" poster={poster} autoPlay muted loop playsInline>\n <source src={source} />\n </video>\n <div className=\"HomeSnippet-content\">\n <h3 className=\"HomeSnippet-title\">{title}</h3>\n <p className=\"HomeSnippet-text\">{text}</p>\n </div>\n </Link>\n ))}\n </PageWidth>\n )\n\n const imgUrl = useMedia('(max-width: 590px)') ? imageMobile : image\n const highlight = (\n <PageWidth fullWidth className=\"HomeSnippet-highlight\">\n <ResponsiveImage className=\"HomeSnippet-background\" src={imgUrl} alt=\"\" />\n <PageWidth className=\"HomeSnippet-info\">\n <h3 className=\"HomeSnippet-title\">{title}</h3>\n <p className=\"HomeSnippet-text\">{text}</p>\n <div className=\"HomeSnippet-buttons\">\n {cta.map(({ id, href, text }) => (\n <Button key={id} to={href} className=\"Btn--default HomeSnippet-button\">\n {text}\n </Button>\n ))}\n </div>\n </PageWidth>\n </PageWidth>\n )\n\n const multipleRows = (\n <PageWidth fullWidth className=\"HomeSnippet-multipleRows\">\n <div className=\"HomeSnippet-image\" style={{ backgroundImage: `url(${image})` }}>\n <PageWidth fullWidth className=\"HomeSnippet-title\">\n <PageWidth>\n <h3>{title}</h3>\n </PageWidth>\n </PageWidth>\n </div>\n <PageWidth className=\"HomeSnippet-multipleRows-wrap\">\n {content.map(({ text, title }) => (\n <div className=\"HomeSnippet-row\" key={title}>\n <h4 className=\"HomeSnippet-subtitle\">{title}</h4>\n <p className=\"HomeSnippet-text\">{text}</p>\n </div>\n ))}\n </PageWidth>\n </PageWidth>\n )\n\n return (\n <>\n {type === 'product-videos' && productVideos}\n {type === 'highlight' && highlight}\n {type === 'multiple-rows' && multipleRows}\n </>\n )\n}\n\nexport default HomeSnippet\n", | |
| "style": "/** product-videos type **/\n.HomeSnippet-productVideos {\n color: #FFF;\n flex-direction: column;\n display: flex;\n}\n\n.HomeSnippet-productVideos .HomeSnippet-link {\n color: inherit;\n display: inline-block;\n height: 600px;\n position: relative;\n text-decoration: none;\n width: 100%;\n}\n\n.HomeSnippet-productVideos .HomeSnippet-link:not(:first-child) {\n margin-top: 10px;\n}\n\n.HomeSnippet-productVideos .HomeSnippet-video {\n height: 100%;\n object-fit: cover;\n position: absolute;\n width: 100%;\n}\n\n.HomeSnippet-productVideos .HomeSnippet-content {\n display: flex;\n flex-direction: column;\n height: 100%;\n justify-content: flex-end;\n padding: 25px 15px 15px;\n position: relative;\n}\n\n.HomeSnippet-productVideos .HomeSnippet-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 40px;\n line-height: 1;\n}\n\n.HomeSnippet-productVideos .HomeSnippet-text {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 20px;\n}\n\n/** highlight type **/\n.HomeSnippet-highlight {\n background: #000 center bottom no-repeat;\n background-size: cover;\n color: #FFF;\n display: flex;\n align-content: center;\n justify-content: center;\n height: 600px;\n text-align: center;\n overflow: hidden;\n}\n\n.HomeSnippet-highlight .HomeSnippet-background {\n position: absolute;\n object-fit: cover;\n object-position: 50% 50%;\n width: 100%;\n height: 100%;\n}\n\n.HomeSnippet-highlight .HomeSnippet-info {\n margin: 110px auto 50px auto;\n max-width: 590px;\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0;\n}\n\n.HomeSnippet-highlight .HomeSnippet-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 40px;\n line-height: 1.3;\n margin-bottom: 20px;\n padding: 0 10px;\n}\n\n.HomeSnippet-highlight .HomeSnippet-text {\n font-size: 16px;\n}\n\n.HomeSnippet-highlight .HomeSnippet-buttons .HomeSnippet-button {\n border-color: inherit;\n color: inherit;\n margin: 23px 10px 0;\n}\n\n/** multi-rows type **/\n.HomeSnippet-multipleRows {\n background-color: #000;\n color: #FFF;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-image {\n position: relative;\n background: transparent center center no-repeat;\n background-size: cover;\n height: 600px;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-title {\n position: absolute;\n left: 0;\n bottom: 0;\n width: 100%;\n height: 20%;\n background-image: linear-gradient( rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 90% );\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 42px;\n line-height: 1.6;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-row {\n flex: 1;\n padding-bottom: 60px;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-row + .HomeSnippet-row {\n padding-left: 0px;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-multipleRows-wrap {\n display: flex;\n flex-direction: column;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-subtitle {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 27px;\n margin-bottom: 20px;\n}\n\n.HomeSnippet-multipleRows .HomeSnippet-text {\n margin-bottom: 20px;\n}\n\n\n@media (min-width: 768px) {\n .HomeSnippet-productVideos {\n flex-direction: row;\n }\n\n .HomeSnippet-productVideos .HomeSnippet-link:not(:first-child) {\n margin-top: 0px;\n margin-left: 20px;\n }\n\n .HomeSnippet-multipleRows .HomeSnippet-multipleRows-wrap {\n flex-direction: row;\n }\n\n .HomeSnippet-multipleRows .HomeSnippet-row + .HomeSnippet-row {\n padding-left: 100px;\n }\n}\n\n@media (max-width: 590px) {\n .HomeSnippet-productVideos .HomeSnippet-link {\n height: 300px;\n }\n .HomeSnippet-highlight {\n height: 625px;\n }\n .HomeSnippet-highlight .HomeSnippet-info {\n margin-top: 50px;\n padding: 0 20px;\n }\n .HomeSnippet-highlight .HomeSnippet-background {\n object-fit: contain;\n object-position: 50% 88%;\n }\n .HomeSnippet-multipleRows .HomeSnippet-image {\n height: 230px;\n }\n .HomeSnippet-multipleRows .HomeSnippet-multipleRows-wrap {\n padding-top: 10px;\n }\n .HomeSnippet-multipleRows .HomeSnippet-title>div {\n display: flex;\n align-items: flex-end;\n }\n .HomeSnippet-multipleRows .HomeSnippet-row {\n padding-bottom: 30px;\n }\n}\n\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Accordions", | |
| "code": "import React, { useState, useRef, useEffect } from 'react'\nimport cx from 'classnames'\n\nimport './styles.css'\n\nconst Accordion = ({ active, item: { title, content, whiteBackground }, onClick }) => {\n const contentRef = useRef()\n const [height, setHeight] = useState(0)\n\n useEffect(() => {\n const height = active ? (contentRef.current || { clientHeight: 0 }).clientHeight : 0\n setHeight(height)\n })\n\n return (\n <div className={cx('Accordion', { 'Accordion--active': active })}>\n <div className=\"Accordion-heading\" onClick={onClick}>\n <h4>{title}</h4>\n </div>\n <div\n className={cx('Accordion-content', { 'Accordion-content--white': whiteBackground })}\n style={{ height }}\n >\n <div ref={contentRef} className=\"Accordion-body\">\n <div>{content}</div>\n </div>\n </div>\n </div>\n )\n}\n\nconst Accordions = ({ items }) => {\n const [activeItem, setActiveItem] = useState(null)\n return (\n <div className=\"Accordions\">\n {items.map((item, index) => (\n <Accordion\n key={index}\n active={activeItem === item}\n item={item}\n onClick={() => setActiveItem(activeItem === item ? null : item)}\n />\n ))}\n </div>\n )\n}\n\nexport default Accordions\n", | |
| "style": ".Accordions {\n margin-top: 25px;\n}\n\n.Accordion {\n overflow: hidden;\n}\n\n.Accordion-heading {\n position: relative;\n padding: 20px 0;\n border-bottom: 1px solid #dedede;\n font-family: 'Gotham-Bold';\n cursor: pointer;\n}\n\n.Accordion-heading::after {\n content: ' ';\n position: absolute;\n top: 50%;\n right: 0;\n display: block;\n background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAASCAYAAABM8m7ZAAAABmJLR0QA/wD/AP+gvaeTAAAA7ElEQVRIib3USy5DURzA4S/cxBYMVDwSsZ5qDbTXwMBqbMKQrsAyjJVURKwB5RroSW+uc6Luwy85o/P48p8clo0w1H7ruMBubPMcn5gjbxHNMEGBFxyWN3N8LDaLFvEyGtYT9sOBswpc4A39BugaLitvFnjGQfngMd4rh+YY10BjkxZ4wHbsQht4Cr1PoaFhAzzDdR30N3zUJVoHT6HTv6KhQQI/WRHt1UFXwTNcdYGGThdY+fFX3ETQR+y1gYbyCF5dM4n/uGkD3z9aDL3DVhdoaOzn5DPsdImGjiwn73zSan3cYvM/0dBGk8tfejyQAuUo6BAAAAAASUVORK5CYII=');\n background-size: 14px 9px;\n width: 14px;\n height: 9px;\n transition: 0.3s transform, 0.3s -webkit-transform\n}\n\n.Accordion--active .Accordion-heading::after {\n transform: rotate(180deg);\n}\n\n.Accordion-content {\n overflow: hidden;\n border-bottom: 1px solid #dedede;\n opacity: 0;\n transition: all 0.5s;\n}\n\n.Accordion-content--white {\n background-color: white;\n padding: 20px 40px;\n}\n\n.Accordion--active .Accordion-content {\n opacity: 1;\n}\n\n.Accordion-body {\n padding: 20px 0;\n}\n\n@media (max-width: 767px) {\n\n\n .Accordion-content--white {\n background-color: white;\n padding: 10px 20px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleProductSuggestions", | |
| "code": "import React from 'react'\nimport BlogArticleSectionHeader from 'Components/BlogArticleSectionHeader'\nimport ProductImageWithComparisonOnHover from 'Components/ProductImageWithComparisonOnHover'\n\nimport './styles.css'\n\nconst BlogArticleProductSuggestions = ({ title, products }) => (\n <section className=\"BlogArticleProductSuggestions\">\n {title && <BlogArticleSectionHeader>{title}</BlogArticleSectionHeader>}\n <div className=\"BlogArticleProductSuggestions-list\">\n {products.map(product => (\n <div key={product.id} className=\"BlogArticleProductSuggestions-item\">\n <a href={`/products/${product.slug}/`}>\n <ProductImageWithComparisonOnHover\n img={product.image}\n oldImg={product.comparisonImageSrc}\n alt={product.alt || ''}\n />\n <p className=\"BlogArticleProductSuggestions-item-title\">{product.title}</p>\n <span className=\"BlogArticleProductSuggestions-item-subtitle\">{product.subtitle}</span>\n </a>\n </div>\n ))}\n </div>\n </section>\n)\n\nexport default BlogArticleProductSuggestions\n", | |
| "style": ".BlogArticleProductSuggestions {\n max-width: 720px;\n padding-top: 60px;\n padding-bottom: 80px;\n margin: auto;\n}\n\n.BlogArticleProductSuggestions-list {\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n column-gap: 30px;\n}\n\n.BlogArticleProductSuggestions-item {\n position: relative;\n display: inline-block;\n width: 100%;\n padding-top: 100%;\n margin-bottom: 40px;\n}\n\n.BlogArticleProductSuggestions-item a {\n text-decoration: none;\n color: inherit;\n}\n\n.BlogArticleProductSuggestions-item-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 16px;\n line-height: 1.4;\n padding-top: 17px;\n}\n\n.BlogArticleProductSuggestions-item-subtitle {\n font-family: 'Gotham-Book', sans-serif;\n font-size: 14px;\n line-height: 1.5;\n}\n\n@media (max-width: 767px) {\n .BlogArticleProductSuggestions {\n padding: 20px;\n }\n\n .BlogArticleProductSuggestions-list {\n grid-template-columns: 1fr;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "BlogArticleSectionHeader", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst BlogArticleSectionHeader = ({ children }) => (\n <div className=\"BlogArticleSectionHeader\">\n <h2 className=\"BlogArticleSectionHeader-title\">{children}</h2>\n </div>\n)\n\nexport default BlogArticleSectionHeader\n", | |
| "style": ".BlogArticleSectionHeader {\n max-width: 720px;\n margin: auto;\n padding: 20px 0 30px;\n}\n\n.BlogArticleSectionHeader-title {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 27px;\n}\n\n@media (max-width: 767px) {\n .BlogArticleSectionHeader {\n padding: 20px 20px 30px;\n }\n\n .BlogArticleSectionHeader-title {\n font-size: 26px;\n }\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CorporateCustomProducts", | |
| "code": "import React from 'react'\nimport cx from 'classnames'\nimport { ResponsiveImage } from 'frontend-ui'\nimport PageWidth from 'Components/PageWidth'\nimport './styles.css'\n\nconst CorporateCustomProducts = ({ products, black }) => {\n return (\n <div className={cx('CorporateCustomProducts', { 'CorporateCustomProducts--black': black })}>\n <PageWidth className=\"CorporateCustomProducts-list\">\n {products.map(({ id, image, alt = '', title, description }) => (\n <div key={id} className=\"CorporateCustomProducts-item\">\n <div className=\"CorporateCustomProducts-item-image\">\n <ResponsiveImage src={image} alt={alt} />\n </div>\n <div className=\"CorporateCustomProducts-itemMeta\">\n <h3 className=\"CorporateCustomProducts-item-title\">{title}</h3>\n <p className=\"CorporateCustomProducts-item-subtitle\">{description}</p>\n </div>\n </div>\n ))}\n </PageWidth>\n </div>\n )\n}\n\nexport default CorporateCustomProducts\n", | |
| "style": ".CorporateCustomProducts-list {\n display: flex;\n padding-top: 80px;\n padding-bottom: 30px;\n}\n\n.CorporateCustomProducts-item {\n flex: 1;\n}\n\n.CorporateCustomProducts-item-image {\n padding: 0 20px;\n}\n\n.CorporateCustomProducts-item-image img {\n width: auto;\n max-width: 100%;\n}\n\n.CorporateCustomProducts-itemMeta {\n padding: 40px 25px 0;\n}\n\n.CorporateCustomProducts-item:first-child .CorporateCustomProducts-itemMeta {\n padding: 40px 25px 0 0;\n}\n\n.CorporateCustomProducts-item:last-child .CorporateCustomProducts-itemMeta {\n padding: 40px 0 0 25px;\n}\n\n.CorporateCustomProducts-item-title {\n font-family: 'Gotham-Bold';\n font-size: 18px;\n margin-bottom: 20px;\n}\n\n.CorporateCustomProducts-item-subtitle {\n margin-bottom: 10px;\n}\n\n\n.CorporateCustomProducts--black {\n background-color: black;\n color: white;\n}\n\n.CorporateCustomProducts--black .CorporateCustomProducts-item-image {\n padding: 0 0 40px 50px;\n}\n\n.CorporateCustomProducts--black .CorporateCustomProducts-itemMeta,\n.CorporateCustomProducts--black .CorporateCustomProducts-item:first-child .CorporateCustomProducts-itemMeta,\n.CorporateCustomProducts--black .CorporateCustomProducts-item:last-child .CorporateCustomProducts-itemMeta {\n padding: 0 50px;\n}\n\n.CorporateCustomProducts--black .CorporateCustomProducts-item-title {\n font-family: \"Gotham-Bold\";\n font-size: 17px;\n}\n\n@media (max-width: 767px) {\n .CorporateCustomProducts-list {\n flex-direction: column;\n padding-left: 0;\n padding-right: 0;\n }\n\n .CorporateCustomProducts-item-image {\n padding: 0;\n }\n \n .CorporateCustomProducts-itemMeta{\n padding: 30px 20px 40px;\n }\n .CorporateCustomProducts-item:first-child .CorporateCustomProducts-itemMeta{\n padding: 10px 20px 40px;\n }\n .CorporateCustomProducts-item:last-child .CorporateCustomProducts-itemMeta {\n padding: 15px 20px 0;\n }\n\n .CorporateCustomProducts-item-title {\n font-size: 16px;\n }\n \n .CorporateCustomProducts--black .CorporateCustomProducts-list {\n padding-top: 0;\n }\n .CorporateCustomProducts--black .CorporateCustomProducts-item-image {\n padding: 0 0 0 20px;\n }\n \n .CorporateCustomProducts--black .CorporateCustomProducts-item-image img {\n max-width: 70px;\n }\n \n .CorporateCustomProducts--black .CorporateCustomProducts-itemMeta,\n .CorporateCustomProducts--black .CorporateCustomProducts-item:first-child .CorporateCustomProducts-itemMeta,\n .CorporateCustomProducts--black .CorporateCustomProducts-item:last-child .CorporateCustomProducts-itemMeta {\n padding: 20px 40px 50px 20px;\n }\n \n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductInfo", | |
| "code": "import React, { useEffect, useState } from 'react'\nimport AddToCart from 'Components/AddToCart'\nimport Button from 'Components/Button'\nimport Link from 'frontend-link'\n\nimport './styles.css'\n\nconst ProductInfo = ({\n images = [],\n title,\n description,\n meta = [],\n offPrice,\n offPriceTag,\n price,\n typesButtons,\n variantId,\n}) => {\n const [openMetaItem, setOpenMetaItem] = useState(null)\n const firstImage = images[0] || []\n let [imageList, setImageList] = useState(firstImage)\n\n useEffect(() => {\n setImageList((imageList = imageList || images[0]))\n })\n\n const changeImages = (element, index) => {\n const optionsButtons = document.querySelectorAll('.ProductInfo-optionsButton')\n\n setImageList((imageList = images[index]))\n\n for (let i = 0; i < optionsButtons.length; ++i) {\n optionsButtons[i].classList.remove('is-selected')\n }\n\n element.target.classList.add('is-selected')\n }\n\n return (\n <div className=\"ProductInfo\">\n <div className=\"ProductInfo-imageWrapper\">\n <img src={imageList[0]} alt=\"\" />\n </div>\n <div className=\"ProductInfo-thumbsWrapper\">\n {imageList && imageList.map(src => (\n <img src={src} alt=\"\" key={src} />\n ))}\n </div>\n <h1 className=\"ProductInfo-title\">{title}</h1>\n <p className=\"ProductInfo-description\">{description}</p>\n <hr className=\"ProductInfo-separator\" />\n <span className={`ProductInfo-price ${offPrice ? 'is-strikethrough' : ''}`}>{price}</span>\n {offPrice && <span className=\"ProductInfo-price\">{offPrice}</span>}\n {offPriceTag && <p className=\"ProductInfo-offPriceLabel\">Outlet Sale: {offPriceTag}</p>}\n {typesButtons && (\n <div className=\"ProductInfo-options\">\n <p className=\"ProductInfo-optionsLabel\">Size</p>\n {typesButtons.map((label, index) => (\n <Button\n key={label}\n as=\"button\"\n className={`ProductInfo-optionsButton Btn--default ${\n index === 0 ? 'is-selected' : ''\n }`}\n onClick={element => changeImages(element, index)}\n >\n {label}\n </Button>\n ))}\n </div>\n )}\n <AddToCart variantId={variantId}>Add to Cart</AddToCart>\n <div className=\"ProductInfo-meta\">\n {meta.map(info => (\n <div\n className={`ProductInfo-metaItem ${\n openMetaItem === info.title\n ? 'ProductInfo-metaItem--is-open'\n : 'ProductInfo-metaItem--is-closed'\n }`}\n key={info.title}\n >\n <button\n type=\"button\"\n className=\"ProductInfo-metaItemButton\"\n onClick={() => {\n openMetaItem === info.title ? setOpenMetaItem(null) : setOpenMetaItem(info.title)\n }}\n >\n {info.title}\n <span className=\"ProductInfo-metaItemArrow\"></span>\n </button>\n <ul className=\"ProductInfo-metaItemList\">\n {info.type === 'description' && (\n <li className=\"ProductInfo-metaItemListItem\">\n <p>{info.content.text}</p>\n <ul>\n {info.content.list.map(value => (\n <li key={value}>{value}</li>\n ))}\n </ul>\n {info.content.availableOptions && (\n <p className=\"ProductInfo-metaItemAvailable\">{info.content.availableOptions}</p>\n )}\n </li>\n )}\n {info.type === 'info' && (\n <li className=\"ProductInfo-metaItemListItem\">\n {info.content.map((content, index) => (\n <div key={index} className=\"ProductInfo-metaItemInfo\">\n <h4 className=\"ProductInfo-metaItemHeading\">{content.heading}</h4>\n {content.text && (\n <p className=\"ProductInfo-metaItemSmallText\">{content.text}</p>\n )}\n {content.textList && (\n <ul>\n {content.textList.map((value, index) => (\n <React.Fragment key={index}>\n {Array.isArray(value) ? (\n <ul>\n {value.map(text => (\n <li key={text}>{text}</li>\n ))}\n </ul>\n ) : (\n <li>{value}</li>\n )}\n </React.Fragment>\n ))}\n </ul>\n )}\n {content.logoList &&\n content.logoList.map(logo => (\n <Link\n key={logo.url}\n to={logo.url}\n className=\"ProductInfo-metaItemLogoLink\"\n >\n <img\n className=\"ProductInfo-metaItemLogoImage\"\n src={logo.source}\n alt={logo.description}\n />\n </Link>\n ))}\n </div>\n ))}\n </li>\n )}\n {info.type === 'faq' &&\n info.content.map(value => (\n <li className=\"ProductInfo-metaItemListItem\" key={value.question}>\n <div className=\"ProductInfo-metaItemQuestion\">{value.question}</div>\n <p>{value.answer}</p>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n </div>\n )\n}\n\nexport default ProductInfo\n", | |
| "style": ".ProductInfo {\n background-color: #F3F3F3;\n border-bottom: 1px solid #DEDEDE;\n padding: 0 20px;\n}\n\n.ProductInfo-imageWrapper {\n background-color: #F3F3F3;\n}\n\n.ProductInfo-imageWrapper img {\n display: block;\n max-width: 100%;\n}\n\n.ProductInfo-thumbsWrapper {\n display: grid;\n grid-auto-flow: column;\n grid-gap: 11px;\n grid-template-columns: repeat(auto-fill, 64px);\n margin-top: 11px;\n overflow: hidden; \n}\n\n.ProductInfo-thumbsWrapper img {\n border-bottom: 4px solid #F3F3F3;\n max-width: 100%;\n padding: 0 5px 10px;\n}\n\n.ProductInfo-thumbsWrapper img:first-child {\n border-color: #000;\n}\n\n.ProductInfo-title {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 30px;\n font-weight: 400;\n line-height: 1.6;\n margin-top: 20px;\n}\n\n.ProductInfo-description {\n font-size: 14px;\n font-family: 'Gotham-Book', sans-serif;\n}\n\n.ProductInfo-separator {\n background-color: #DEDEDE;\n border: 0;\n height: 1px;\n margin: 15px 0 25px;\n}\n\n.ProductInfo-price {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 24px;\n font-weight: 700;\n margin-bottom: 20px;\n}\n\n.ProductInfo-options {\n margin-bottom: 30px;\n}\n\n.ProductInfo-optionsLabel {\n font-family: \"Gotham-Bold\",sans-serif;\n font-size: 12px;\n font-weight: 400;\n line-height: 1.6;\n margin-bottom: 5px;\n}\n\n.ProductInfo-optionsButton {\n background-color: #FFF;\n font-family: Inconsolata;\n font-size: 15px;\n font-weight: 700;\n margin: 0 8px 12px 0;\n padding: 7px 15px;\n}\n\n.ProductInfo-optionsButton:not(.is-selected) {\n border: 1px solid #DEDEDE;\n font-weight: 500;\n}\n\n.ProductInfo-meta {\n margin: 30px 0 40px;\n}\n\n.ProductInfo-metaItem:not(:first-child) {\n margin-top: 5px;\n}\n\n.ProductInfo-metaItemButton {\n border-bottom: 1px solid #DEDEDE;\n display: flex;\n font-family: \"Gotham-Bold\", sans-serif;\n font-weight: 400;\n justify-content: space-between;\n line-height: 1.6;\n padding: 20px 0;\n width: 100%;\n}\n\n.ProductInfo-metaItemArrow {\n display: inline-block;\n height: 16px;\n position: relative;\n width: 16px;\n}\n\n.ProductInfo-metaItemArrow:before,\n.ProductInfo-metaItemArrow:after {\n background-color: #000;\n content: '';\n display: inline-block;\n height: 2px;\n position: absolute;\n top: 12px;\n transition: transform .2s ease;\n width: 10px;\n}\n\n.ProductInfo-metaItemArrow:before {\n left: 0;\n transform: rotate(45deg);\n}\n\n.ProductInfo-metaItemArrow:after {\n right: 0;\n transform: rotate(-45deg);\n}\n\n.ProductInfo-metaItem.is-open .ProductInfo-metaItemArrow:before {\n transform: rotate(-45deg);\n}\n\n.ProductInfo-metaItem.is-open .ProductInfo-metaItemArrow:after {\n transform: rotate(45deg);\n}\n\n.ProductInfo-metaItemList {\n display: block;\n height: auto;\n overflow: hidden;\n\n transition: max-height .3s ease, opacity .3s ease;\n}\n\n.ProductInfo-metaItem--is-closed .ProductInfo-metaItemList {\n opacity: 0;\n max-height: 0;\n}\n\n.ProductInfo-metaItem--is-open .ProductInfo-metaItemList {\n max-height: 1500px;\n opacity: 1;\n}\n\n.ProductInfo-metaItemListItem {\n padding: 20px 0;\n}\n\n.ProductInfo-metaItemListItem ul {\n list-style-type: square;\n margin: 4px 0 0 18px;\n padding-bottom: 20px;\n}\n\n.ProductInfo-metaItemListItem:not(:last-child),\n.ProductInfo-metaItem:not(:last-child) .ProductInfo-metaItemList {\n border-bottom: 1px solid #DEDEDE;\n}\n\n.ProductInfo-metaItemQuestion {\n font-family: \"Gotham-Bold\", sans-serif;\n font-size: 14px;\n line-height: 18px;\n padding: 0 20px 10px 0;\n}\n\n.ProductInfo-metaItemAvailable {\n border-top: 1px solid #DEDEDE;\n padding-top: 20px;\n}\n\n.ProductInfo-metaItemInfo {\n border-bottom: 1px solid #DEDEDE;\n margin-bottom: 20px;\n}\n\n.ProductInfo-metaItemInfo:last-child {\n border-bottom: 0;\n margin-bottom: 0;\n}\n\n.ProductInfo-metaItemInfo:after {\n clear: both;\n content: '';\n display: block;\n}\n\n.ProductInfo-metaItemHeading {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 14px;\n font-weight: 700;\n line-height: 18px;\n margin-bottom: 10px;\n}\n\n.ProductInfo-metaItemLogoLink {\n display: block;\n float: left;\n margin: 0 0 20px 20px;\n max-height: 80px;\n max-width: 80px;\n}\n\n.ProductInfo-metaItemLogoImage {\n max-height: 100%;\n max-width: 100%;\n}\n\n.ProductInfo-metaItemSmallText {\n font-size: 12px;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "ProductPageSnippet", | |
| "code": "import React from 'react'\nimport Link from 'frontend-link'\n\nimport './styles.css'\n\nconst ProductPageSnippet = ({\n backgroundColor,\n companyLogoSource,\n companyLogoDescription,\n companyUrl,\n contentRows,\n imagesBlink,\n imagesCompare,\n mediaDescription,\n mediaPoster,\n mediaSource,\n separator,\n title,\n text,\n textColor,\n type,\n}) => {\n switch (type) {\n case 'image':\n return (\n <img\n src={mediaSource}\n alt={mediaDescription}\n style={{ backgroundColor: `${backgroundColor}` }}\n className=\"ProductPageSnippet-image ProductPageSnippet-image--fullWidth\"\n />\n )\n case 'images-blink':\n return (\n <div className=\"ProductPageSnippet-blinkImages\">\n {imagesBlink.map(image => (\n <img\n key={image.mediaSource}\n src={image.mediaSource}\n alt={image.mediaDescription}\n className=\"ProductPageSnippet-image\"\n />\n ))}\n </div>\n )\n case 'images-compare':\n return (\n <div className=\"ProductPageSnippet-compareImages\">\n {imagesCompare.map(image => (\n <div key={image.mediaSource} className=\"ProductPageSnippet-compareImagesContent\">\n <img\n src={image.mediaSource}\n alt={image.mediaDescription}\n className=\"ProductPageSnippet-image ProductPageSnippet-image--fullWidth\"\n />\n </div>\n ))}\n </div>\n )\n case 'video':\n return (\n <video className=\"ProductPageSnippet-video\" poster={mediaPoster} autoPlay muted playsInline>\n <source src={mediaSource} />\n </video>\n )\n case 'composite-content':\n return (\n <div style={{ backgroundColor: `${backgroundColor}`, color: `${textColor}` }}>\n {mediaSource && mediaDescription && (\n <img className=\"ProductPageSnippet-image\" src={mediaSource} alt={mediaDescription} />\n )}\n {mediaSource && mediaPoster && (\n <video\n className=\"ProductPageSnippet-video\"\n poster={mediaPoster}\n autoPlay\n muted\n playsInline\n >\n <source src={mediaSource} />\n </video>\n )}\n {separator && <hr className=\"ProductPageSnippet-separator\" />}\n <div className=\"ProductPageSnippet-box\">\n <h3 className=\"ProductPageSnippet-title\">{title}</h3>\n <p className=\"ProductPageSnippet-text\">{text}</p>\n {companyUrl && companyLogoSource && (\n <Link to={companyUrl} className=\"ProductPageSnippet-logoLink\">\n <img\n className=\"ProductPageSnippet-logoImage\"\n src={companyLogoSource}\n alt={companyLogoDescription}\n />\n </Link>\n )}\n </div>\n </div>\n )\n case 'multiple-rows':\n return (\n <div\n className=\"ProductPageSnippet-rowContent\"\n style={{ backgroundColor: `${backgroundColor}`, color: `${textColor}` }}\n >\n <img\n className=\"ProductPageSnippet-image ProductPageSnippet-image--fullWidth\"\n src={mediaSource}\n alt={mediaDescription}\n />\n {contentRows.map(({ mediaDescription, mediaSource, text, title }) => (\n <div className=\"ProductPageSnippet-row\" key={title}>\n <img\n className=\"ProductPageSnippet-smallImage\"\n src={mediaSource}\n alt={mediaDescription}\n />\n <h3 className=\"ProductPageSnippet-title is-small\">{title}</h3>\n <p className=\"ProductPageSnippet-text\">{text}</p>\n </div>\n ))}\n </div>\n )\n default:\n return null\n }\n}\n\nexport default ProductPageSnippet\n", | |
| "style": "@keyframes fadeInOut {\n 0%, 45% {\n opacity: 1;\n }\n\n 60%, 100% {\n opacity: 0;\n }\n}\n\n.ProductPageSnippet-image {\n display: block;\n height: auto;\n margin: 0 auto;\n max-width: 100%;\n}\n\n.ProductPageSnippet-image:not(.ProductPageSnippet-image--fullWidth) {\n padding: 0 20px;\n}\n\n.ProductPageSnippet-image--fullWidth + .ProductPageSnippet-image--fullWidth {\n padding-top: 10px;\n}\n\n.ProductPageSnippet-video {\n display: block;\n max-width: 100%;\n pointer-events: none;\n}\n\n.ProductPageSnippet-separator {\n background-color: #B4B4B4;\n border: 0;\n height: 1px;\n margin: 0 20px;\n}\n\n.ProductPageSnippet-box {\n padding: 45px 20px 60px;\n}\n\n.ProductPageSnippet-title {\n font-family: 'Gotham-Bold', sans-serif;\n font-size: 23px;\n font-weight: 400;\n line-height: 1.6;\n margin-bottom: 10px;\n}\n\n.ProductPageSnippet-title.is-small {\n font-size: 18px;\n}\n\n.ProductPageSnippet-text {\n font-size: 16px;\n margin-bottom: 20px;\n}\n\n.ProductPageSnippet-logoLink {\n display: block;\n width: 115px;\n}\n\n.ProductPageSnippet-logoImage {\n max-height: 100%;\n max-width: 100%;\n}\n\n.ProductPageSnippet-smallImage {\n max-height: 100px;\n max-width: 70px;\n padding-bottom: 20px;\n}\n\n.ProductPageSnippet-row {\n padding: 0 20px 50px;\n}\n\n.ProductPageSnippet-blinkImages,\n.ProductPageSnippet-compareImages {\n height: 330px;\n margin: 0 auto;\n overflow: hidden;\n position: relative;\n width: 374px;\n}\n\n.ProductPageSnippet-blinkImages .ProductPageSnippet-image {\n position: absolute;\n}\n\n.ProductPageSnippet-blinkImages .ProductPageSnippet-image:last-child {\n animation: fadeInOut 2.5s ease-in-out infinite alternate;\n transition: opacity 1s ease-in-out;\n}\n\n.ProductPageSnippet-compareImages:after {\n background-color: #000;\n content: '';\n height: 100%;\n left: 50%;\n position: absolute;\n top: 30px;\n width: 2px;\n}\n\n.ProductPageSnippet-compareImagesContent {\n height: 100%;\n position: absolute;\n width: 100%;\n}\n\n.ProductPageSnippet-compareImagesContent:last-child {\n overflow: hidden;\n width: 50%;\n}\n\n.ProductPageSnippet-compareImagesContent .ProductPageSnippet-image {\n max-width: none;\n width: 374px;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Values", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst Values = () => {\n return (\n <div>\n <div className=\"Values\">\n <img\n src=\"https://cdn.shopify.com/s/files/1/0384/6721/files/Banner_-_Land_Rover_River.jpg?52669\"\n alt=\"Values\"\n className=\"Values-header\"\n />\n\n <div className=\"Values-content\">\n <h2 className=\"Values-title\">Our Values</h2>\n\n <div className=\"Values-columns\">\n <div className=\"Values-column\">\n <h3 className=\"Values-column-title\">Durability</h3>\n <p className=\"Values-column-desc\">\n We build rugged and reliable products; buy it once, buy it right.\n </p>\n </div>\n\n <div className=\"Values-column\">\n <h3 className=\"Values-column-title\">Portability</h3>\n <p className=\"Values-column-desc\">\n We value functionality, keeping you powered and protected from nightstand to\n mountaintop.\n </p>\n </div>\n\n <div className=\"Values-column\">\n <h3 className=\"Values-column-title\">Resourcefulness</h3>\n <p className=\"Values-column-desc\">\n We are minimalist, always striving to do more, with less.\n </p>\n </div>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default Values\n", | |
| "style": ".Values {\n background: #000;\n}\n\n.Values-header {\n width: 100%;\n height: auto;\n}\n\n.Values-content {\n color: #fff;\n}\n\n.Values-title {\n font-size: 50px;\n width: 100%;\n padding: 0 20px;\n margin-top: -80px;\n margin-bottom: 40px;\n\n background: linear-gradient(rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 90%);\n}\n\n.Values-columns {\n padding: 0 20px;\n background: #000;\n\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n grid-gap: 20px;\n}\n\n@media (max-width: 767px) {\n .Values-columns {\n grid-template-columns: 1fr;\n grid-template-rows: repeat(3, 1fr);\n }\n}\n\n.Values-column-title {\n font-size: 27px;\n font-family: 'Gotham-Bold';\n margin-bottom: 20px;\n}\n\n.Values-column-desc {\n margin-bottom: 20px;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "FeaturedProduct", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst FeaturedProduct = ({ product: { img, title, subtitle } }) => {\n return (\n <figure className=\"FeaturedProduct\">\n <img className=\"FeaturedProduct-img\" src={img} alt=\"Modern Strap\" />\n\n <figcaption className=\"FeaturedProduct-caption\">\n <h2 className=\"FeaturedProduct-caption-title\">{title}</h2>\n <p className=\"FeaturedProduct-caption-subtitle\">{subtitle}</p>\n </figcaption>\n </figure>\n )\n}\n\nexport default FeaturedProduct\n", | |
| "style": ".FeaturedProduct {\n height: 600px;\n position: relative;\n}\n\n.FeaturedProduct-img {\n object-fit: cover;\n height: 100%;\n max-width: 100%;\n}\n\n@media (max-width: 767px) {\n .FeaturedProduct {\n height: auto;\n }\n\n .FeaturedProduct:not(:last-child) {\n margin-bottom: 10px;\n }\n\n .FeaturedProduct-img {\n height: auto;\n }\n}\n\n.FeaturedProduct-caption {\n color: #fff;\n\n position: absolute;\n bottom: 0;\n top: 60%;\n left: 0;\n right: 0;\n\n display: flex;\n flex-direction: column;\n justify-content: flex-end;\n align-items: flex-start;\n padding: 15px 15px;\n background: linear-gradient(rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 1) 90%);\n}\n\n.FeaturedProduct-caption-title {\n font-size: 38px;\n line-height: 1;\n}\n\n.FeaturedProduct-caption-subtitle {\n font-size: 20px;\n font-family: 'Gotham-Bold';\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Image", | |
| "code": "import React from 'react'\nimport './styles.css'\n\nconst Image = ({ src, loading = 'lazy', ...props }) => {\n return <img src={src} loading={loading} {...props} />\n}\n\nexport default Image\n", | |
| "style": "img {\n width: 100%;\n height: auto;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "LandingPageFeaturedProducts", | |
| "code": "import React from 'react'\nimport FeaturedProduct from 'Components/FeaturedProduct'\n\nimport './styles.css'\n\nconst LandingPageFeaturedProducts = ({ productA, productB }) => {\n return (\n <div className=\"container\">\n <div className=\"LandingPageFeaturedProducts\">\n <FeaturedProduct product={productA} />\n\n <FeaturedProduct product={productB} />\n </div>\n </div>\n )\n}\n\nexport default LandingPageFeaturedProducts\n", | |
| "style": "@media (min-width: 768px) {\n .LandingPageFeaturedProducts {\n display: flex;\n justify-content: space-between;\n }\n\n .LandingPageFeaturedProducts > * {\n flex: 0 0 calc(50% - 10px);\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "TestComponent", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst TestComponent = ({ value = '', products = [] }) => {\n return (\n <div>\n <h1 className=\"heading\">You can preview here: {value}.</h1>\n <hr/>\n {products.map(product => (\n <p key={product}>\n {product}\n </p>\n ))}\n </div>\n )\n}\n\nexport default TestComponent", | |
| "style": ".heading {\n margin: 20px;\n color: #E74B90;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "TestComponent2", | |
| "code": "import React from 'react'\n\nimport './styles.css'\n\nconst Section = () => {\n return (\n <h1 className=\"heading\">TC2...</h1>\n )\n}\n\nexport default Section", | |
| "style": ".heading {\n margin: 20px;\n color: #E74B90;\n}", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "Search", | |
| "code": "import React, { useState } from 'react'\nimport cx from 'classnames'\nimport PageWidth from 'Components/PageWidth'\nimport Icons from 'Components/Icons'\n\nimport './styles.css'\n\nconst Search = ({ isOpen, closeSearch }) => {\n let [searchValue, setSearchValue] = useState('')\n const updateSearchValue = e => {\n setSearchValue(e.target.value)\n }\n\n return (\n <>\n <div className={cx('Search-overlay', { 'Search-overlay--is-active': isOpen })}></div>\n <div className={cx('Search', { 'Search--is-active': isOpen })}>\n <PageWidth className=\"Search-wrap\">\n <form action=\"/search\" method=\"get\" className=\"Search-form\" role=\"search\">\n <button type=\"submit\">\n <Icons name=\"Search\" black large />\n </button>\n <input\n type=\"search\"\n name=\"q\"\n value={searchValue}\n ref={input => input && isOpen && input.focus()}\n onChange={updateSearchValue}\n placeholder=\"Search our store\"\n aria-label=\"Search our store\"\n />\n </form>\n <button type=\"button\" onClick={closeSearch}>\n <Icons name=\"Close\" black large />\n </button>\n </PageWidth>\n </div>\n </>\n )\n}\n\nexport default Search\n", | |
| "style": ".Search {\n width: 100%;\n position: absolute;\n left: 0;\n right: 0;\n bottom: 100%;\n height: 100%;\n z-index: 30;\n overflow: hidden;\n transition: all 0.3s cubic-bezier(0, 0, 0.38, 1);\n background: #fff;\n}\n\n.Search--is-active {\n bottom: 0;\n}\n\n.Search-overlay {\n position: fixed;\n left: 0;\n top: 0;\n bottom: 0;\n right: 0;\n background: #aeb1b8;\n opacity: 0;\n pointer-events: none;\n}\n\n.Search-overlay--is-active {\n opacity: 0.6;\n transition: opacity 0.3s linear;\n}\n\n.Search-form {\n flex-grow: 1;\n display: flex;\n align-items: center;\n}\n\n.Search-form input {\n border: none;\n outline: none;\n width: 100%;\n padding: 8px 10px;\n line-height: 1.5;\n}\n\ninput[type=search]::-ms-reveal,\ninput[type=search]::-ms-clear {\n display: none;\n width: 0;\n height: 0;\n}\n\ninput[type=\"search\"]::-webkit-search-decoration,\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-results-button,\ninput[type=\"search\"]::-webkit-search-results-decoration {\n display: none;\n}\n\n\n.Search-wrap {\n display: flex;\n}\n\n.Search button {\n padding: 0 20px;\n}\n\n.Search button svg {\n display: block;\n}\n\n\n@media (min-width: 768px) {\n .Search-form input {\n font-size: 1.5em;\n }\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "CartItem", | |
| "code": "import React from 'react'\nimport ItemQuantityInput from 'Components/ItemQuantityInput'\n\nimport './styles.css'\n\nconst currencyFormatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n})\n\nconst CartItem = ({ item }) => {\n return (\n <div className=\"CartItem-container\">\n <a className=\"CartItem-img-wrapper\" href={`/${item.variant.product.handle}`}>\n <img\n alt={item.variant.image.altText || item.title}\n className=\"CartItem-img\"\n src={item.variant.image.src}\n width=\"70\"\n height=\"70\"\n />\n </a>\n <div className=\"CartItem-details\">\n <a className=\"CartItem-title-link\" href={`/${item.variant.product.handle}`}>\n <p>{item.title}</p>\n </a>\n <p className=\"CartItem-description\">{item.description}</p>\n <div className=\"CartItem-qty-price-container\">\n <ItemQuantityInput\n itemId={item.id}\n variantId={item.variant.id}\n quantity={item.quantity}\n />\n <span className=\"CartItem-price\">\n {currencyFormatter.format(item.variant.priceV2.amount)}\n </span>\n </div>\n </div>\n </div>\n )\n}\n\nexport default CartItem\n", | |
| "style": ".CartItem-container {\n display: flex;\n padding: 20px 0;\n}\n\n.CartItem-container:last-child {\n border-bottom: 0 none;\n padding-bottom: 0;\n}\n\n.CartItem-img-wrapper {\n display: flex;\n justify-content: center;\n align-items: center;\n flex: 1;\n}\n\n.CartItem-img {\n display: block;\n margin: 0 auto;\n max-width: 100%;\n width: auto;\n height: auto;\n}\n\n.CartItem-details {\n flex: 2;\n padding-left: 20px;\n}\n\n.CartItem-details > * {\n margin-bottom: 8px;\n}\n\n.CartItem-title-link {\n color: inherit;\n text-decoration: none;\n}\n\n.CartItem-description {\n font-size: 13px;\n}\n\n.CartItem-qty-price-container {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.CartItem-price {\n font-size: 14px;\n}\n", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "page_meta", | |
| "code": "\n import React from 'react'\n import { Helmet } from 'react-helmet-async'\n const PageMeta = ({ title, description, url }) => {\n return (\n <Helmet>\n <title>{title}</title>\n <meta name=\"description\" content={description} />\n <link rel=\"canonical\" href={url} />\n </Helmet>\n )\n }\n\t\texport default PageMeta", | |
| "style": "", | |
| "__typename": "Component" | |
| }, | |
| { | |
| "name": "dropzone", | |
| "code": "", | |
| "style": "", | |
| "__typename": "Component" | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment