Diff -- /var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/TEMPLATES/store_layouts/spotlight.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/affiliate.3dshawn.com/TEMPLATES/store_layouts/spotlight.html

added on local at 2026-07-01 13:47:54

Added
+244
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 797bd773db4f
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1<!-- =====================================================================
2 LAYOUT: Single Spotlight
3 One huge featured product up top, smaller catalog strip below.
4 Best for sellers with a flagship, weekly drops, or pre-orders.
5===================================================================== -->
6
7<style>:root { $theme_css_vars }</style>
8
9[if:$preview_banner]
10<div style="position:sticky;top:0;z-index:9999;background:#0a0e1c;border-bottom:1px solid rgba(59,130,246,0.40);box-shadow:0 4px 16px rgba(0,0,0,0.55);padding:10px 20px;text-align:center;font-size:13px;color:#93c5fd;font-weight:600">
11 <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align:-2px"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="3"/></svg>
12 $preview_banner
13</div>
14[/if]
15
16<header style="border-bottom:1px solid var(--col-border);padding:14px 24px;display:flex;align-items:center;gap:14px;background:var(--col-bg);flex-wrap:wrap">
17 <a href="/store.cgi?id=$store_id" style="display:flex;align-items:center;gap:10px;text-decoration:none;flex-shrink:0">
18 <div class="brand-mark" style="background:linear-gradient(130deg, var(--col-accent), var(--col-accent-bright));width:34px;height:34px;font-size:13px">$store_initials</div>
19 <span style="font-family:var(--font-display);font-size:18px;font-weight:700;color:var(--col-text)">$store_name</span>
20 </a>
21 <div style="flex:1;display:flex;justify-content:center;min-width:0">$store_search_form</div>
22 <nav style="margin-left:auto;display:flex;gap:6px;align-items:center;flex-wrap:wrap">
23 [if:$has_nav_pages]
24 [loop:@nav_pages]
25 <a href="$loop1.href" class="btn btn-ghost btn-sm">$loop1.title</a>
26 [/loop]
27 [/if]
28 <a href="/store.cgi?id=$store_id#shop" class="btn btn-ghost btn-sm">All designs</a>
29 <a href="$cart_href" class="btn btn-primary btn-sm" style="position:relative" id="we-cart-link">
30 $header_cart_label
31 [if:$has_cart_items]<span class="we-cart-badge" style="margin-left:6px;display:inline-block;min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:#fff;color:var(--col-accent);font-size:11px;font-weight:800;line-height:18px">$cart_count</span>[/if]
32 </a>
33 </nav>
34 <div style="display:inline-flex;gap:8px;align-items:center;margin-left:8px">$store_signin_link $store_cart_link</div>
35</header>
36
37[if:$is_specific_page]
38 [if:$page_not_found]
39 <section style="padding:120px 32px;text-align:center;max-width:600px;margin:0 auto">
40 <h1 class="hero-title" style="font-size:48px">Page not found</h1>
41 <a href="/store.cgi?id=$store_id" class="btn btn-primary btn-lg">Back to home</a>
42 </section>
43 [/if]
44 [if:!$page_not_found]
45 <section style="padding:80px 32px [if:$is_collection_page]20px[/if][if:!$is_collection_page]60px[/if];max-width:[if:$is_collection_page]1400px[/if][if:!$is_collection_page]900px[/if];margin:0 auto">
46 <h1 class="hero-title" style="font-size:48px">$page_title</h1>
47 <div class="text-secondary" style="font-size:17px;line-height:1.7;margin-top:24px;white-space:pre-wrap">$page_body</div>
48 </section>
49
50 [if:$is_collection_page]
51 <section id="shop" style="padding:20px 32px 80px;max-width:1400px;margin:0 auto">
52 [if:$has_products]
53 <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:16px">
54 [loop:@products]
55 <div class="we-tile" data-we-listing-id="$loop1.id" style="background:var(--col-surface-1);border:1px solid var(--col-border);border-radius:10px;overflow:hidden;transition:transform 0.15s,border-color 0.15s;position:relative">
56 <div style="aspect-ratio:1;background:url('$loop1.hero_image') $loop1.hero_image_pos/cover"></div>
57 <div style="padding:14px">
58 <div style="font-size:14px;font-weight:600;color:var(--col-text);margin-bottom:6px">$loop1.title</div>
59 <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">
60 <span style="font-size:15px;font-weight:700;color:var(--col-accent-bright)">$loop1.price</span>
61 <span style="font-size:11px;color:var(--col-text-3)">$loop1.rating_n</span>
62 </div>
63 <button type="button" class="btn btn-primary btn-sm we-add-to-cart" data-mid="$loop1.id" data-sid="$store_id" style="width:100%">Add to cart</button>
64 </div>
65 [if:$is_editor_owner]
66 <button type="button" class="we-feature-btn" data-we-feature-id="$loop1.id" title="Make this the featured product">&#9733; Feature</button>
67 [/if]
68 </div>
69 [/loop]
70 </div>
71 [/if]
72 [if:!$has_products]
73 <div class="card" style="text-align:center;padding:60px 24px;color:var(--col-text-2)">
74 Nothing to show yet. Designs added on the Models page will appear here.
75 </div>
76 [/if]
77 $pagination_html
78 </section>
79 [/if]
80 [/if]
81[/if]
82
83[if:!$is_specific_page]
84<!-- Hero spotlight: ONE huge featured product. featured_product is set
85 in store.cgi to the first product in the catalog (or empty when
86 there are no products). Kept outside any iteration because the
87 template engine cannot run conditionals inside iterations. -->
88[if:$has_featured]
89<section $featured_image_attrs style="position:relative;min-height:80vh;background:url('$featured_product.hero_image') $featured_product.hero_image_pos/cover;display:flex;align-items:flex-end;border-bottom:1px solid var(--col-border)">
90 <div style="position:absolute;inset:0;background:linear-gradient(0deg, var(--col-bg) 0%, rgba(0,0,0,0) 60%);pointer-events:none"></div>
91 <div style="position:relative;z-index:2;padding:60px 48px;max-width:900px">
92 <span style="display:inline-flex;align-items:center;gap:8px;background:var(--col-accent);color:#fff;padding:6px 14px;border-radius:999px;font-size:11px;letter-spacing:2px;text-transform:uppercase;font-weight:700">
93 &#9733; $featured_badge_label
94 </span>
95 <h1 style="font-family:var(--font-display);font-size:clamp(48px,7vw,96px);font-weight:800;letter-spacing:-0.03em;line-height:0.95;color:var(--col-text);margin:18px 0 16px">$featured_product.title</h1>
96 <p style="font-size:20px;color:var(--col-text-2);max-width:600px;line-height:1.5">$store_tagline</p>
97 <div style="display:flex;gap:14px;align-items:center;margin-top:32px;flex-wrap:wrap">
98 <span style="font-size:36px;font-weight:800;color:var(--col-accent-bright)">$featured_product.price</span>
99 <button type="button" class="btn btn-primary btn-lg we-add-to-cart" data-mid="$featured_product.id" data-sid="$store_id">$cta_primary_label</button>
100 <a href="#shop" class="btn btn-secondary btn-lg">$cta_secondary_label</a>
101 </div>
102 </div>
103</section>
104[/if]
105
106[if:!$has_featured]
107<section style="min-height:50vh;display:flex;align-items:center;justify-content:center;background:var(--col-bg-2);border-bottom:1px solid var(--col-border);padding:80px 48px;text-align:center">
108 <div style="max-width:600px">
109 <h1 style="font-family:var(--font-display);font-size:clamp(40px,5vw,64px);font-weight:800;color:var(--col-text);margin:0 0 16px">$store_name</h1>
110 <p style="font-size:18px;color:var(--col-text-2);line-height:1.6">$store_tagline</p>
111 <p class="text-dim" style="margin-top:32px;font-size:14px">The featured release will appear here once designs are added.</p>
112 </div>
113</section>
114[/if]
115
116<!-- Product strip -- small, dense grid of remaining products -->
117<section id="shop" style="padding:60px 32px 80px;max-width:1400px;margin:0 auto">
118 <div style="display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:32px">
119 <h2 style="font-family:var(--font-display);font-size:28px;color:var(--col-text);margin:0">$section_heading</h2>
120 <span style="color:var(--col-text-3);font-size:13px">$product_count designs total</span>
121 </div>
122
123 [if:$has_secondary]
124 <div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px">
125 [loop:@secondary_products]
126 <div class="we-tile" data-we-listing-id="$loop1.id" style="background:var(--col-surface-1);border:1px solid var(--col-border);border-radius:8px;overflow:hidden;transition:transform 0.15s,border-color 0.15s;position:relative">
127 <div style="aspect-ratio:1;background:url('$loop1.hero_image') $loop1.hero_image_pos/cover"></div>
128 <div style="padding:12px">
129 <div style="font-size:13px;font-weight:600;color:var(--col-text);margin-bottom:6px">$loop1.title</div>
130 <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px">
131 <span style="font-size:14px;font-weight:700;color:var(--col-accent-bright)">$loop1.price</span>
132 <span style="font-size:11px;color:var(--col-text-3)">$loop1.rating_n</span>
133 </div>
134 <button type="button" class="btn btn-primary btn-sm we-add-to-cart" data-mid="$loop1.id" data-sid="$store_id" style="width:100%">Add to cart</button>
135 </div>
136 [if:$is_editor_owner]
137 <button type="button" class="we-feature-btn" data-we-feature-id="$loop1.id" title="Make this the featured product">&#9733; Feature</button>
138 [/if]
139 </div>
140 [/loop]
141 </div>
142 [/if]
143
144 [if:!$has_secondary]
145 <div class="card" style="text-align:center;padding:48px 24px">
146 <div style="color:var(--col-text-2)">No additional designs yet.</div>
147 </div>
148 [/if]
149</section>
150[/if]
151
152[if:$has_marketplace_links]
153<section style="background:var(--col-bg-2);border-top:1px solid var(--col-border);padding:36px 32px;text-align:center">
154 <div style="font-size:11px;letter-spacing:1.5px;text-transform:uppercase;color:var(--col-text-3);font-weight:700;margin-bottom:14px">Also find $store_name on</div>
155 <div style="display:flex;justify-content:center;gap:10px;flex-wrap:wrap">
156 [loop:@marketplace_links]
157 <a href="$loop1.href" target="_blank" rel="noopener" class="btn btn-secondary btn-sm" style="display:inline-flex;align-items:center;gap:8px">
158 <span style="display:inline-grid;place-items:center;width:22px;height:22px;border-radius:5px;background:linear-gradient(130deg,var(--col-accent),var(--col-accent-bright));color:#fff;font-size:11px;font-weight:700">$loop1.icon</span>
159 $loop1.name
160 </a>
161 [/loop]
162 </div>
163</section>
164[/if]
165
166<footer style="background:var(--col-bg-2);border-top:1px solid var(--col-border);padding:30px 32px;text-align:center">
167 <div class="text-xs text-dim" style="letter-spacing:1.5px;text-transform:uppercase">$store_name &middot; $footer_byline</div>
168</footer>
169
170<script>
171/* Add-to-cart for any element with .we-add-to-cart + data-mid + data-sid.
172 POSTs to /cart_add.cgi, updates the header cart badge, and flashes
173 the button to "Added to cart" briefly so the buyer sees feedback. */
174(function() {
175 document.addEventListener('click', function(e) {
176 var btn = e.target.closest('.we-add-to-cart');
177 if (!btn) return;
178 e.preventDefault();
179 var mid = btn.getAttribute('data-mid');
180 var sid = btn.getAttribute('data-sid');
181 if (!mid || !sid) return;
182 var originalText = btn.textContent;
183 btn.disabled = true;
184 btn.textContent = 'Adding...';
185 var fd = new FormData();
186 fd.append('model_id', mid);
187 fd.append('storefront_id', sid);
188 fetch('/cart_add.cgi', { method: 'POST', body: fd, credentials: 'same-origin' })
189 .then(function(r){
190 return r.text().then(function(body){
191 try { return JSON.parse(body); }
192 catch (e) {
193 var snippet = body ? body.replace(/<[^>]*>/g,' ').replace(/\s+/g,' ').trim().slice(0, 200) : '(empty body)';
194 throw new Error('server returned ' + r.status + ' ' + r.statusText + ' (' + snippet + ')');
195 }
196 });
197 })
198 .then(function(data){
199 if (!data || !data.success) throw new Error(data && data.error || 'add failed');
200 btn.textContent = 'Added ✓';
201 /* Update header badge in place. */
202 var link = document.getElementById('we-cart-link');
203 if (link) {
204 var badge = link.querySelector('.we-cart-badge');
205 if (badge) {
206 badge.textContent = data.count;
207 } else {
208 badge = document.createElement('span');
209 badge.className = 'we-cart-badge';
210 badge.style.cssText = 'margin-left:6px;display:inline-block;min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:#fff;color:var(--col-accent);font-size:11px;font-weight:800;line-height:18px';
211 badge.textContent = data.count;
212 link.appendChild(badge);
213 }
214 }
215 setTimeout(function(){ btn.disabled = false; btn.textContent = originalText; }, 1500);
216 })
217 .catch(function(err){
218 btn.disabled = false;
219 btn.textContent = originalText;
220 appToast({ message: 'Add to cart failed: ' + err.message, type: 'error' });
221 });
222 });
223})();
224
225// Make product cards clickable. Spotlight uses <div class="we-tile">
226// rather than <a> wrappers (because of the inline Add-to-Cart and
227// Feature buttons), so we add a click handler that navigates to the
228// listing detail page -- except when the click was on one of the
229// inner buttons (which have their own handlers).
230(function(){
231 document.addEventListener('click', function(e){
232 if (e.target.closest('button, a, input, textarea, select')) return;
233 var tile = e.target.closest('[data-we-listing-id]');
234 if (!tile) return;
235 var id = tile.getAttribute('data-we-listing-id');
236 if (!id) return;
237 window.location.href = '/listing_details.cgi?id=' + encodeURIComponent(id);
238 });
239 // Cursor affordance.
240 document.querySelectorAll('[data-we-listing-id]').forEach(function(t){
241 t.style.cursor = 'pointer';
242 });
243})();
244</script>