From bae4b557ae3d6d02628426c7d14b80e03f6dd931 Mon Sep 17 00:00:00 2001 From: jzzliu Date: Sat, 7 Nov 2026 20:13:33 -0700 Subject: [PATCH] Update Site source --- .openai/hosting.json | 1 + dist/blanket.svg | 3 ++ dist/bottle.svg | 3 ++ dist/cap.svg | 3 ++ dist/index.html | 27 ++++++++++++ dist/landscape.svg | 11 +++++ dist/lantern.svg | 3 ++ dist/mug.svg | 3 ++ dist/pack.svg | 3 ++ dist/shop.js | 100 +++++++++++++++++++++++++++++++++++++++++++ dist/style.css | 1 + 11 files changed, 158 insertions(+) create mode 100644 .openai/hosting.json create mode 100644 dist/blanket.svg create mode 100644 dist/bottle.svg create mode 100644 dist/cap.svg create mode 100644 dist/index.html create mode 100644 dist/landscape.svg create mode 100644 dist/lantern.svg create mode 100644 dist/mug.svg create mode 100644 dist/pack.svg create mode 100644 dist/shop.js create mode 100644 dist/style.css diff --git a/.openai/hosting.json b/.openai/hosting.json new file mode 100644 index 0000000..24dc15c --- /dev/null +++ b/.openai/hosting.json @@ -0,0 +1 @@ +{"project_id":"appgprj_6aefe80c1e848191a6ff4b0420d61c4e","static":{"directory":"dist"}} diff --git a/dist/blanket.svg b/dist/blanket.svg new file mode 100644 index 0000000..881fe05 --- /dev/null +++ b/dist/blanket.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dist/bottle.svg b/dist/bottle.svg new file mode 100644 index 0000000..7b6c495 --- /dev/null +++ b/dist/bottle.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dist/cap.svg b/dist/cap.svg new file mode 100644 index 0000000..f3aef9a --- /dev/null +++ b/dist/cap.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dist/index.html b/dist/index.html new file mode 100644 index 0000000..6d1e588 --- /dev/null +++ b/dist/index.html @@ -0,0 +1,27 @@ + + + + + +Fieldwork Supply — Equipment for getting out + + + +
FIELDWORK SUPPLY   /   A FICTIONAL STOREFRONT
+
Fieldwork.
+
+
+

THE TRAIL COLLECTION / 01

Better
outside.

Thoughtfully designed gear for slow mornings, long trails, and weekends out of range.

Explore the collection
+
Illustrated mountain range and pine forest at sunsetFIG. 01   /   ABOVE THE TREELINE
+
+

01 / THE SHOP

Trail essentials

Pack light. Make it count.

+
+

+

02 / THE FIELD NOTES

Good gear leaves room for the good stuff.

Fieldwork is an imagined gear shop built around a simple packing list. Six essentials, each with a clear job, for getting out the door and into the day.

Back to the collection ↑
+
+ +

FIELDWORK / EQUIPMENT

+

Your bag

+
+ + diff --git a/dist/landscape.svg b/dist/landscape.svg new file mode 100644 index 0000000..9c9123c --- /dev/null +++ b/dist/landscape.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/dist/lantern.svg b/dist/lantern.svg new file mode 100644 index 0000000..e9b1427 --- /dev/null +++ b/dist/lantern.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dist/mug.svg b/dist/mug.svg new file mode 100644 index 0000000..e20f5b7 --- /dev/null +++ b/dist/mug.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dist/pack.svg b/dist/pack.svg new file mode 100644 index 0000000..f12ebda --- /dev/null +++ b/dist/pack.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/dist/shop.js b/dist/shop.js new file mode 100644 index 0000000..6f9933e --- /dev/null +++ b/dist/shop.js @@ -0,0 +1,100 @@ +"use strict"; +const catalog = [ + {id:"pack",name:"Ridgeline Pack",category:"Carry",price:86,detail:"A compact daypack with a roll-top closure and an easy-access front pocket."}, + {id:"mug",name:"Camp Enamel Mug",category:"Camp",price:24,detail:"An enamel-coated camp mug with a generous handle and a dark rolled rim."}, + {id:"cap",name:"Switchback Cap",category:"Wear",price:32,detail:"A soft five-panel cap with an adjustable back for sunny walks and early starts."}, + {id:"bottle",name:"Alpine Flask",category:"Carry",price:38,detail:"A narrow insulated flask with a screw-top lid and a carry loop."}, + {id:"lantern",name:"Afterglow Lantern",category:"Camp",price:54,detail:"A compact lantern with a warm diffuser and a folding carry handle."}, + {id:"blanket",name:"Meadow Blanket",category:"Camp",price:68,detail:"A striped camp blanket that rolls down neatly for a picnic or a cool evening."} +]; +const byId = id => document.getElementById(id); +const money = value => new Intl.NumberFormat("en-US",{style:"currency",currency:"USD",maximumFractionDigits:0}).format(value); +const product = id => catalog.find(item => item.id === id); +const art = item => '' + item.name + ' product illustration'; +const storageKey = "fieldwork-bag-v1"; +let bag = {}; +try { + const stored = JSON.parse(localStorage.getItem(storageKey)) || {}; + for (const {id} of catalog) { + if (Number.isSafeInteger(stored[id]) && stored[id] > 0) bag[id] = stored[id]; + } +} catch {} +let filter = "All"; +let toastTimer; +function renderProducts() { + const items = catalog.filter(item => filter === "All" || item.category === filter); + const order = byId("sort").value; + if (order !== "featured") items.sort((a,b) => order === "low" ? a.price-b.price : b.price-a.price); + byId("products").innerHTML = items.map(item => `
+ +

${item.category}

${item.name}

${money(item.price)}

+
`).join(""); + byId("results").textContent = `${items.length} products shown`; +} +function renderCart() { + const items = catalog.filter(item => bag[item.id]); + byId("count").textContent = items.reduce((sum,item) => sum + bag[item.id],0); + byId("cart-items").innerHTML = items.map(item => `
${art(item)} +
${item.name}

${money(item.price * bag[item.id])}

+
+ ${bag[item.id]}
`).join("") || "

Your bag is empty.

"; + byId("subtotal").textContent = money(items.reduce((sum,item) => sum + item.price * bag[item.id],0)); + byId("cart-summary").hidden = !items.length; +} +function updateBag(id, amount) { + bag[id] = (bag[id] || 0) + amount; + if (bag[id] <= 0) delete bag[id]; + try {localStorage.setItem(storageKey,JSON.stringify(bag));} catch {} + renderCart(); +} +function notify(message) { + byId("toast").textContent = message; + clearTimeout(toastTimer); + toastTimer = setTimeout(() => byId("toast").textContent = "",2400); +} +byId("filters").innerHTML = ["All",...new Set(catalog.map(item => item.category))] + .map(category => ``).join(""); +byId("filters").addEventListener("click",event => { + const button = event.target.closest("[data-category]"); + if (!button) return; + filter = button.dataset.category; + for (const option of byId("filters").children) option.setAttribute("aria-pressed", option === button); + renderProducts(); +}); +byId("sort").addEventListener("change",renderProducts); +byId("bag").addEventListener("click",() => { + byId("order").hidden = true; + byId("cart-items").hidden = false; + byId("cart").showModal(); +}); +document.addEventListener("click",event => { + const button = event.target.closest("button"); + if (!button) return; + const {add,detail,adjust,step} = button.dataset; + if (add) { + updateBag(add,1); + if (byId("product-dialog").open) byId("product-dialog").close(); + notify(`${product(add).name} added to your bag`); + } + if (detail) { + const item = product(detail); + byId("product-detail").innerHTML = `${art(item)}

${item.name}

${item.detail}

+ `; + byId("product-dialog").showModal(); + } + if (adjust) { + updateBag(adjust,Number(step)); + (byId("cart-items").querySelector(`[data-adjust="${adjust}"][data-step="${step}"]`) || byId("cart").querySelector(".close")).focus(); + } +}); +byId("checkout").addEventListener("click",() => { + for (const id of Object.keys(bag)) delete bag[id]; + try {localStorage.removeItem(storageKey);} catch {} + renderCart(); + byId("cart-items").hidden = true; + byId("order").textContent = "Demo order placed. Thanks for exploring Fieldwork."; + byId("order").hidden = false; + byId("cart").querySelector(".close").focus(); +}); +renderProducts(); +renderCart(); diff --git a/dist/style.css b/dist/style.css new file mode 100644 index 0000000..1ad7e40 --- /dev/null +++ b/dist/style.css @@ -0,0 +1 @@ +:root{--paper:#f7f5ed;--ink:#1d2924;--forest:#20392d;--lime:#e2f596;--line:#d8dbce;--muted:#50594e;--mono:ui-monospace,monospace}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);color:var(--ink);font-family:system-ui,sans-serif}button,select{font:inherit;color:inherit}button,a,select{touch-action:manipulation}button{cursor:pointer}a{color:inherit;text-decoration:none}a:focus-visible,button:focus-visible,select:focus-visible{outline:3px solid #527e49;outline-offset:4px}p,h1,h2,h3{margin:0}.notice{text-align:center;padding:.62rem;background:var(--lime);font:700 .67rem var(--mono);letter-spacing:.12em}.top,main,footer{width:min(1320px,calc(100% - 8vw));margin:auto}.top{height:78px;display:flex;align-items:center;justify-content:space-between;gap:1rem}.wordmark{font-size:2rem;font-weight:850;letter-spacing:-.085em}.wordmark span{color:#53794b}.top nav{display:flex;gap:2rem;font-size:.92rem}.top nav a:hover,footer a:hover{text-decoration:underline}.bag,.close{border:1px solid var(--line);background:transparent;border-radius:30px;padding:.5rem .85rem}.bag span{display:inline-grid;place-items:center;background:var(--forest);color:white;border-radius:50%;width:1.4rem;height:1.4rem;font-size:.75rem;margin-left:.35rem}.hero{display:grid;grid-template-columns:43% 57%;min-height:520px;background:var(--forest);color:#fbfaf0}.hero-copy{padding:clamp(2rem,5.4vw,6rem);display:flex;align-items:flex-start;justify-content:center;flex-direction:column;gap:1.3rem}.eyebrow{font:700 .72rem var(--mono);letter-spacing:.12em}.hero .eyebrow{color:var(--lime)}.eyebrow i{display:inline-block;width:.55rem;height:.55rem;border-radius:50%;background:currentColor;margin-right:.5rem}.hero h1{font-size:clamp(4rem,8.4vw,8.8rem);line-height:.79;letter-spacing:-.085em}.hero h1 span{color:var(--lime)}.hero-copy>p:not(.eyebrow){color:#e1e6d9;max-width:29ch;line-height:1.5}.primary{display:inline-flex;align-items:center;justify-content:space-between;gap:1rem;background:var(--lime);color:var(--ink);border:0;padding:.9rem 1.15rem;font-weight:750}.primary:hover{background:#d3ea78}.hero-art{position:relative;min-height:100%;overflow:hidden}.hero-art img{display:block;width:100%;height:100%;object-fit:cover;position:absolute}.image-label{position:absolute;bottom:1rem;right:1rem;background:#192c24;color:#fff;padding:.55rem .75rem;font:.66rem var(--mono);letter-spacing:.07em}.shop{padding:4.5rem 0}.shop-heading{display:flex;align-items:end;justify-content:space-between;gap:1rem;margin-bottom:1.6rem}.shop h2,.story h2{font-size:clamp(2.6rem,5vw,5rem);line-height:.95;letter-spacing:-.07em;margin-top:.55rem}.shop-heading>p{color:var(--muted)}.controls{display:flex;justify-content:space-between;align-items:center;gap:.8rem;flex-wrap:wrap;border-block:1px solid var(--line);padding:.85rem 0;margin-bottom:1.2rem}.controls label{display:flex;gap:.5rem;align-items:center;font-size:.85rem}.controls select{border:1px solid var(--line);background:transparent;padding:.45rem}.controls button{border:1px solid var(--line);background:transparent;border-radius:24px;padding:.45rem .85rem;margin:.15rem .3rem .15rem 0;font-size:.83rem}.controls button[aria-pressed=true]{background:var(--forest);color:white;border-color:var(--forest)}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1.8rem 1rem}.product{min-width:0}.product-image{display:block;width:100%;padding:0;border:0;background:transparent}.product-image img,#product-detail img,.cart-row img{display:block;width:100%;height:auto}.product-image img{transition:filter .2s}.product-image:hover img{filter:brightness(.94)}.product-info{display:grid;grid-template-columns:1fr auto;align-items:end;gap:.45rem;padding:.85rem 0}.product h3{font-size:clamp(1rem,2vw,1.3rem);letter-spacing:-.035em}.product .eyebrow{font-size:.65rem;color:var(--muted);margin-bottom:.35rem}.add{background:transparent;border:1px solid var(--line);width:2.6rem;height:2.6rem;font-size:1.3rem}.add:hover{background:var(--lime)}.price{font:700 .83rem var(--mono);margin-top:.3rem}.story{background:#e4e7d9;padding:clamp(2rem,6vw,6rem)}.story h2{max-width:15ch}.story>p:not(.eyebrow){max-width:53ch;line-height:1.65;margin:1.25rem 0}.story a,footer>a:last-child{text-decoration:underline;text-underline-offset:4px}footer{display:flex;align-items:center;justify-content:space-between;gap:1rem;padding:2.5rem 0;font-size:.8rem}dialog{background:var(--paper);color:var(--ink);border:1px solid var(--line);max-width:min(520px,calc(100% - 2rem));width:100%;max-height:90dvh;padding:1.3rem;overflow:auto}dialog::backdrop{background:#101b16aa}#cart{margin:0 0 0 auto;max-height:100dvh;height:100dvh;max-width:min(470px,100%);border:0}.dialog-head,.subtotal{display:flex;align-items:center;justify-content:space-between;gap:1rem;margin-bottom:1rem}.close{font-size:1.35rem;line-height:1}.cart-row{display:grid;grid-template-columns:75px 1fr auto;align-items:center;gap:.8rem;padding:.75rem 0;border-bottom:1px solid var(--line)}.qty{display:flex;align-items:center;gap:.4rem}.qty button{background:transparent;border:1px solid var(--line);width:1.8rem;height:1.8rem}.subtotal{margin-top:1rem}.fine{font-size:.78rem;color:var(--muted);margin-top:.8rem}#product-detail h2{margin-top:1rem}#product-detail>p{margin:.65rem 0 1rem;line-height:1.5}#toast{position:fixed;right:1rem;bottom:1rem;background:var(--forest);color:white;padding:.8rem 1rem;z-index:3}#toast:empty{display:none}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}[hidden]{display:none!important}@media(max-width:760px){.hero{grid-template-columns:1fr;min-height:0}.hero-art{min-height:310px}.hero h1{font-size:clamp(4.2rem,14vw,6.5rem)}.grid{grid-template-columns:repeat(2,minmax(0,1fr))}.shop{padding:3rem 0}.top nav{gap:.75rem}.top{height:65px}}@media(max-width:420px){.top nav a:last-child{display:none}.shop-heading>p{display:none}.product-info{gap:.2rem}footer{flex-wrap:wrap}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;transition:none!important}}