Diff -- /var/www/vhosts/webstls.com/httpdocs/TEMPLATES/webstls_categories.html
Diff

/var/www/vhosts/webstls.com/httpdocs/TEMPLATES/webstls_categories.html

added on WebSTLs (webstls.com) at 2026-07-01 22:26:58

Added
+550
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to aa4079c679eb
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1<!-- Category manager. Backed by either /categories.cgi (per-seller list)
2 or /admin_categories.cgi (admin default list new sellers receive
3 a copy of). $form_action + page header tvars switch between the
4 two. -->
5
6<div class="page-head">
7 <div>
8 <span class="page-eyebrow"><span class="dot"></span> $page_eyebrow</span>
9 <h1 class="page-title">$page_title</h1>
10 <p class="page-subtitle">$page_subtitle</p>
11 </div>
12 <div class="page-actions">
13 <button type="button" class="btn btn-primary" id="catOpenNew">
14 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
15 New category
16 </button>
17 </div>
18</div>
19
20[if:$has_flash]
21<div class="banner $flash_kind mb-3">
22 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/></svg>
23 <div class="text-sm fw-600">$flash_msg</div>
24</div>
25[/if]
26
27<style>
28 /* Compact card: 3 rows -- full-width color banner with the category
29 name, then description, then slug + action buttons on the bottom
30 row floating right. The banner reads as a header strip so the
31 card has a clear visual hierarchy at a glance. */
32 .cat-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(240px, 1fr)); gap:10px; }
33 .cat-card { padding:0; border:1px solid var(--col-border); border-radius:10px; background:var(--col-surface-1); display:flex; flex-direction:column; overflow:hidden; }
34 /* Banner stretches full card width. Rounded only on top because
35 the card itself clips the corners (`overflow:hidden`). */
36 .cat-banner { display:flex; align-items:center; gap:6px; padding:8px 12px; font-size:13px; font-weight:700; color:#fff; min-width:0; }
37 .cat-banner-name { min-width:0; flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
38 /* Emoji renders larger than the surrounding letters; a -1px vertical
39 nudge centers it visually against the smaller glyphs. */
40 .cat-banner-emoji { font-size:16px; line-height:1; display:inline-block; transform:translateY(-1px); flex-shrink:0; }
41 .cat-body { padding:8px 12px 10px; display:flex; flex-direction:column; gap:6px; }
42 .cat-desc { font-size:12px; color:var(--col-text-2); line-height:1.4; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; min-height:1.4em; }
43 .cat-foot { display:flex; align-items:center; justify-content:space-between; gap:8px; }
44 .cat-meta { font-size:10px; color:var(--col-text-3); letter-spacing:0.5px; text-transform:uppercase; display:flex; gap:10px; align-items:center; min-width:0; overflow:hidden; }
45 .cat-actions { display:flex; gap:4px; flex-shrink:0; }
46 .cat-actions .btn { padding:3px 9px; font-size:11px; }
47 .cat-empty { padding:60px 24px; text-align:center; border:1px dashed var(--col-border-2); border-radius:14px; color:var(--col-text-2); }
48
49 /* Modal */
50 .cat-modal { position:fixed; inset:0; background:rgba(8,11,24,0.78); display:none; align-items:center; justify-content:center; z-index:9000; padding:20px; }
51 .cat-modal.is-open { display:flex; }
52 .cat-modal-card { background:var(--col-surface-1); border:1px solid var(--col-border-2); border-radius:14px; padding:24px 28px; width:min(520px, 100%); max-height:90vh; overflow-y:auto; }
53 .cat-modal h2 { font-family:var(--font-display,inherit); font-size:22px; margin:0 0 6px; color:#fff; }
54 .cat-modal .helper { font-size:13px; color:var(--col-text-3); margin:0 0 18px; }
55 .cat-color-grid { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
56 .cat-color-grid input[type=radio] { display:none; }
57 .cat-color-grid label { width:28px; height:28px; border-radius:50%; border:2px solid transparent; cursor:pointer; transition:transform .12s; }
58 .cat-color-grid input:checked + label { border-color:#fff; transform:scale(1.15); }
59 .cat-color-custom-wrap.is-active { border-style:solid !important; border-color:#fff !important; transform:scale(1.15); }
60
61 /* Emoji quick-pick grid. ~100 buttons, scrolls vertically so the
62 modal stays compact. Custom thin scrollbar so it doesn't stand
63 out against the modal surface. */
64 .cat-emoji-picker { display:flex; flex-wrap:wrap; gap:4px; margin-top:6px; padding:6px; background:var(--col-surface-2); border:1px solid var(--col-border); border-radius:8px; max-height:148px; overflow-y:auto; scrollbar-width:thin; scrollbar-color:var(--col-border-2) transparent; }
65 .cat-emoji-picker::-webkit-scrollbar { width:8px; }
66 .cat-emoji-picker::-webkit-scrollbar-thumb { background:var(--col-border-2); border-radius:4px; }
67 .cat-emoji-picker::-webkit-scrollbar-track { background:transparent; }
68 .cat-emoji-pick { width:32px; height:32px; padding:0; border:1px solid var(--col-border); background:var(--col-surface-1); border-radius:6px; font-size:18px; line-height:1; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; transition:background .12s,border-color .12s,transform .12s; color:var(--col-text); flex:0 0 auto; }
69 .cat-emoji-pick:hover { background:var(--grad-brand-soft); border-color:var(--col-accent); transform:scale(1.08); }
70 .cat-emoji-pick[data-clear="1"] { color:var(--col-text-3); font-size:14px; }
71</style>
72
73[if:!$has_cats]
74<div class="cat-empty">
75 <div style="font-size:48px;margin-bottom:8px">+</div>
76 <h2 style="color:#fff;font-family:var(--font-display,inherit);margin-bottom:8px">No categories yet</h2>
77 <p>Categories let you group listings on your storefront. Try <strong>"Halloween 2026"</strong>, <strong>"Patreon exclusive"</strong>, <strong>"Tabletop"</strong> &mdash; whatever organization your buyers will look for.</p>
78 <button type="button" class="btn btn-primary" id="catOpenNewEmpty" style="margin-top:14px">Create your first category</button>
79</div>
80[/if]
81
82[if:$has_cats]
83<div class="cat-grid">
84 [loop:@cats]
85 <div class="cat-card">
86 <div class="cat-banner" style="background:$loop1.color">
87 [if:$loop1.icon]<span class="cat-banner-emoji">$loop1.icon</span>[/if]
88 <span class="cat-banner-name">$loop1.name</span>
89 </div>
90 <div class="cat-body">
91 <div class="cat-desc">$loop1.description</div>
92 <div class="cat-foot">
93 <div class="cat-meta">
94 <span>/$loop1.slug</span>
95 [if:$show_counts]<span>$loop1.model_count listing(s)</span>[/if]
96 </div>
97 <div class="cat-actions">
98 <button type="button" class="btn btn-secondary btn-sm cat-edit"
99 data-id="$loop1.id" data-name="$loop1.name" data-desc="$loop1.description"
100 data-color="$loop1.color" data-icon="$loop1.icon" data-sort="$loop1.sort_order"
101 data-public="$loop1.is_public">Edit</button>
102 <form method="POST" action="$form_action" style="display:inline"
103 data-confirm-title="Delete this category?"
104 data-confirm-message="Removing the category does not delete any listings. Tags pointing at it will simply drop from those listings."
105 data-confirm-label="Delete"
106 data-confirm-style="danger">
107 <input type="hidden" name="_act" value="delete">
108 <input type="hidden" name="id" value="$loop1.id">
109 <button type="submit" class="btn btn-danger btn-sm">Delete</button>
110 </form>
111 </div>
112 </div>
113 </div>
114 </div>
115 [/loop]
116</div>
117[/if]
118
119<!-- Create / edit modal -->
120<div class="cat-modal" id="catModal">
121 <div class="cat-modal-card">
122 <h2 id="catModalTitle">New category</h2>
123 <p class="helper">Pick a chip color and an optional emoji. Both render on your storefront filter bar.</p>
124 <form method="POST" action="$form_action" id="catForm">
125 <input type="hidden" name="_act" id="catAct" value="create">
126 <input type="hidden" name="id" id="catId" value="">
127
128 <div class="form-group">
129 <label class="form-label">Name <span class="req">*</span></label>
130 <input type="text" name="name" id="catName" class="input" maxlength="120" required placeholder="e.g. Halloween 2026">
131 </div>
132
133 <div class="form-group">
134 <label class="form-label">Description <span class="text-xs text-dim">(optional)</span></label>
135 <input type="text" name="description" id="catDesc" class="input" maxlength="255" placeholder="One-line description for the chip tooltip">
136 </div>
137
138 <div class="form-group">
139 <label class="form-label">Chip color</label>
140 <div class="cat-color-grid" id="catColors">
141 <input type="radio" name="color_swatch" id="cc1" value="#6d28d9"><label for="cc1" style="background:#6d28d9"></label>
142 <input type="radio" name="color_swatch" id="cc2" value="#1d4ed8"><label for="cc2" style="background:#1d4ed8"></label>
143 <input type="radio" name="color_swatch" id="cc3" value="#047857"><label for="cc3" style="background:#047857"></label>
144 <input type="radio" name="color_swatch" id="cc4" value="#b45309"><label for="cc4" style="background:#b45309"></label>
145 <input type="radio" name="color_swatch" id="cc5" value="#b91c1c"><label for="cc5" style="background:#b91c1c"></label>
146 <input type="radio" name="color_swatch" id="cc6" value="#be185d"><label for="cc6" style="background:#be185d"></label>
147 <input type="radio" name="color_swatch" id="cc7" value="#0e7490"><label for="cc7" style="background:#0e7490"></label>
148 <input type="radio" name="color_swatch" id="cc8" value="#334155"><label for="cc8" style="background:#334155"></label>
149 <!-- Custom color: the rainbow tile is visible, the native
150 color input sits transparently on top so the click hits
151 the actual input (label-for tricks don't reliably open
152 native color pickers in Chrome). -->
153 <div class="cat-color-custom-wrap" title="Pick a custom color"
154 style="position:relative;width:28px;height:28px;border-radius:50%;border:2px dashed var(--col-border-2);overflow:hidden;background:conic-gradient(from 0deg,#b91c1c,#b45309,#047857,#0e7490,#1d4ed8,#6d28d9,#be185d,#b91c1c);">
155 <span id="catCustomDot" style="display:none;position:absolute;inset:5px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,0.25);background:#fff;pointer-events:none"></span>
156 <input type="color" id="catColorCustom" value="#6d28d9"
157 style="position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:none;padding:0;background:transparent">
158 </div>
159 </div>
160 <!-- One hidden field carries the actual value either swatch or
161 picker put into it. Keeps the server-side handler simple. -->
162 <input type="hidden" name="color" id="catColor" value="#6d28d9">
163 </div>
164
165 <!-- Emoji + picker takes a full row (the picker is wide; cramming
166 it into a 2-col grid wastes ~half the modal). Sort order +
167 Show-on-storefront move below into their own row. -->
168 <div>
169 <div class="form-group">
170 <label class="form-label">Emoji <span class="text-xs text-dim">(optional)</span></label>
171 <input type="text" name="icon" id="catIcon" class="input" maxlength="40" placeholder="&#x1F383;">
172 <div class="cat-emoji-picker" id="catEmojiPicker">
173 <!-- ~100 emojis grouped by theme. Click inserts into the
174 field; the X at the end clears. Buttons not links so
175 they don't submit the form. -->
176 <button type="button" class="cat-emoji-pick">&#x1F4E6;</button><!-- box -->
177 <button type="button" class="cat-emoji-pick">&#x1F381;</button><!-- gift -->
178 <button type="button" class="cat-emoji-pick">&#x1F48E;</button><!-- gem -->
179 <button type="button" class="cat-emoji-pick">&#x1F3F7;&#xFE0F;</button><!-- label -->
180 <button type="button" class="cat-emoji-pick">&#x1F516;</button><!-- bookmark -->
181 <button type="button" class="cat-emoji-pick">&#x1F4CC;</button><!-- pushpin -->
182 <button type="button" class="cat-emoji-pick">&#x1F3AF;</button><!-- target -->
183 <button type="button" class="cat-emoji-pick">&#x1FA99;</button><!-- coin -->
184 <button type="button" class="cat-emoji-pick">&#x1F39F;&#xFE0F;</button><!-- ticket -->
185 <button type="button" class="cat-emoji-pick">&#x1F6CD;&#xFE0F;</button><!-- shopping bag -->
186
187 <button type="button" class="cat-emoji-pick">&#x2B50;</button><!-- star -->
188 <button type="button" class="cat-emoji-pick">&#x2728;</button><!-- sparkles -->
189 <button type="button" class="cat-emoji-pick">&#x1F31F;</button><!-- glowing star -->
190 <button type="button" class="cat-emoji-pick">&#x1F4AB;</button><!-- dizzy -->
191 <button type="button" class="cat-emoji-pick">&#x26A1;</button><!-- lightning -->
192 <button type="button" class="cat-emoji-pick">&#x1F525;</button><!-- fire -->
193 <button type="button" class="cat-emoji-pick">&#x1F4A7;</button><!-- droplet -->
194 <button type="button" class="cat-emoji-pick">&#x2744;&#xFE0F;</button><!-- snowflake -->
195 <button type="button" class="cat-emoji-pick">&#x2600;&#xFE0F;</button><!-- sun -->
196 <button type="button" class="cat-emoji-pick">&#x1F308;</button><!-- rainbow -->
197
198 <button type="button" class="cat-emoji-pick">&#x1F496;</button><!-- sparkling heart -->
199 <button type="button" class="cat-emoji-pick">&#x1F49D;</button><!-- heart with ribbon -->
200 <button type="button" class="cat-emoji-pick">&#x2764;&#xFE0F;</button><!-- red heart -->
201 <button type="button" class="cat-emoji-pick">&#x1F9E1;</button><!-- orange heart -->
202 <button type="button" class="cat-emoji-pick">&#x1F49B;</button><!-- yellow heart -->
203 <button type="button" class="cat-emoji-pick">&#x1F49A;</button><!-- green heart -->
204 <button type="button" class="cat-emoji-pick">&#x1F499;</button><!-- blue heart -->
205 <button type="button" class="cat-emoji-pick">&#x1F49C;</button><!-- purple heart -->
206
207 <button type="button" class="cat-emoji-pick">&#x1F384;</button><!-- christmas tree -->
208 <button type="button" class="cat-emoji-pick">&#x1F383;</button><!-- jack-o-lantern -->
209 <button type="button" class="cat-emoji-pick">&#x1F386;</button><!-- fireworks -->
210 <button type="button" class="cat-emoji-pick">&#x1F387;</button><!-- sparkler -->
211 <button type="button" class="cat-emoji-pick">&#x1F388;</button><!-- balloon -->
212 <button type="button" class="cat-emoji-pick">&#x1F38A;</button><!-- confetti ball -->
213 <button type="button" class="cat-emoji-pick">&#x1F389;</button><!-- party popper -->
214 <button type="button" class="cat-emoji-pick">&#x1F380;</button><!-- ribbon -->
215
216 <button type="button" class="cat-emoji-pick">&#x1F436;</button><!-- dog -->
217 <button type="button" class="cat-emoji-pick">&#x1F431;</button><!-- cat -->
218 <button type="button" class="cat-emoji-pick">&#x1F98A;</button><!-- fox -->
219 <button type="button" class="cat-emoji-pick">&#x1F430;</button><!-- rabbit -->
220 <button type="button" class="cat-emoji-pick">&#x1F43C;</button><!-- panda -->
221 <button type="button" class="cat-emoji-pick">&#x1F981;</button><!-- lion -->
222 <button type="button" class="cat-emoji-pick">&#x1F42F;</button><!-- tiger -->
223 <button type="button" class="cat-emoji-pick">&#x1F409;</button><!-- dragon -->
224 <button type="button" class="cat-emoji-pick">&#x1F984;</button><!-- unicorn -->
225 <button type="button" class="cat-emoji-pick">&#x1F422;</button><!-- turtle -->
226 <button type="button" class="cat-emoji-pick">&#x1F98B;</button><!-- butterfly -->
227 <button type="button" class="cat-emoji-pick">&#x1F420;</button><!-- tropical fish -->
228
229 <button type="button" class="cat-emoji-pick">&#x1F33F;</button><!-- herb -->
230 <button type="button" class="cat-emoji-pick">&#x1F331;</button><!-- seedling -->
231 <button type="button" class="cat-emoji-pick">&#x1F333;</button><!-- deciduous tree -->
232 <button type="button" class="cat-emoji-pick">&#x1F337;</button><!-- tulip -->
233 <button type="button" class="cat-emoji-pick">&#x1F339;</button><!-- rose -->
234 <button type="button" class="cat-emoji-pick">&#x1F33B;</button><!-- sunflower -->
235 <button type="button" class="cat-emoji-pick">&#x1F340;</button><!-- four-leaf clover -->
236 <button type="button" class="cat-emoji-pick">&#x1F341;</button><!-- maple leaf -->
237
238 <button type="button" class="cat-emoji-pick">&#x1F355;</button><!-- pizza -->
239 <button type="button" class="cat-emoji-pick">&#x1F370;</button><!-- cake -->
240 <button type="button" class="cat-emoji-pick">&#x1F369;</button><!-- donut -->
241 <button type="button" class="cat-emoji-pick">&#x1F36A;</button><!-- cookie -->
242 <button type="button" class="cat-emoji-pick">&#x2615;</button><!-- coffee -->
243 <button type="button" class="cat-emoji-pick">&#x1F37A;</button><!-- beer -->
244
245 <button type="button" class="cat-emoji-pick">&#x1F4A1;</button><!-- light bulb -->
246 <button type="button" class="cat-emoji-pick">&#x1F527;</button><!-- wrench -->
247 <button type="button" class="cat-emoji-pick">&#x1F528;</button><!-- hammer -->
248 <button type="button" class="cat-emoji-pick">&#x2699;&#xFE0F;</button><!-- gear -->
249 <button type="button" class="cat-emoji-pick">&#x1F6E0;&#xFE0F;</button><!-- hammer & wrench -->
250 <button type="button" class="cat-emoji-pick">&#x1F4BB;</button><!-- laptop -->
251 <button type="button" class="cat-emoji-pick">&#x1F4F1;</button><!-- mobile phone -->
252 <button type="button" class="cat-emoji-pick">&#x2328;&#xFE0F;</button><!-- keyboard -->
253 <button type="button" class="cat-emoji-pick">&#x1F50C;</button><!-- plug -->
254 <button type="button" class="cat-emoji-pick">&#x1FA9B;</button><!-- screwdriver -->
255
256 <button type="button" class="cat-emoji-pick">&#x1F3AE;</button><!-- video game -->
257 <button type="button" class="cat-emoji-pick">&#x1F579;&#xFE0F;</button><!-- joystick -->
258 <button type="button" class="cat-emoji-pick">&#x1F3B2;</button><!-- die -->
259 <button type="button" class="cat-emoji-pick">&#x1F9E9;</button><!-- puzzle piece -->
260 <button type="button" class="cat-emoji-pick">&#x1F9F8;</button><!-- teddy bear -->
261 <button type="button" class="cat-emoji-pick">&#x1F3A8;</button><!-- art palette -->
262 <button type="button" class="cat-emoji-pick">&#x1F3AD;</button><!-- performing arts -->
263 <button type="button" class="cat-emoji-pick">&#x1FA80;</button><!-- yo-yo -->
264
265 <button type="button" class="cat-emoji-pick">&#x1F3E0;</button><!-- house -->
266 <button type="button" class="cat-emoji-pick">&#x1F6CB;&#xFE0F;</button><!-- couch -->
267 <button type="button" class="cat-emoji-pick">&#x1F6CF;&#xFE0F;</button><!-- bed -->
268 <button type="button" class="cat-emoji-pick">&#x1FA91;</button><!-- chair -->
269 <button type="button" class="cat-emoji-pick">&#x1F6AA;</button><!-- door -->
270 <button type="button" class="cat-emoji-pick">&#x1F511;</button><!-- key -->
271
272 <button type="button" class="cat-emoji-pick">&#x1F697;</button><!-- car -->
273 <button type="button" class="cat-emoji-pick">&#x1F6B2;</button><!-- bicycle -->
274 <button type="button" class="cat-emoji-pick">&#x2708;&#xFE0F;</button><!-- airplane -->
275 <button type="button" class="cat-emoji-pick">&#x1F680;</button><!-- rocket -->
276 <button type="button" class="cat-emoji-pick">&#x26F5;</button><!-- sailboat -->
277 <button type="button" class="cat-emoji-pick">&#x1F682;</button><!-- train -->
278
279 <button type="button" class="cat-emoji-pick">&#x26BD;</button><!-- soccer -->
280 <button type="button" class="cat-emoji-pick">&#x1F3C0;</button><!-- basketball -->
281 <button type="button" class="cat-emoji-pick">&#x1F3BE;</button><!-- tennis -->
282 <button type="button" class="cat-emoji-pick">&#x1F3CB;&#xFE0F;</button><!-- weight lifter -->
283 <button type="button" class="cat-emoji-pick">&#x26F7;&#xFE0F;</button><!-- skier -->
284 <button type="button" class="cat-emoji-pick">&#x1F3CA;</button><!-- swimmer -->
285
286 <button type="button" class="cat-emoji-pick">&#x1F451;</button><!-- crown -->
287 <button type="button" class="cat-emoji-pick">&#x1F3A9;</button><!-- top hat -->
288 <button type="button" class="cat-emoji-pick">&#x1F47B;</button><!-- ghost -->
289 <button type="button" class="cat-emoji-pick">&#x1F916;</button><!-- robot -->
290 <button type="button" class="cat-emoji-pick">&#x1F480;</button><!-- skull -->
291 <button type="button" class="cat-emoji-pick">&#x1F987;</button><!-- bat -->
292 <button type="button" class="cat-emoji-pick">&#x1F9D9;</button><!-- mage -->
293 <button type="button" class="cat-emoji-pick">&#x1F9DA;</button><!-- fairy -->
294
295 <!-- ============== Second 100 emojis ============== -->
296
297 <!-- Weather + sky -->
298 <button type="button" class="cat-emoji-pick">&#x1F324;&#xFE0F;</button><!-- sun behind small cloud -->
299 <button type="button" class="cat-emoji-pick">&#x26C5;</button><!-- sun behind cloud -->
300 <button type="button" class="cat-emoji-pick">&#x2601;&#xFE0F;</button><!-- cloud -->
301 <button type="button" class="cat-emoji-pick">&#x1F327;&#xFE0F;</button><!-- rain -->
302 <button type="button" class="cat-emoji-pick">&#x26C8;&#xFE0F;</button><!-- thunderstorm -->
303 <button type="button" class="cat-emoji-pick">&#x1F32A;&#xFE0F;</button><!-- tornado -->
304 <button type="button" class="cat-emoji-pick">&#x1F30A;</button><!-- ocean wave -->
305 <button type="button" class="cat-emoji-pick">&#x1F32B;&#xFE0F;</button><!-- fog -->
306 <button type="button" class="cat-emoji-pick">&#x1F319;</button><!-- crescent moon -->
307 <button type="button" class="cat-emoji-pick">&#x1F31A;</button><!-- new moon face -->
308 <button type="button" class="cat-emoji-pick">&#x1F31D;</button><!-- full moon face -->
309 <button type="button" class="cat-emoji-pick">&#x1F30D;</button><!-- earth europe -->
310
311 <!-- More animals -->
312 <button type="button" class="cat-emoji-pick">&#x1F40E;</button><!-- horse -->
313 <button type="button" class="cat-emoji-pick">&#x1F404;</button><!-- cow -->
314 <button type="button" class="cat-emoji-pick">&#x1F411;</button><!-- sheep -->
315 <button type="button" class="cat-emoji-pick">&#x1F416;</button><!-- pig -->
316 <button type="button" class="cat-emoji-pick">&#x1F414;</button><!-- chicken -->
317 <button type="button" class="cat-emoji-pick">&#x1F986;</button><!-- duck -->
318 <button type="button" class="cat-emoji-pick">&#x1F985;</button><!-- eagle -->
319 <button type="button" class="cat-emoji-pick">&#x1F989;</button><!-- owl -->
320 <button type="button" class="cat-emoji-pick">&#x1F99C;</button><!-- parrot -->
321 <button type="button" class="cat-emoji-pick">&#x1F41D;</button><!-- bee -->
322 <button type="button" class="cat-emoji-pick">&#x1F41E;</button><!-- ladybug -->
323 <button type="button" class="cat-emoji-pick">&#x1F577;&#xFE0F;</button><!-- spider -->
324 <button type="button" class="cat-emoji-pick">&#x1F419;</button><!-- octopus -->
325 <button type="button" class="cat-emoji-pick">&#x1F980;</button><!-- crab -->
326 <button type="button" class="cat-emoji-pick">&#x1F99E;</button><!-- lobster -->
327
328 <!-- Fruits + vegetables -->
329 <button type="button" class="cat-emoji-pick">&#x1F34E;</button><!-- apple -->
330 <button type="button" class="cat-emoji-pick">&#x1F34A;</button><!-- orange -->
331 <button type="button" class="cat-emoji-pick">&#x1F34B;</button><!-- lemon -->
332 <button type="button" class="cat-emoji-pick">&#x1F347;</button><!-- grapes -->
333 <button type="button" class="cat-emoji-pick">&#x1F353;</button><!-- strawberry -->
334 <button type="button" class="cat-emoji-pick">&#x1F95D;</button><!-- kiwi -->
335 <button type="button" class="cat-emoji-pick">&#x1F351;</button><!-- peach -->
336 <button type="button" class="cat-emoji-pick">&#x1F951;</button><!-- avocado -->
337 <button type="button" class="cat-emoji-pick">&#x1F955;</button><!-- carrot -->
338 <button type="button" class="cat-emoji-pick">&#x1F33D;</button><!-- corn -->
339 <button type="button" class="cat-emoji-pick">&#x1F956;</button><!-- bread -->
340 <button type="button" class="cat-emoji-pick">&#x1F35E;</button><!-- baguette -->
341
342 <!-- Drinks -->
343 <button type="button" class="cat-emoji-pick">&#x1F377;</button><!-- wine glass -->
344 <button type="button" class="cat-emoji-pick">&#x1F378;</button><!-- cocktail -->
345 <button type="button" class="cat-emoji-pick">&#x1F964;</button><!-- cup with straw -->
346 <button type="button" class="cat-emoji-pick">&#x1F9CB;</button><!-- bubble tea -->
347 <button type="button" class="cat-emoji-pick">&#x1F95B;</button><!-- glass of milk -->
348 <button type="button" class="cat-emoji-pick">&#x1F375;</button><!-- teacup -->
349
350 <!-- Music -->
351 <button type="button" class="cat-emoji-pick">&#x1F3B5;</button><!-- musical note -->
352 <button type="button" class="cat-emoji-pick">&#x1F3B6;</button><!-- musical notes -->
353 <button type="button" class="cat-emoji-pick">&#x1F3A4;</button><!-- microphone -->
354 <button type="button" class="cat-emoji-pick">&#x1F3A7;</button><!-- headphone -->
355 <button type="button" class="cat-emoji-pick">&#x1F3B8;</button><!-- guitar -->
356 <button type="button" class="cat-emoji-pick">&#x1F3B9;</button><!-- piano -->
357 <button type="button" class="cat-emoji-pick">&#x1F941;</button><!-- drum -->
358 <button type="button" class="cat-emoji-pick">&#x1F3BA;</button><!-- trumpet -->
359
360 <!-- More sports + awards -->
361 <button type="button" class="cat-emoji-pick">&#x1F3D0;</button><!-- volleyball -->
362 <button type="button" class="cat-emoji-pick">&#x1F3C8;</button><!-- football -->
363 <button type="button" class="cat-emoji-pick">&#x26BE;</button><!-- baseball -->
364 <button type="button" class="cat-emoji-pick">&#x1F94A;</button><!-- boxing glove -->
365 <button type="button" class="cat-emoji-pick">&#x1F3C6;</button><!-- trophy -->
366 <button type="button" class="cat-emoji-pick">&#x1F947;</button><!-- 1st place -->
367 <button type="button" class="cat-emoji-pick">&#x1F3C5;</button><!-- medal -->
368 <button type="button" class="cat-emoji-pick">&#x1F396;&#xFE0F;</button><!-- military medal -->
369
370 <!-- Science -->
371 <button type="button" class="cat-emoji-pick">&#x1F52C;</button><!-- microscope -->
372 <button type="button" class="cat-emoji-pick">&#x1F52D;</button><!-- telescope -->
373 <button type="button" class="cat-emoji-pick">&#x1F9EA;</button><!-- test tube -->
374 <button type="button" class="cat-emoji-pick">&#x1F9EC;</button><!-- DNA -->
375 <button type="button" class="cat-emoji-pick">&#x2697;&#xFE0F;</button><!-- alembic -->
376 <button type="button" class="cat-emoji-pick">&#x1F9F2;</button><!-- magnet -->
377 <button type="button" class="cat-emoji-pick">&#x1FA90;</button><!-- ringed planet -->
378 <button type="button" class="cat-emoji-pick">&#x2604;&#xFE0F;</button><!-- comet -->
379
380 <!-- Travel + places -->
381 <button type="button" class="cat-emoji-pick">&#x1F5FA;&#xFE0F;</button><!-- world map -->
382 <button type="button" class="cat-emoji-pick">&#x1F9ED;</button><!-- compass -->
383 <button type="button" class="cat-emoji-pick">&#x1F30E;</button><!-- earth americas -->
384 <button type="button" class="cat-emoji-pick">&#x1F5FD;</button><!-- statue of liberty -->
385 <button type="button" class="cat-emoji-pick">&#x1F5FC;</button><!-- tokyo tower -->
386 <button type="button" class="cat-emoji-pick">&#x1F3D4;&#xFE0F;</button><!-- snow-capped mountain -->
387 <button type="button" class="cat-emoji-pick">&#x1F3D6;&#xFE0F;</button><!-- beach -->
388 <button type="button" class="cat-emoji-pick">&#x1F3DD;&#xFE0F;</button><!-- desert island -->
389
390 <!-- Office + school -->
391 <button type="button" class="cat-emoji-pick">&#x1F4DA;</button><!-- books -->
392 <button type="button" class="cat-emoji-pick">&#x1F4D6;</button><!-- open book -->
393 <button type="button" class="cat-emoji-pick">&#x1F4DD;</button><!-- memo -->
394 <button type="button" class="cat-emoji-pick">&#x270F;&#xFE0F;</button><!-- pencil -->
395 <button type="button" class="cat-emoji-pick">&#x1F4D0;</button><!-- triangular ruler -->
396 <button type="button" class="cat-emoji-pick">&#x1F4CF;</button><!-- straight ruler -->
397 <button type="button" class="cat-emoji-pick">&#x1F4CE;</button><!-- paperclip -->
398 <button type="button" class="cat-emoji-pick">&#x1F4CB;</button><!-- clipboard -->
399
400 <!-- Money -->
401 <button type="button" class="cat-emoji-pick">&#x1F4B0;</button><!-- money bag -->
402 <button type="button" class="cat-emoji-pick">&#x1F4B5;</button><!-- dollar banknote -->
403 <button type="button" class="cat-emoji-pick">&#x1F4B3;</button><!-- credit card -->
404 <button type="button" class="cat-emoji-pick">&#x1F9FE;</button><!-- receipt -->
405
406 <!-- Time -->
407 <button type="button" class="cat-emoji-pick">&#x23F0;</button><!-- alarm clock -->
408 <button type="button" class="cat-emoji-pick">&#x23F1;&#xFE0F;</button><!-- stopwatch -->
409 <button type="button" class="cat-emoji-pick">&#x231B;</button><!-- hourglass -->
410 <button type="button" class="cat-emoji-pick">&#x1F4C5;</button><!-- calendar -->
411
412 <!-- More tools -->
413 <button type="button" class="cat-emoji-pick">&#x1FA9A;</button><!-- saw -->
414 <button type="button" class="cat-emoji-pick">&#x1FA9F;</button><!-- window -->
415 <button type="button" class="cat-emoji-pick">&#x1FAA4;</button><!-- mouse trap -->
416 <button type="button" class="cat-emoji-pick">&#x1FAA3;</button><!-- bucket -->
417 <button type="button" class="cat-emoji-pick">&#x1F9F9;</button><!-- broom -->
418 <button type="button" class="cat-emoji-pick">&#x1FA9E;</button><!-- mirror -->
419
420 <!-- Marks + symbols -->
421 <button type="button" class="cat-emoji-pick">&#x2705;</button><!-- check mark -->
422 <button type="button" class="cat-emoji-pick">&#x274C;</button><!-- cross mark -->
423 <button type="button" class="cat-emoji-pick">&#x2757;</button><!-- exclamation -->
424 <button type="button" class="cat-emoji-pick">&#x2753;</button><!-- question -->
425 <button type="button" class="cat-emoji-pick">&#x2795;</button><!-- plus -->
426
427 <button type="button" class="cat-emoji-pick" title="Clear" data-clear="1">&#x2715;</button>
428 </div>
429 <div class="text-xs text-dim" style="margin-top:4px;line-height:1.4">Click an emoji above (scroll for more), or type your own. Win+. on Windows / Ctrl+Cmd+Space on Mac opens the OS emoji picker.</div>
430 </div>
431 </div>
432
433 <div class="dash-grid-2" style="gap:10px;align-items:end">
434 <div class="form-group">
435 <label class="form-label">Sort order</label>
436 <input type="number" name="sort_order" id="catSort" class="input" value="0" min="0">
437 </div>
438 <div class="form-group">
439 <label class="up-check" style="display:flex;align-items:center;gap:8px;font-size:13px;color:var(--col-text-2);cursor:pointer;padding:9px 0">
440 <input type="checkbox" name="is_public" id="catPublic" value="1" checked>
441 <span>Show on storefront filter bar</span>
442 </label>
443 </div>
444 </div>
445
446 <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:8px">
447 <button type="button" class="btn btn-secondary" id="catCancel">Cancel</button>
448 <button type="submit" class="btn btn-primary">Save category</button>
449 </div>
450 </form>
451 </div>
452</div>
453
454<script>
455(function(){
456 var modal = document.getElementById('catModal');
457 var titleEl = document.getElementById('catModalTitle');
458 var form = document.getElementById('catForm');
459 var actInput = document.getElementById('catAct');
460 var idInput = document.getElementById('catId');
461 var nameInput = document.getElementById('catName');
462 var descInput = document.getElementById('catDesc');
463 var iconInput = document.getElementById('catIcon');
464 var sortInput = document.getElementById('catSort');
465 var publicInput = document.getElementById('catPublic');
466 var colorHidden = document.getElementById('catColor');
467 var colorPicker = document.getElementById('catColorCustom');
468 var customWrap = document.querySelector('.cat-color-custom-wrap');
469 var customDot = document.getElementById('catCustomDot');
470 var swatches = document.querySelectorAll('#catColors input[type=radio]');
471
472 function applySwatch(value) {
473 colorHidden.value = value;
474 customDot.style.display = 'none';
475 customWrap.classList.remove('is-active');
476 }
477 function applyCustom(value) {
478 colorHidden.value = value;
479 swatches.forEach(function(r){ r.checked = false; });
480 customDot.style.background = value;
481 customDot.style.display = 'block';
482 customWrap.classList.add('is-active');
483 }
484
485 swatches.forEach(function(r){
486 r.addEventListener('change', function(){ if (r.checked) applySwatch(r.value); });
487 });
488 // 'input' fires while dragging; 'change' fires when the dialog
489 // closes. Listen to both so the chip preview tracks the picker live
490 // and the final value is committed even if the user clicks away
491 // without releasing on a color.
492 colorPicker.addEventListener('input', function(){ applyCustom(colorPicker.value); });
493 colorPicker.addEventListener('change', function(){ applyCustom(colorPicker.value); });
494
495 function setColorFromValue(c) {
496 var matched = false;
497 swatches.forEach(function(r){
498 if (r.value.toLowerCase() === c.toLowerCase()) { r.checked = true; matched = true; }
499 else { r.checked = false; }
500 });
501 if (matched) { applySwatch(c); }
502 else { applyCustom(c); colorPicker.value = c; }
503 }
504
505 // Emoji quick-pick: insert clicked emoji into the icon field.
506 document.querySelectorAll('.cat-emoji-pick').forEach(function(b){
507 b.addEventListener('click', function(){
508 if (b.dataset.clear) { iconInput.value = ''; }
509 else { iconInput.value = b.textContent.trim(); }
510 });
511 });
512
513 function openNew() {
514 titleEl.textContent = 'New category';
515 actInput.value = 'create';
516 idInput.value = '';
517 nameInput.value = '';
518 descInput.value = '';
519 iconInput.value = '';
520 sortInput.value = '0';
521 publicInput.checked = true;
522 setColorFromValue('#6d28d9');
523 modal.classList.add('is-open');
524 setTimeout(function(){ nameInput.focus(); }, 50);
525 }
526 function openEdit(btn) {
527 titleEl.textContent = 'Edit category';
528 actInput.value = 'update';
529 idInput.value = btn.dataset.id;
530 nameInput.value = btn.dataset.name || '';
531 descInput.value = btn.dataset.desc || '';
532 iconInput.value = btn.dataset.icon || '';
533 sortInput.value = btn.dataset.sort || '0';
534 publicInput.checked = btn.dataset.public === '1';
535 setColorFromValue(btn.dataset.color || '#6d28d9');
536 modal.classList.add('is-open');
537 }
538 function close() { modal.classList.remove('is-open'); }
539 var newBtn = document.getElementById('catOpenNew');
540 if (newBtn) newBtn.addEventListener('click', openNew);
541 var newBtnEmpty = document.getElementById('catOpenNewEmpty');
542 if (newBtnEmpty) newBtnEmpty.addEventListener('click', openNew);
543 document.querySelectorAll('.cat-edit').forEach(function(b){
544 b.addEventListener('click', function(){ openEdit(b); });
545 });
546 document.getElementById('catCancel').addEventListener('click', close);
547 modal.addEventListener('click', function(e){ if (e.target === modal) close(); });
548 document.addEventListener('keydown', function(e){ if (e.key === 'Escape') close(); });
549})();
550</script>
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help