From b4b0759be419e5921314b88900ee7870cd5a9a34 Mon Sep 17 00:00:00 2001 From: Katie Sexton Date: Tue, 2 Nov 2021 21:55:12 -0600 Subject: [PATCH] build pint club --- assets/blocks/accordion/accordion.css | 62 +++ assets/blocks/accordion/accordion.js | 26 + assets/blocks/club-carousel/club-carousel.css | 106 +++++ assets/blocks/club-carousel/club-carousel.js | 71 +++ assets/blocks/club-checkout/club-checkout.css | 77 +++ assets/blocks/club-checkout/club-checkout.js | 67 +++ assets/blocks/columns/columns.css | 76 +++ assets/blocks/columns/columns.js | 25 + .../blocks/customize-menu/customize-menu.css | 53 +++ .../blocks/customize-menu/customize-menu.js | 64 +++ .../starburst-anchor/starburst-anchor.css | 2 +- assets/scripts/forms.js | 443 ++++++++++++++++++ assets/scripts/scripts.js | 48 +- assets/styles/club.css | 31 ++ assets/styles/forms.css | 112 +++++ assets/styles/lazy-styles.css | 4 + assets/styles/styles.css | 9 + assets/styles/themes/blue-pink.css | 5 +- assets/styles/themes/white-blue.css | 18 + assets/svg/starburst-red.svg | 12 + 20 files changed, 1303 insertions(+), 8 deletions(-) create mode 100644 assets/blocks/accordion/accordion.css create mode 100644 assets/blocks/accordion/accordion.js create mode 100644 assets/blocks/club-carousel/club-carousel.css create mode 100644 assets/blocks/club-carousel/club-carousel.js create mode 100644 assets/blocks/club-checkout/club-checkout.css create mode 100644 assets/blocks/club-checkout/club-checkout.js create mode 100644 assets/blocks/columns/columns.css create mode 100644 assets/blocks/columns/columns.js create mode 100644 assets/blocks/customize-menu/customize-menu.css create mode 100644 assets/blocks/customize-menu/customize-menu.js create mode 100644 assets/scripts/forms.js create mode 100644 assets/styles/club.css create mode 100644 assets/styles/forms.css create mode 100644 assets/svg/starburst-red.svg diff --git a/assets/blocks/accordion/accordion.css b/assets/blocks/accordion/accordion.css new file mode 100644 index 0000000..2ff174d --- /dev/null +++ b/assets/blocks/accordion/accordion.css @@ -0,0 +1,62 @@ +.accordion { + margin-top: 2rem; +} + +@media (min-width: 1200px) { + .accordion { + width: unset; + display: flex; + flex-wrap: wrap; + } + + .accordion > div { + width: calc(50% - 1rem); + margin-right: 2rem; + } + + .accordion > div:nth-of-type(2n) { + margin-right: 0; + } +} + +.accordion > div { + text-align: left; + font-size: 66%; + line-height: 1.4; + font-weight: var(--weight-normal); + margin-bottom: 1rem; +} + +.accordion > div h3 { + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + transition: letter-spacing 0.2s; +} + +.accordion > div h3:hover, +.accordion > div h3:focus { + letter-spacing: 1px; +} + +.accordion > div h3::after { + content: '\2303'; + display: block; + margin-left: 3px; + transform: rotate(180deg); + transition: transform 0.2s; +} + +.accordion > div h3 + p { + margin-top: 1rem; +} + +.accordion > div h3[aria-expanded=false] + p { + display: none; + visibility: hidden; +} + +.accordion > div h3[aria-expanded=true]::after { + transform: rotate(0deg); +} diff --git a/assets/blocks/accordion/accordion.js b/assets/blocks/accordion/accordion.js new file mode 100644 index 0000000..657532b --- /dev/null +++ b/assets/blocks/accordion/accordion.js @@ -0,0 +1,26 @@ +import { + createEl, + toClassName +} from '../../scripts/scripts.js'; + +function toggle(e) { + const expanded = e.target.getAttribute('aria-expanded'); + if (expanded === 'true') { + e.target.setAttribute('aria-expanded', false); + } else { + e.target.setAttribute('aria-expanded', true); + } +} + +export default function decorateAccordion(block) { + const rows = block.querySelectorAll('div:scope > div'); + rows.forEach((row) => { + const q = row.querySelector('h3'); + q.setAttribute('role', 'button'); + q.setAttribute('aria-expanded', false); + q.setAttribute('aria-controls', toClassName(q.textContent)); + q.addEventListener('click', toggle); + const a = q.nextElementSibling; + a.id = toClassName(q.textContent); + }) +} diff --git a/assets/blocks/club-carousel/club-carousel.css b/assets/blocks/club-carousel/club-carousel.css new file mode 100644 index 0000000..1076c99 --- /dev/null +++ b/assets/blocks/club-carousel/club-carousel.css @@ -0,0 +1,106 @@ +.club-carousel-container { + position: relative; + flex: 1 1 auto; + max-width: unset; + width: 100%; + padding: 0; +} + +.club-carousel { + visibility: hidden; + display: none; +} + +.club-carousel[data-block-loaded=true] { + visibility: visible; + display: flex; + overflow-x: scroll; + overflow-y: hidden; + scroll-behavior: smooth; + max-height: inherit; + width: unset; +} + +.club-carousel::-webkit-scrollbar { + display: none; +} + +@media (min-width: 768px) { + .club-carousel { + height: calc(100vh * .6); + } +} + +.club-carousel-slide { + display: inline-block; + flex-shrink: 0; + flex-grow: 0; +} + +.club-carousel-slide:not(:last-child) { + margin-right: 1rem; +} + +.club-carousel-slide img { + height: 100%; + max-width: 254px; + object-fit: cover; +} + +@media (min-width: 464px) { + .club-carousel-slide { + max-width: calc(100vw / 2.6); + } + + .club-carousel-slide img { + max-width: unset; + width: calc(100vw / 2.6); + } +} + +@media (min-width: 768px) { + .club-carousel .club-carousel-slide { + max-width: unset; + width: unset; + } + + .club-carousel .club-carousel-slide img { + height: 100%; + object-fit: cover; + } +} + +@media (min-width: 1200px) { + .club-carousel .club-carousel-slide img { + } +} + +.club-carousel .icon { + position: absolute; + bottom: 1.5rem; + background: var(--color-white); + opacity: 0.2; +} + +.club-carousel .icon.nav.right { + right: 1.5rem; +} + +.club-carousel .icon.nav.left { + left: 1.5rem; +} + +@media (min-width: 768px) { + .club-carousel .icon.nav.right { + right: 1rem; + } + + .club-carousel .icon.nav.left { + left: 1rem; + } +} + +.club-carousel .icon.nav:hover, +.club-carousel .icon.nav:focus { + opacity: 1; +} diff --git a/assets/blocks/club-carousel/club-carousel.js b/assets/blocks/club-carousel/club-carousel.js new file mode 100644 index 0000000..060fc28 --- /dev/null +++ b/assets/blocks/club-carousel/club-carousel.js @@ -0,0 +1,71 @@ +import { + createEl +} from '../../scripts/scripts.js'; + +async function fetchCarousel(url) { + const resp = await fetch(`${url}.plain.html`); + if (resp.ok) { + const html = await resp.text(); + const placeholder = createEl('div'); + placeholder.innerHTML = html; + const pictures = placeholder.querySelectorAll('picture'); + return [ ...pictures ]; + } else { + console.error('Carousel cannot be created'); + } +} + +function navScroll(e) { + const btn = e.target.closest('button'); + const carousel = btn.closest('.club-carousel'); + const num = carousel.querySelectorAll('.club-carousel-slide').length; + const slide = carousel.querySelector('.club-carousel-slide'); + const slideWidth = slide.offsetWidth; + const container = carousel.parentElement; + const containerWidth = container.offsetWidth; + const direction = btn.classList[btn.classList.length - 1]; + // const currPosition = carousel.scrollLeft; + // const totalWidth = slideWidth * num; + + if (direction === 'left') { + carousel.scrollLeft -= containerWidth - 10; + } else if (direction === 'right') { + carousel.scrollLeft += containerWidth + 10; + } +} + +export default async function decorateClubCarousel(block) { + const { href } = block.querySelector('a'); + const { pathname } = new URL(href); + const pictures = await fetchCarousel(pathname); + block.innerHTML = ''; + if (pictures) { + + pictures.forEach((pic) => { + const container = createEl('div', { + class: 'club-carousel-slide' + }); + container.append(pic); + block.append(container); + }); + + const rightBtn = createEl('button', { + class: 'icon nav right', + title: `scroll right` + }); + + const leftBtn = createEl('button', { + class: 'icon nav left', + title: `scroll left` + }); + + rightBtn.addEventListener('click', navScroll); + leftBtn.addEventListener('click', navScroll); + + block.prepend(leftBtn); + block.prepend(rightBtn); + + } else { + block.remove(); + } +} diff --git a/assets/blocks/club-checkout/club-checkout.css b/assets/blocks/club-checkout/club-checkout.css new file mode 100644 index 0000000..d39092a --- /dev/null +++ b/assets/blocks/club-checkout/club-checkout.css @@ -0,0 +1,77 @@ +.club-checkout-container { + text-align: center; +} + +@media (min-width: 1200px) { + .club-checkout { + width: unset; + } +} + +.club-checkout > div { + /* border: 2px solid red; */ + font-size: 66%; + line-height: 1.4; + font-weight: var(--weight-normal); +} + +.club-checkout > div div { + padding: 4rem 1rem; +} + +.club-checkout > div svg:not(.icon-reg) { + width: 20rem; + height: 20rem; +} + +.club-checkout a.btn { + margin-top: 1.6rem; +} + +@media (min-width: 768px) { + .club-checkout > div { + display: flex; + } + + .club-checkout > div.club-checkout-2 > div { + width: calc(100% / 2); + } + + .club-checkout > div.club-checkout-2 > div:first-child { + margin-right: 1rem; + } + + .club-checkout > div.club-checkout-2 > div:last-child { + margin-left: 1rem; + } + + .club-checkout > div.club-checkout-3 > div { + width: calc(100% / 3); + } + + .club-checkout > div.club-checkout-3 > div:nth-child(2) { + margin: 0 2rem; + } + + .club-checkout > div.club-checkout-3 svg { + width: 15rem; + height: 15rem; + } +} + +/* COLORS */ +@media (min-width: 768px) { + .club-checkout.club-checkout-blue { + padding: 2rem; + } +} + +.club-checkout.club-checkout-blue { + background: var(--color-blue); + color: var(--color-white); +} + +.club-checkout.club-checkout-blue a.btn { + background: var(--color-white); + color: var(--color-blue); +} diff --git a/assets/blocks/club-checkout/club-checkout.js b/assets/blocks/club-checkout/club-checkout.js new file mode 100644 index 0000000..45a987d --- /dev/null +++ b/assets/blocks/club-checkout/club-checkout.js @@ -0,0 +1,67 @@ +import { + createEl, + readBlockConfig +} from '../../scripts/scripts.js'; + +import { + getFields, + buildFields +} from '../../scripts/forms.js'; + +import { + clearCustomizeMenu +} from '../customize-menu/customize-menu.js'; + +function populateCustomizeMenu(e, type) { + const menu = document.querySelector('.customize-menu'); + clearCustomizeMenu(menu); + if (menu) { + // display menu + menu.parentElement.setAttribute('aria-expanded', true); + // populate title + const title = menu.querySelector('h2'); + title.textContent = `customize your ${type} pint club`; + // populate form + const form = menu.querySelector('form'); + const fieldsArr = ['pint-club']; + if (type === 'prepay') { fieldsArr.unshift('prepay-months'); } + const allFields = getFields(fieldsArr); + allFields.forEach((field) => { + const f = buildFields(field); + form.append(f); + }); + const btn = document.getElementById('customize-footer-btn'); + btn.textContent = 'join the club'; + } +} + +function enableCheckout(a) { + a.classList.add('btn', 'btn-rect'); + const { hash } = new URL(a.href); + const type = hash.replace('#', ''); + a.removeAttribute('href'); + a.addEventListener('click', (e) => { + populateCustomizeMenu(e, type); + }); +} + +export default function decorateClubCheckout(block) { + const config = readBlockConfig(block); + for (const property in config) { + if (!property.startsWith('-')) { + const configDiv = block.querySelector('div'); + configDiv.remove(); + } else { + delete config[property]; + } + } + if (config.color) { + block.classList.add(`club-checkout-${config.color}`); + } + const columnsCount = block.firstChild.childElementCount; + block.firstChild.classList.add(`club-checkout-${columnsCount}`); + // stylize links + block.querySelectorAll('a').forEach((a) => { + enableCheckout(a); + }); +} diff --git a/assets/blocks/columns/columns.css b/assets/blocks/columns/columns.css new file mode 100644 index 0000000..61979d6 --- /dev/null +++ b/assets/blocks/columns/columns.css @@ -0,0 +1,76 @@ +.columns-container { + text-align: center; +} + +@media (min-width: 1200px) { + .columns { + width: unset; + } +} + +.columns > div { + /* border: 2px solid red; */ + font-size: 66%; + line-height: 1.4; + font-weight: var(--weight-normal); +} + +.columns > div div { + padding: 1rem; +} + +.columns > div svg:not(.icon-reg) { + width: 20rem; + height: 20rem; +} + +.columns a.btn { + margin-top: 1.6rem; +} + +@media (min-width: 768px) { + .columns > div { + display: flex; + } + + .columns > div.columns-2 > div { + width: calc(100% / 2); + } + + .columns > div.columns-2 > div:first-child { + margin-right: 1rem; + } + + .columns > div.columns-2 > div:last-child { + margin-left: 1rem; + } + + .columns > div.columns-3 > div { + width: calc(100% / 3); + } + + .columns > div.columns-3 > div:nth-child(2) { + margin: 0 2rem; + } + + .columns > div.columns-3 svg { + width: 15rem; + height: 15rem; + } +} + +/* COLORS */ +@media (min-width: 768px) { + .columns.columns-blue { + padding: 2rem; + } +} + +.columns.columns-blue { + background: var(--color-blue); + color: var(--color-white); +} + +.columns.columns-blue a.btn { + background: var(--color-white); +} diff --git a/assets/blocks/columns/columns.js b/assets/blocks/columns/columns.js new file mode 100644 index 0000000..5d8f752 --- /dev/null +++ b/assets/blocks/columns/columns.js @@ -0,0 +1,25 @@ +import { + createEl, + readBlockConfig +} from '../../scripts/scripts.js'; + +export default function decorateColumns(block) { + const config = readBlockConfig(block); + for (const property in config) { + if (!property.startsWith('-')) { + const configDiv = block.querySelector('div'); + configDiv.remove(); + } else { + delete config[property]; + } + } + if (config.color) { + block.classList.add(`columns-${config.color}`); + } + const columnsCount = block.firstChild.childElementCount; + block.firstChild.classList.add(`columns-${columnsCount}`); + // stylize links + block.querySelectorAll('a').forEach((a) => { + a.classList.add('btn', 'btn-rect'); + }); +} diff --git a/assets/blocks/customize-menu/customize-menu.css b/assets/blocks/customize-menu/customize-menu.css new file mode 100644 index 0000000..8126d33 --- /dev/null +++ b/assets/blocks/customize-menu/customize-menu.css @@ -0,0 +1,53 @@ +.customize-menu-container { + /* border: 2px solid red; */ + overflow-y: scroll; +} + +.customize-menu-container[aria-expanded=false] { + visibility: hidden; + display: none; +} + +.customize-menu-container { + visibility: visible; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; +} + +.customize-menu { + width: 60rem; + max-width: 92%; + max-height: calc(100vh - 4rem); + margin: 2rem auto; + padding: 2rem; +} + +.customize-body { + border: 1px solid currentColor; +} + +.customize-body-form > *:last-child { + border-bottom: 0; +} + +.customize-body-head { + border-bottom: 1px solid currentColor; + padding-left: 2rem; + padding-right: 2rem; +} + +.customize-footer { + padding-bottom: calc(100vh / 5); +} + +.customize-footer a { + /* padding: 1rem 2rem; */ + font-size: 80%; +} + +.customize-footer a:first-child { + margin-top: 2rem; +} diff --git a/assets/blocks/customize-menu/customize-menu.js b/assets/blocks/customize-menu/customize-menu.js new file mode 100644 index 0000000..0dbd851 --- /dev/null +++ b/assets/blocks/customize-menu/customize-menu.js @@ -0,0 +1,64 @@ +import { + createEl, + readBlockConfig +} from '../../scripts/scripts.js'; + +export function clearCustomizeMenu(block) { + block.querySelector('.customize-body-head').innerHTML = ''; + block.querySelector('.customize-body-form').innerHTML = ''; + const btn = document.getElementById('customize-footer-btn'); + btn.textContent = ''; + // remove event listeners + const newBtn = btn.cloneNode(true); + btn.parentNode.replaceChild(newBtn, btn); +} + +export default function buildCustomizeMenu(block) { + block.parentElement.setAttribute('aria-expanded', false); + + // container + block.classList.add('customize'); + + // close button + ////////////////////////////////////////////////// + const closeBtnContainer = createEl('div', { + class: 'icon-container customize-close' + }); + const closeBtn = createEl('button', { + class: 'icon close', + title: `close TODO` + }); + closeBtn.addEventListener('click', (e) => { + block.parentElement.setAttribute('aria-expanded', false); + }); + closeBtnContainer.append(closeBtn); + + // customize body + ////////////////////////////////////////////////// + const body = createEl('div', { + class: 'customize-body' + }); + //body header + const head = createEl('h2', { + class: 'customize-body-head' + }); + // body form + const form = createEl('form', { + class: 'customize-body-form' + }); + body.append(head, form); + + // customize footer + ////////////////////////////////////////////////// + const footer = createEl('div', { + class: 'customize-footer' + }); + + const btn = createEl('a', { + id: 'customize-footer-btn', + class: 'btn btn-rect' + }); + footer.append(btn); + + block.append(closeBtnContainer, body, footer); +} diff --git a/assets/blocks/starburst-anchor/starburst-anchor.css b/assets/blocks/starburst-anchor/starburst-anchor.css index ec816cb..a258e8b 100644 --- a/assets/blocks/starburst-anchor/starburst-anchor.css +++ b/assets/blocks/starburst-anchor/starburst-anchor.css @@ -3,7 +3,7 @@ } .starburst-anchor { - /* border: 2px solid red; */ + margin-top: 2rem !important; margin-bottom: 2rem !important; } diff --git a/assets/scripts/forms.js b/assets/scripts/forms.js new file mode 100644 index 0000000..7a23c2d --- /dev/null +++ b/assets/scripts/forms.js @@ -0,0 +1,443 @@ +import { + createEl, + toClassName, + readBlockConfig +} from './scripts.js'; + +function toggle(e) { + const expanded = e.target.getAttribute('aria-expanded'); + if (expanded === 'true') { + e.target.setAttribute('aria-expanded', false); + } else { + e.target.setAttribute('aria-expanded', true); + } +} + +export function getFields(fields) { + let allFields = []; + fields.forEach((f) => { + switch (f) { + case 'contact': + allFields.push( + { + data: { + store: true + }, + title: 'name', + type: 'text', + placeholder: 'your name', + required: true + }, + { + data: { + store: true + }, + title: 'cell', + type: 'tel', + placeholder: 'your cell', + required: true + }, + { + data: { + store: true + }, + title: 'email', + type: 'email', + placeholder: 'your email', + required: true + } + ); + break; + case 'address': + allFields.push( + { + data: { + fieldtype: 'address', + store: true + }, + title: 'addr1', + type: 'text', + placeholder: 'your address', + required: true + }, + { + data: { + fieldtype: 'address', store: true + }, + title: 'addr2', + type: 'text', + placeholder: 'apt # or building code? add here!' + }, + { + data: { + fieldtype: 'address', + store: true + }, + title: 'city', + type: 'text', + placeholder: 'your city', + required: true + }, + { + data: { + fieldtype: 'address', + store: true + }, + title: 'state', + type: 'text', + value: 'utah', + readonly: true + }, + { + data: { + fieldtype: 'address' + }, + title: 'zip', + type: 'select', + placeholder: 'your zip code', + src: 'deliveryZips', + required: true + } + ); + break; + case 'address-national': + allFields.push( + { + data: { + fieldtype: 'address', + store: true + }, + title: 'addr1', + type: 'text', + placeholder: 'your address', + required: true + }, + { + data: { + fieldtype: 'address', + store: true + }, + title: 'addr2', + type: 'text', + placeholder: 'apt # or building code? add here!' + }, + { + data: { + fieldtype: 'address', + store: true + }, + title: 'city', + type: 'text', + placeholder: 'your city', + required: true + }, + { + data: { + fieldtype: 'address', + store: true + }, + title: 'state', + type: 'text', + placeholder: 'your state', + required: true + }, + { + data: { + fieldtype: 'address', + store: true + }, + title: 'zip', + type: 'text', + placeholder: 'your zip code', + required: true + } + ) + break; + case 'pint-club': + allFields.push( + { + title: 'customize-pints', + type: 'checkbox', + label: 'customize your pints (select any that apply)', + src: 'packs', + options: [ + 'keep it normalĀ®', + 'vegan', + 'half-vegan', + 'nut free', + 'gluten free' + ] + }, + { + title: 'allergies', + type: 'text', + placeholder: 'any allergies? even shellfish, seriously! ya never know!' + }, + { + title: 'delivery-option', + type: 'radio', + label: 'how do you want to get your pints?', + options: [ + 'pickup', + 'shipping' + ], + required: true + } + ); + break; + case 'prepay-months': + allFields.push( + { + title: 'prepay-months', + type: 'radio', + label: 'how many months?', + options: [ + '3', + '6', + '12' + ], + required: true + } + ); + break; + case 'merch': + allFields.push( + { + title: 'merch-checkout', + type: 'radio', + label: 'pick up/shipping', + options: [ + 'in store pick up', + 'ship in the mail' + ], + required: true + } + ); + break; + case 'pick-up': + allFields.push( + { + title: 'pickup-date', + type: 'text', + value: 'today', + readonly: true + }, + { + title: 'pickup-time', + type: 'select', + placeholder: 'select your pickup time', + src: 'hoursOfOp', + required: true + } + ) + break; + case 'discount-code': + allFields.push( + { + title: 'discount', + type: 'text', + placeholder: 'discount code' + } + ) + break; + case 'tip': + allFields.push( + { + title: 'tip', + type: 'select', + placeholder: 'no tip', + src: 'tipPercentages' + } + ) + break; + case 'payment-option': + allFields.push( + { + title: 'payment-option', + type: 'checkbox', + label: 'pay with gift card?', + options: [ + 'pay with gift card?' + ] + } + ) + break; + case 'cone-builder': + allFields.push( + { + title: 'flavor', + type: 'select', + placeholder: 'select your flavor', + src: 'coneBuilderFlavors' + }, + { + title: 'dip', + type: 'radio', + label: 'dip', + options: [ + 'no dip' + ] + }, + { + title: 'toppings', + type: 'checkbox', + label: 'select topping (up to 3)', + options: [], + src: 'coneBuilderTopping' + } + ) + break; + case 'cone-builder-second-flavor': + allFields.push( + { + title: 'second-flavor', + type: 'select', + placeholder: 'select your second flavor', + src: 'coneBuilderFlavors' + } + ) + break; + case 'cone-builder-title': + allFields.push( + { + title: 'title', + type: 'text', + placeholder: 'name your creation', + required: true + } + ) + break; + default: + console.error('hey normal, you tried to build a form with an invalid field:', f); + break; + } + }) + return allFields; +} + +export function buildFields(field) { + let fieldEl; + + if (field.type === 'radio' || field.type === 'checkbox') { + //setup options + fieldEl = createEl('div', { + class: `form-${field.type}`, + id: `${field.type}-${toClassName(field.title)}` + }); + + const expanded = field.required || false; + const title = createEl('h3', { + role: 'button', + 'aria-expanded': expanded, + // 'aria-controls': toClassName(q.textContent) + }); + title.textContent = field.label; + title.addEventListener('click', toggle); + + fieldEl.append(title); + + const optionsContainer = createEl('div', { + class: `form-${field.type}-container`, + 'aria-expanded': false + }); + + field.options.forEach((o) => { + const label = createEl('label', { + class: `form-${field.type}-option`, + for: toClassName(o) + }); + label.textContent = o; + + const bubble = createEl('span', { + class: `form-${field.type}-bubble` + }); + + const option = createEl('input', { + class: `form-${field.type}-default`, + id: toClassName(o), + name: field.title, + type: field.type + }); + option.value = o; + + label.append(option, bubble); + optionsContainer.append(label); + }); + + fieldEl.append(optionsContainer); + } + else if (field.type === 'select') { + fieldEl = createEl('div', { + class: 'form-select-wrapper' + }); + // data attributes + if (field.data) { + for (dataType in field.data) { + fieldEl.setAttribute(`data-${dataType}`, field.data[dataType]); + } + } + const select = createEl(field.type, { + class: 'form-select', + id: toClassName(field.title), + name: toClassName(field.title) + }); + + const option = createEl('option'); + option.textContent = field.placeholder; + option.value = ''; + option.disabled = true; + option.selected = true; + option.hidden = true; + + select.append(option); + fieldEl.append(select); + } else { + fieldEl = createEl('input', { + class: 'form-field', + id: toClassName(field.title), + name: toClassName(field.title), + type: field.type || 'text' + }); + // input patterns + if (field.type === 'tel') { + fieldEl.pattern = '[0-9]{10,11}'; + } else if (field.type === 'email') { + fieldEl.pattern = '[a-zA-Z0-9\\.]+@[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)+'; + } else if (field.title === 'zip') { + fieldEl.pattern = '[0-9]{5}(?:-[0-9]{4})?'; + } + // placeholder + if (field.placeholder) { + fieldEl.placeholder = field.placeholder; + } + // default value + if (field.value) { + fieldEl.value = field.value; + } + // data params + if (field.data) { + for (dataType in field.data) { + fieldEl.setAttribute(`data-${dataType}`, field.data[dataType]); + } + } + // required + if (field.required) { + fieldEl.required = field.required; + } + // readonly + if (field.readonly) { + fieldEl.readOnly = field.readonly; + } + } + + return fieldEl; +} + +export function populateOptions(el, data) { + data.forEach((d) => { + const option = createEl('option'); + option.value = d.value || d; + option.textContent = d.text || d; + el.append(option); + }); +} diff --git a/assets/scripts/scripts.js b/assets/scripts/scripts.js index 386d75f..1e9d4d7 100644 --- a/assets/scripts/scripts.js +++ b/assets/scripts/scripts.js @@ -266,7 +266,7 @@ async function loadBlock(block) { loadCSS(`blocks/${name}/${name}.css`); try { const mod = await - import (buildPath(`blocks/${name}/${name}.js`)); + import(buildPath(`blocks/${name}/${name}.js`)); if (mod.default) { await mod.default(block, name, document); } @@ -446,6 +446,9 @@ async function decoratePage(win = window) { if (path.includes('about')) { decorateAboutPage(path); } + if (path.includes('pint-club')) { + decorateClubPage(path); + } doc.querySelector('body').classList.add('appear'); setLCPTrigger(doc, async() => { @@ -454,6 +457,16 @@ async function decoratePage(win = window) { if (path.includes('index')) { decorateIndexPage(path, main); } + const checkoutEnabled = ['pint-club', 'order']; + if (checkoutEnabled.includes(path[0])) { + decorateSquareLinks(); + loadCSS(`styles/forms.css`); + const mod = await import(buildPath(`scripts/forms.js`)); + if (mod.default) { + await mod.default(block, 'forms', document); + } + loadScript('https://js.squareup.com/v2/paymentform'); + } loadCSS('styles/lazy-styles.css'); loadFooter(); externalizeLinks(); @@ -462,6 +475,23 @@ async function decoratePage(win = window) { } +/** + * Build autoblock. + * @param {array} path path parameters + */ +function buildAutoblock(type) { + const wrapper = createEl('section', { + class: `${type}-container` + }); + const block = createEl('div', { + class: type + }); + wrapper.append(block); + document.querySelector('main').append(wrapper); + decorateBlock(block); + loadBlock(block); +} + /** * Decorate index page. * @param {array} path path parameters @@ -489,8 +519,6 @@ function decorateOrderPage(path) { .querySelector('main > div:first-of-type') .classList.add('order-location-info'); loadCSS('styles/order.css'); - decorateSquareLinks(); - loadScript('https://js.squareup.com/v2/paymentform'); } /** @@ -516,6 +544,20 @@ function decorateAboutPage(path) { loadCSS('styles/about.css'); } +/** + * Decorate pint club page. + * @param {array} path path parameters + */ +function decorateClubPage(path) { + document.querySelector('main').classList.add(path.join('--')); + // set first div as info + document + .querySelector('main > div:first-of-type') + .classList.add('club-info'); + loadCSS('styles/club.css'); + buildAutoblock('customize-menu'); +} + function removeEmptyDivs() { document.querySelectorAll('div').forEach((div) => { console.log(div); diff --git a/assets/styles/club.css b/assets/styles/club.css new file mode 100644 index 0000000..2a33732 --- /dev/null +++ b/assets/styles/club.css @@ -0,0 +1,31 @@ +main.pint-club { + text-align: center; +} + +/* CLUB INFO */ + +main.pint-club > div.club-info p { + position: relative; + height: 10rem; +} + +main.pint-club > div.club-info svg.icon-pint-club { + position: absolute; + width: 20rem; + height: 20rem; + top: -1rem; + right: 0; + z-index: 2; +} + +@media (min-width: 768px) { + main.pint-club > div.club-info svg.icon-pint-club { + right: -10%; + } +} + +@media (min-width: 1200px) { + main.pint-club > div.club-info svg.icon-pint-club { + right: -50%; + } +} diff --git a/assets/styles/forms.css b/assets/styles/forms.css new file mode 100644 index 0000000..adad783 --- /dev/null +++ b/assets/styles/forms.css @@ -0,0 +1,112 @@ +/* DEFAULTS */ +input, label, select, textarea { + margin: 0; + border: 0; + border-radius: 0; + padding: 1rem; + display: inline-block; + vertical-align: middle; + white-space: normal; + background: none; + font-family: acumin-pro-extra-condensed, sans-serif; + font-weight: var(--weight-bold); + font-style: normal; + color: inherit; + font-size: 120%; + line-height: 1; +} + +.form-radio h3, +.form-checkbox h3 { + padding: 2rem; + text-align: left; + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + transition: letter-spacing 0.2s; +} + +.form-radio h3::after, +.form-checkbox h3::after { + content: '\2303'; + display: block; + margin-left: 3px; + transform: rotate(180deg); + transition: transform 0.2s; +} + +.form-radio h3:hover, +.form-radio h3:focus, +.form-checkbox h3:hover, +.form-checkbox h3:focus { + letter-spacing: 1px; +} + +.form-radio h3[aria-expanded=false] + *, +.form-checkbox h3[aria-expanded=false] + * { + visibility: hidden; + display: none; +} + +.form-radio h3[aria-expanded=true]::after, +.form-checkbox h3[aria-expanded=true]::after { + transform: rotate(0deg); +} + +.form-radio-container, +.form-checkbox-container { + display: flex; + flex-wrap: wrap; + padding: 1rem 2rem; + /* font-weight: var(--weight-normal); */ + border-bottom: 1px solid currentColor; +} + +.form-radio-option, +.form-checkbox-option { + position: relative; + margin: 0.5rem 0.5rem 0.5rem 0; + padding-left: 4rem; + font-family: "Century Gothic", sans-serif; + font-family: "Poppins", sans-serif; + font-size: 60%; + cursor: pointer; +} + +.form-radio-default, +.form-checkbox-default { + position: absolute; + opacity: 0; + top: 50%; + left: 9px; + transform: translateY(-50%); +} + +.form-radio-bubble, +.form-checkbox-bubble { + position: absolute; + top: 50%; + left: 0; + height: 3rem; + width: 3rem; + border: 1px solid currentColor; + border-radius: 50%; + transform: translateY(-50%); +} + +.form-radio-default:checked ~ span, +.form-checkbox-default:checked ~ span{ + background: currentColor; +} + +.form-field { + /* border: 2px solid red; */ + display: block; + width: 100%; + padding: 1rem 2rem; +} + +.form-field::placeholder { + color: currentColor; +} diff --git a/assets/styles/lazy-styles.css b/assets/styles/lazy-styles.css index 1bb1db3..aea7fc6 100644 --- a/assets/styles/lazy-styles.css +++ b/assets/styles/lazy-styles.css @@ -24,6 +24,10 @@ a[data-origin=external] { color: var(--color-blue); } +.starburst-container.starburst-red { + color: var(--color-white); +} + .starburst-container:hover, .starburst-container:focus { transform: scale(1.4); diff --git a/assets/styles/styles.css b/assets/styles/styles.css index 8a69636..a96a134 100644 --- a/assets/styles/styles.css +++ b/assets/styles/styles.css @@ -303,3 +303,12 @@ button.icon:focus { .popup-container { visibility: hidden; } + +/* BLOCKS */ +body.appear, .block { + visibility: hidden; +} + +body.appear .block[data-block-loaded=true] { + visibility: unset; +} diff --git a/assets/styles/themes/blue-pink.css b/assets/styles/themes/blue-pink.css index c74e8a7..611ded1 100644 --- a/assets/styles/themes/blue-pink.css +++ b/assets/styles/themes/blue-pink.css @@ -5,7 +5,6 @@ body { } /* INDEX PAGE */ - .index-carousel .icon { background: transparent; } @@ -41,9 +40,7 @@ body { border-color: var(--color-blue); } - /* ORDER PAGE */ - main[class*=order--] > div:not(.order-location-info) { background: var(--color-pink); color: var(--color-blue); @@ -112,4 +109,4 @@ button.icon::after { .order.block #back-btn { background: var(--color-pink); color: var(--color-blue); -} \ No newline at end of file +} diff --git a/assets/styles/themes/white-blue.css b/assets/styles/themes/white-blue.css index b898caa..23d184f 100644 --- a/assets/styles/themes/white-blue.css +++ b/assets/styles/themes/white-blue.css @@ -111,3 +111,21 @@ button.icon::after { background: var(--color-blue); border-color: var(--color-blue); } + +/* CUSTOMIZE MENU */ +.customize-menu-container { + background: var(--color-white); +} + +.customize-menu-container a { + background: var(--color-blue); + color: var(--color-white); +} + +/* FORMS */ +.form-radio h3, +.form-checkbox h3 { + background: var(--color-blue); + color: var(--color-white); + border-bottom: 1px solid var(--color-white); +} diff --git a/assets/svg/starburst-red.svg b/assets/svg/starburst-red.svg new file mode 100644 index 0000000..aa4b907 --- /dev/null +++ b/assets/svg/starburst-red.svg @@ -0,0 +1,12 @@ + + + + +