Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/MODS/RePricer/Themes.pm
Diff

/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/MODS/RePricer/Themes.pm

added on local at 2026-07-01 21:47:15

Added
+877
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 7c0b599412b5
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1package MODS::RePricer::Themes;
2#======================================================================
3# RePricer — Storefront Themes registry.
4#
5# This file is THE place to add or tweak storefront themes. Each theme
6# is just a Perl hash. To add a new theme, copy any block below, change
7# the values, and add it to @THEMES at the bottom. The platform picks
8# it up immediately — no database migration, no template edits.
9#
10# WHAT EACH FIELD DOES (everything below "id" is just colors):
11# id — number. MUST be unique. Used by storefronts.theme_id.
12# slug — short lowercase name. Used in URLs / filenames.
13# name — what creators see in the picker (e.g. "Dungeon Forge").
14# tagline — one-line vibe description shown under the name.
15# bg — main page background color.
16# bg_2 — slightly lighter bg, used for header/footer/cards.
17# surface — card / panel background (one notch above bg_2).
18# surface_2 — even lighter card for nested panels.
19# border — line color for card edges, dividers.
20# border_2 — subtler/brighter border for hover states.
21# text — main body text color (READ THIS ON BG: must be legible).
22# text_2 — secondary text (subheads, less-important info).
23# text_3 — tertiary text (timestamps, dim metadata).
24# accent — brand color. Buttons, links, highlights, gradient start.
25# accent_2 — second brand color. Gradient end. Stars, pills.
26# accent_deep— pressed/active variant of accent.
27# accent_glow— rgba(...) version of accent for soft glow effects.
28#
29# DESIGN PHILOSOPHY:
30# These themes target sellers of products. Each one is
31# tuned for a particular niche (tabletop minis, FDM functional parts,
32# premium resin art, sci-fi / cyberpunk, classic D&D, cute prints).
33#
34# Pick colors that work TOGETHER. Test contrast: text on bg must be
35# readable. The site is dark by default; if you make a light theme
36# make sure ALL text colors flip too.
37#======================================================================
38use strict;
39use warnings;
40
41#----------------------------------------------------------------------
42# Themes — add new ones here.
43#----------------------------------------------------------------------
44our @THEMES = (
45 {
46 id => 1,
47 slug => 'forge',
48 name => 'Dungeon Forge',
49 tagline => 'Bold purple-and-blue magic. Built for tabletop minis & fantasy terrain.',
50 bg => '#050813',
51 bg_2 => '#080c1a',
52 surface => '#0e1426',
53 surface_2 => '#141b33',
54 border => '#1c2a48',
55 border_2 => '#283c66',
56 text => '#e6ecf6',
57 text_2 => '#a8b6d1',
58 text_3 => '#6f7e9c',
59 accent => '#0f766e',
60 accent_2 => '#059669',
61 accent_deep => '#5b21b6',
62 accent_glow => 'rgba(15,118,110,0.35)',
63 },
64 {
65 id => 2,
66 slug => 'workshop',
67 name => 'Workshop',
68 tagline => 'Industrial orange on graphite. Perfect for FDM tools, jigs & functional parts.',
69 bg => '#0d0e10',
70 bg_2 => '#15171a',
71 surface => '#1c1f23',
72 surface_2 => '#24282d',
73 border => '#2d323a',
74 border_2 => '#404750',
75 text => '#f4f1ec',
76 text_2 => '#b8b3a8',
77 text_3 => '#7a7468',
78 accent => '#f97316',
79 accent_2 => '#fbbf24',
80 accent_deep => '#c2410c',
81 accent_glow => 'rgba(249,115,22,0.35)',
82 },
83 {
84 id => 3,
85 slug => 'atelier',
86 name => 'Atelier',
87 tagline => 'Clean cream-and-rose. The premium look for high-end resin & art prints.',
88 bg => '#f8f5f0',
89 bg_2 => '#ede8df',
90 surface => '#ffffff',
91 surface_2 => '#f4efe7',
92 border => '#dcd5c8',
93 border_2 => '#c9c0ae',
94 text => '#1f1a14',
95 text_2 => '#5a4f3e',
96 text_3 => '#8a7f6c',
97 accent => '#c2410c',
98 accent_2 => '#d97757',
99 accent_deep => '#9a3412',
100 accent_glow => 'rgba(194,65,12,0.20)',
101 },
102 {
103 id => 4,
104 slug => 'mecha',
105 name => 'Mecha',
106 tagline => 'Neon cyan on void-black. Cyberpunk, sci-fi mechs, futurist tech parts.',
107 bg => '#02060a',
108 bg_2 => '#050b14',
109 surface => '#0a131f',
110 surface_2 => '#101c2e',
111 border => '#1a3046',
112 border_2 => '#2a4a6e',
113 text => '#e6f8ff',
114 text_2 => '#7fb8d6',
115 text_3 => '#4a7d96',
116 accent => '#14b8a6',
117 accent_2 => '#059669',
118 accent_deep => '#0e7490',
119 accent_glow => 'rgba(20,184,166,0.40)',
120 },
121 {
122 id => 5,
123 slug => 'tabletop',
124 name => 'Tabletop',
125 tagline => 'Old-leather red & parchment gold. Classic D&D, wargame & RPG energy.',
126 bg => '#1a0e0a',
127 bg_2 => '#22130d',
128 surface => '#2c1a13',
129 surface_2 => '#38221a',
130 border => '#5a3324',
131 border_2 => '#7a4632',
132 text => '#f4e8d0',
133 text_2 => '#c8b08a',
134 text_3 => '#8c7458',
135 accent => '#dc2626',
136 accent_2 => '#d97706',
137 accent_deep => '#991b1b',
138 accent_glow => 'rgba(220,38,38,0.35)',
139 },
140 {
141 id => 6,
142 slug => 'cottage',
143 name => 'Cottage',
144 tagline => 'Soft sage & cream. Cute, whimsical, handcrafted — kawaii prints & cozy minis.',
145 bg => '#1c1f1a',
146 bg_2 => '#24281f',
147 surface => '#2e3327',
148 surface_2 => '#3a4030',
149 border => '#4a5240',
150 border_2 => '#65705a',
151 text => '#f5f0e1',
152 text_2 => '#c4c0a8',
153 text_3 => '#8a8770',
154 accent => '#84cc16',
155 accent_2 => '#facc15',
156 accent_deep => '#4d7c0f',
157 accent_glow => 'rgba(132,204,22,0.35)',
158 },
159 {
160 id => 7,
161 slug => 'midnight',
162 name => 'Midnight',
163 tagline => 'Deep blue & silver. Calm, premium, late-night focus.',
164 bg => '#0a0e1a',
165 bg_2 => '#10172a',
166 surface => '#171f36',
167 surface_2 => '#1f2a44',
168 border => '#283c66',
169 border_2 => '#3b5394',
170 text => '#e2e8f8',
171 text_2 => '#94a3c8',
172 text_3 => '#64708e',
173 accent => '#0d9488',
174 accent_2 => '#14b8a6',
175 accent_deep => '#4338ca',
176 accent_glow => 'rgba(13,148,136,0.30)',
177 },
178 {
179 id => 8,
180 slug => 'ember',
181 name => 'Ember',
182 tagline => 'Warm amber on charcoal. Cozy bookshop, fireplace energy.',
183 bg => '#1a120a',
184 bg_2 => '#22180e',
185 surface => '#2c2014',
186 surface_2 => '#36271a',
187 border => '#4d3922',
188 border_2 => '#6e5532',
189 text => '#f5e8d4',
190 text_2 => '#c8a878',
191 text_3 => '#8c7448',
192 accent => '#ea580c',
193 accent_2 => '#f59e0b',
194 accent_deep => '#9a3412',
195 accent_glow => 'rgba(234,88,12,0.30)',
196 },
197 {
198 id => 9,
199 slug => 'ink',
200 name => 'Ink',
201 tagline => 'High-contrast black & white with a single red. Editorial, magazine-bold.',
202 bg => '#0a0a0a',
203 bg_2 => '#141414',
204 surface => '#1c1c1c',
205 surface_2 => '#262626',
206 border => '#333333',
207 border_2 => '#525252',
208 text => '#fafafa',
209 text_2 => '#a3a3a3',
210 text_3 => '#737373',
211 accent => '#ef4444',
212 accent_2 => '#fafafa',
213 accent_deep => '#b91c1c',
214 accent_glow => 'rgba(239,68,68,0.35)',
215 },
216 {
217 id => 10,
218 slug => 'nebula',
219 name => 'Nebula',
220 tagline => 'Deep space purples & magenta. Dreamy, cosmic, otherworldly.',
221 bg => '#0d0617',
222 bg_2 => '#160a23',
223 surface => '#1f1130',
224 surface_2 => '#2a173f',
225 border => '#3d2459',
226 border_2 => '#5a3a82',
227 text => '#f3e8ff',
228 text_2 => '#c4a8e0',
229 text_3 => '#8a6da8',
230 accent => '#d946ef',
231 accent_2 => '#059669',
232 accent_deep => '#86198f',
233 accent_glow => 'rgba(217,70,239,0.35)',
234 },
235 {
236 id => 11,
237 slug => 'parchment',
238 name => 'Parchment',
239 tagline => 'Warm cream paper with sepia ink. Light theme, vintage map vibes.',
240 bg => '#f4ead5',
241 bg_2 => '#ebdfc4',
242 surface => '#fdf6e3',
243 surface_2 => '#f0e3c8',
244 border => '#cdb992',
245 border_2 => '#a89570',
246 text => '#2a1f10',
247 text_2 => '#5c4a30',
248 text_3 => '#8a7754',
249 accent => '#92400e',
250 accent_2 => '#b45309',
251 accent_deep => '#78350f',
252 accent_glow => 'rgba(146,64,14,0.20)',
253 },
254 {
255 id => 12,
256 slug => 'reef',
257 name => 'Reef',
258 tagline => 'Teal & coral. Tropical, energetic, summer vacation feel.',
259 bg => '#062029',
260 bg_2 => '#0a2c38',
261 surface => '#103847',
262 surface_2 => '#15485b',
263 border => '#1f6075',
264 border_2 => '#2e8094',
265 text => '#e0f5fa',
266 text_2 => '#88c4d4',
267 text_3 => '#5290a0',
268 accent => '#fb7185',
269 accent_2 => '#14b8a6',
270 accent_deep => '#9f1239',
271 accent_glow => 'rgba(251,113,133,0.35)',
272 },
273
274 # --- Subtle / sophisticated palettes ---
275 {
276 id => 13,
277 slug => 'stone',
278 name => 'Stone',
279 tagline => 'Warm neutrals with a bronze accent. Quiet, refined, gallery-grade.',
280 bg => '#1a1815',
281 bg_2 => '#221f1a',
282 surface => '#2a2620',
283 surface_2 => '#34302a',
284 border => '#463f35',
285 border_2 => '#635a4d',
286 text => '#ebe4d6',
287 text_2 => '#aea189',
288 text_3 => '#7a6f5a',
289 accent => '#b08968',
290 accent_2 => '#d4a574',
291 accent_deep => '#7a5a40',
292 accent_glow => 'rgba(176,137,104,0.30)',
293 },
294 {
295 id => 14,
296 slug => 'pine',
297 name => 'Pine',
298 tagline => 'Deep forest green with sage highlights. Calm, natural, grounded.',
299 bg => '#0a1612',
300 bg_2 => '#0f1d18',
301 surface => '#14261f',
302 surface_2 => '#1b3127',
303 border => '#2c4a3d',
304 border_2 => '#406a55',
305 text => '#e8efe6',
306 text_2 => '#99b3a3',
307 text_3 => '#5a7a6a',
308 accent => '#4a8f5e',
309 accent_2 => '#6dab6e',
310 accent_deep => '#2d5a3a',
311 accent_glow => 'rgba(74,143,94,0.30)',
312 },
313 {
314 id => 15,
315 slug => 'obsidian',
316 name => 'Obsidian',
317 tagline => 'Near-black with antique gold. The black-tie palette.',
318 bg => '#0a0a0a',
319 bg_2 => '#121212',
320 surface => '#1a1a1a',
321 surface_2 => '#232323',
322 border => '#2e2e2e',
323 border_2 => '#444444',
324 text => '#e8e1cd',
325 text_2 => '#a89b78',
326 text_3 => '#6e6450',
327 accent => '#c8a951',
328 accent_2 => '#d4b962',
329 accent_deep => '#8a7530',
330 accent_glow => 'rgba(200,169,81,0.30)',
331 },
332 {
333 id => 16,
334 slug => 'linen',
335 name => 'Linen',
336 tagline => 'Soft cream with dusty blue. A light, airy, daylight palette.',
337 bg => '#f4f0e8',
338 bg_2 => '#ebe4d6',
339 surface => '#ffffff',
340 surface_2 => '#f4f0e8',
341 border => '#d4cab8',
342 border_2 => '#b3a890',
343 text => '#1f2030',
344 text_2 => '#565d6e',
345 text_3 => '#8a8f9c',
346 accent => '#4a6488',
347 accent_2 => '#6e88ab',
348 accent_deep => '#2c4566',
349 accent_glow => 'rgba(74,100,136,0.20)',
350 },
351
352 # --- Eye-catching palettes ---
353 {
354 id => 17,
355 slug => 'sunset',
356 name => 'Sunset',
357 tagline => 'Hot pink fading into tangerine. Warm, vivid, golden-hour energy.',
358 bg => '#1a0a14',
359 bg_2 => '#25101a',
360 surface => '#321524',
361 surface_2 => '#401d30',
362 border => '#5e2945',
363 border_2 => '#823a5d',
364 text => '#ffe8f0',
365 text_2 => '#d090a5',
366 text_3 => '#8c5d70',
367 accent => '#ff5e8a',
368 accent_2 => '#ff9a3d',
369 accent_deep => '#c4204e',
370 accent_glow => 'rgba(255,94,138,0.40)',
371 },
372 {
373 id => 18,
374 slug => 'bubblegum',
375 name => 'Bubblegum',
376 tagline => 'Hot pink with cool mint. Playful, sweet, kawaii pop.',
377 bg => '#1a0d18',
378 bg_2 => '#221423',
379 surface => '#2d1a30',
380 surface_2 => '#3d2542',
381 border => '#543663',
382 border_2 => '#74508a',
383 text => '#fce5f5',
384 text_2 => '#c590c8',
385 text_3 => '#8a5d8e',
386 accent => '#ff6bb5',
387 accent_2 => '#6dffce',
388 accent_deep => '#c43d83',
389 accent_glow => 'rgba(255,107,181,0.40)',
390 },
391 {
392 id => 19,
393 slug => 'volt',
394 name => 'Volt',
395 tagline => 'Electric yellow on jet black. High-energy, sportsbar-bright.',
396 bg => '#050505',
397 bg_2 => '#0d0d0d',
398 surface => '#161616',
399 surface_2 => '#1f1f1f',
400 border => '#2a2a2a',
401 border_2 => '#3d3d3d',
402 text => '#f0f5e0',
403 text_2 => '#a8b088',
404 text_3 => '#686e55',
405 accent => '#d4ff00',
406 accent_2 => '#a3f000',
407 accent_deep => '#92b800',
408 accent_glow => 'rgba(212,255,0,0.40)',
409 },
410 {
411 id => 20,
412 slug => 'inferno',
413 name => 'Inferno',
414 tagline => 'Deep red bleeding into orange. Hot, urgent, fire-engine intensity.',
415 bg => '#0d0303',
416 bg_2 => '#160606',
417 surface => '#1f0a0a',
418 surface_2 => '#2c1010',
419 border => '#4a1818',
420 border_2 => '#6e2828',
421 text => '#fce8d6',
422 text_2 => '#d49980',
423 text_3 => '#8a5f48',
424 accent => '#ff3300',
425 accent_2 => '#ff8800',
426 accent_deep => '#b22000',
427 accent_glow => 'rgba(255,51,0,0.40)',
428 },
429
430 # --- Wow / bold palettes ---
431 {
432 id => 21,
433 slug => 'vapor',
434 name => 'Vapor',
435 tagline => 'Magenta and cyan on void purple. Synthwave, neon, 80s arcade.',
436 bg => '#0a061a',
437 bg_2 => '#100a25',
438 surface => '#1a1135',
439 surface_2 => '#251d4a',
440 border => '#382c66',
441 border_2 => '#4d3a8c',
442 text => '#ecdef9',
443 text_2 => '#a890d8',
444 text_3 => '#6c5a99',
445 accent => '#ff42db',
446 accent_2 => '#00d8ff',
447 accent_deep => '#b315a8',
448 accent_glow => 'rgba(255,66,219,0.45)',
449 },
450 {
451 id => 22,
452 slug => 'royale',
453 name => 'Royale',
454 tagline => 'Royal purple with gilded gold. Regal, opulent, throne-room luxury.',
455 bg => '#0e081a',
456 bg_2 => '#160e26',
457 surface => '#1f1432',
458 surface_2 => '#2a1c45',
459 border => '#3e2c5e',
460 border_2 => '#5d4385',
461 text => '#f0e8fa',
462 text_2 => '#b89cd6',
463 text_3 => '#7a6190',
464 accent => '#d4af37',
465 accent_2 => '#b884d8',
466 accent_deep => '#8a6f1f',
467 accent_glow => 'rgba(212,175,55,0.30)',
468 },
469 {
470 id => 23,
471 slug => 'acid',
472 name => 'Acid',
473 tagline => 'Lime against magenta. Loud, clashing, deliberately uncomfortable.',
474 bg => '#060808',
475 bg_2 => '#0c1010',
476 surface => '#131818',
477 surface_2 => '#1d2424',
478 border => '#283030',
479 border_2 => '#3a4444',
480 text => '#e8fff0',
481 text_2 => '#88b09c',
482 text_3 => '#4d6a5e',
483 accent => '#c0ff00',
484 accent_2 => '#ff00aa',
485 accent_deep => '#88b800',
486 accent_glow => 'rgba(192,255,0,0.40)',
487 },
488 {
489 id => 24,
490 slug => 'aurora',
491 name => 'Aurora',
492 tagline => 'Emerald green and lavender on midnight sky. True northern-lights.',
493 bg => '#050818',
494 bg_2 => '#0a1024',
495 surface => '#101632',
496 surface_2 => '#181f44',
497 border => '#26305c',
498 border_2 => '#3a4880',
499 text => '#e8f0fa',
500 text_2 => '#9fb3d6',
501 text_3 => '#647590',
502 accent => '#00e88c',
503 accent_2 => '#10b981',
504 accent_deep => '#00a85f',
505 accent_glow => 'rgba(0,232,140,0.40)',
506 },
507
508 # --- Subtle palettes ---
509 {
510 id => 25,
511 slug => 'slate',
512 name => 'Slate',
513 tagline => 'Cool industrial grey with muted steel blue. Quietly confident.',
514 bg => '#0f1318',
515 bg_2 => '#161b22',
516 surface => '#1d242e',
517 surface_2 => '#262e3a',
518 border => '#363f4d',
519 border_2 => '#4a5566',
520 text => '#e6ebf2',
521 text_2 => '#9aa5b3',
522 text_3 => '#5e6878',
523 accent => '#5b8def',
524 accent_2 => '#8fa8d4',
525 accent_deep => '#3a6cc4',
526 accent_glow => 'rgba(91,141,239,0.25)',
527 },
528 {
529 id => 26,
530 slug => 'wheat',
531 name => 'Wheat',
532 tagline => 'Warm wheat and pale gold. Field-at-harvest, calming neutral light tone.',
533 bg => '#f5efe2',
534 bg_2 => '#ebe3d0',
535 surface => '#fdf9ef',
536 surface_2 => '#f0e9d4',
537 border => '#d4c79e',
538 border_2 => '#a89770',
539 text => '#2a2418',
540 text_2 => '#5c5238',
541 text_3 => '#897d5a',
542 accent => '#a8783f',
543 accent_2 => '#c8985c',
544 accent_deep => '#7d5a2c',
545 accent_glow => 'rgba(168,120,63,0.22)',
546 },
547 {
548 id => 27,
549 slug => 'granite',
550 name => 'Granite',
551 tagline => 'Speckled stone grey with a charcoal accent. Architectural, weighty.',
552 bg => '#15171a',
553 bg_2 => '#1d1f23',
554 surface => '#26282d',
555 surface_2 => '#30333a',
556 border => '#3e424a',
557 border_2 => '#555a64',
558 text => '#e4e6ea',
559 text_2 => '#9da3ad',
560 text_3 => '#646b75',
561 accent => '#7a8590',
562 accent_2 => '#a8b3c0',
563 accent_deep => '#525c66',
564 accent_glow => 'rgba(122,133,144,0.30)',
565 },
566 {
567 id => 28,
568 slug => 'mist',
569 name => 'Mist',
570 tagline => 'Soft blue-grey morning. Calm, foggy, contemplative light theme.',
571 bg => '#eef2f6',
572 bg_2 => '#dde5ed',
573 surface => '#ffffff',
574 surface_2 => '#e6ecf4',
575 border => '#c2cdd9',
576 border_2 => '#9caab8',
577 text => '#1d2733',
578 text_2 => '#56616e',
579 text_3 => '#8593a2',
580 accent => '#5882a8',
581 accent_2 => '#7ca0c4',
582 accent_deep => '#3a5e80',
583 accent_glow => 'rgba(88,130,168,0.20)',
584 },
585
586 # --- Eye-catching palettes ---
587 {
588 id => 29,
589 slug => 'mango',
590 name => 'Mango',
591 tagline => 'Ripe mango orange and hot pink. Tropical, fresh-squeezed energy.',
592 bg => '#1a0f0a',
593 bg_2 => '#23150d',
594 surface => '#2e1c12',
595 surface_2 => '#3c241a',
596 border => '#5a3525',
597 border_2 => '#824c34',
598 text => '#ffeed8',
599 text_2 => '#d4a07a',
600 text_3 => '#8c6748',
601 accent => '#ff8a3d',
602 accent_2 => '#ff4d8a',
603 accent_deep => '#c25a18',
604 accent_glow => 'rgba(255,138,61,0.40)',
605 },
606 {
607 id => 30,
608 slug => 'coral',
609 name => 'Coral',
610 tagline => 'Coral pink with peach blush. Warm, friendly, beach-house energy.',
611 bg => '#1a1112',
612 bg_2 => '#23161a',
613 surface => '#301d22',
614 surface_2 => '#3e262d',
615 border => '#5a3942',
616 border_2 => '#7e525d',
617 text => '#ffe5e0',
618 text_2 => '#d49aa0',
619 text_3 => '#8a6068',
620 accent => '#ff7e6b',
621 accent_2 => '#ffb98a',
622 accent_deep => '#c44a3a',
623 accent_glow => 'rgba(255,126,107,0.35)',
624 },
625 {
626 id => 31,
627 slug => 'iris',
628 name => 'Iris',
629 tagline => 'Violet petal and periwinkle. Soft floral, dreamy, garden party.',
630 bg => '#10091e',
631 bg_2 => '#170f2c',
632 surface => '#1e1640',
633 surface_2 => '#272055',
634 border => '#3a2f78',
635 border_2 => '#5040a8',
636 text => '#ece4ff',
637 text_2 => '#b4a8e0',
638 text_3 => '#7e6ea8',
639 accent => '#059669',
640 accent_2 => '#a3aaff',
641 accent_deep => '#6028d4',
642 accent_glow => 'rgba(5,150,105,0.40)',
643 },
644 {
645 id => 32,
646 slug => 'magma',
647 name => 'Magma',
648 tagline => 'Molten orange cracking through black rock. Volcanic, primal heat.',
649 bg => '#0a0606',
650 bg_2 => '#150a08',
651 surface => '#1f0f0c',
652 surface_2 => '#2c1612',
653 border => '#4a2218',
654 border_2 => '#7a3d2a',
655 text => '#fce0d0',
656 text_2 => '#d49680',
657 text_3 => '#8a5d48',
658 accent => '#ff5722',
659 accent_2 => '#ffaa00',
660 accent_deep => '#a82912',
661 accent_glow => 'rgba(255,87,34,0.50)',
662 },
663
664 # --- Wow / specialty palettes ---
665 {
666 id => 33,
667 slug => 'dragon',
668 name => 'Dragon',
669 tagline => 'Emerald scales, ruby flame, antique gold. Three-color heroic fantasy.',
670 bg => '#0a0d0c',
671 bg_2 => '#101513',
672 surface => '#181f1c',
673 surface_2 => '#222a25',
674 border => '#324036',
675 border_2 => '#4d5e44',
676 text => '#f0e8d0',
677 text_2 => '#a8b09a',
678 text_3 => '#6d7565',
679 accent => '#059669',
680 accent_2 => '#dc2626',
681 accent_deep => '#0d8a60',
682 accent_glow => 'rgba(16,185,129,0.40)',
683 },
684 {
685 id => 34,
686 slug => 'frost',
687 name => 'Frost',
688 tagline => 'Icy white-blue with crystal cyan. Glacial, sharp, winter premium.',
689 bg => '#06121e',
690 bg_2 => '#0a1c30',
691 surface => '#10283f',
692 surface_2 => '#163454',
693 border => '#244766',
694 border_2 => '#3a6890',
695 text => '#e8f4ff',
696 text_2 => '#a0c4e0',
697 text_3 => '#6090b0',
698 accent => '#7dd3fc',
699 accent_2 => '#bae6fd',
700 accent_deep => '#0891b2',
701 accent_glow => 'rgba(125,211,252,0.45)',
702 },
703 {
704 id => 35,
705 slug => 'phantom',
706 name => 'Phantom',
707 tagline => 'Dark purple bleeding into ghostly pink-white. Ethereal, dreamlike, occult.',
708 bg => '#0a0612',
709 bg_2 => '#120920',
710 surface => '#1c1030',
711 surface_2 => '#2a1845',
712 border => '#3e2a66',
713 border_2 => '#5a428a',
714 text => '#f8e8ff',
715 text_2 => '#c8a8d4',
716 text_3 => '#8a6e9e',
717 accent => '#f0abfc',
718 accent_2 => '#14b8a6',
719 accent_deep => '#a855f7',
720 accent_glow => 'rgba(240,171,252,0.40)',
721 },
722 {
723 id => 36,
724 slug => 'toxic',
725 name => 'Toxic',
726 tagline => 'Radioactive green and caution yellow. Hazmat-warning, biohazard intense.',
727 bg => '#080a06',
728 bg_2 => '#0e1208',
729 surface => '#161c0c',
730 surface_2 => '#1e2810',
731 border => '#2c3a18',
732 border_2 => '#445824',
733 text => '#ecffd0',
734 text_2 => '#a4c078',
735 text_3 => '#688048',
736 accent => '#84e000',
737 accent_2 => '#fde047',
738 accent_deep => '#5a9000',
739 accent_glow => 'rgba(132,224,0,0.45)',
740 },
741);
742
743#----------------------------------------------------------------------
744# OO interface (so .cgi handlers can do MODS::RePricer::Themes->new)
745#----------------------------------------------------------------------
746sub new { return bless({}, shift) }
747
748# Return the full theme list (array of hashrefs). For the picker UI.
749sub all {
750 return [ map { { %$_ } } @THEMES ]; # shallow copies
751}
752
753# Look up one theme by id. Falls back to theme #1 if id is unknown
754# so the buyer page never renders an "untheamed" storefront.
755sub by_id {
756 my ($self, $id) = @_;
757 $id ||= 0;
758 $id =~ s/[^0-9]//g;
759 foreach my $t (@THEMES) {
760 return { %$t } if $t->{id} == $id;
761 }
762 return { %{ $THEMES[0] } };
763}
764
765# Load a user's custom theme row by primary key. Returns the same
766# hashref shape as the built-in themes so css_vars()/thumbnail_html()
767# work on either source without branching at every call site.
768# Returns undef if the id doesn't exist.
769#
770# Note: DB columns avoid the SQL reserved words `border` and `text` by
771# prefixing with `c` (cborder, cborder_2, ctext, ctext_*). We unmap
772# them back to the canonical theme-hash key names here.
773sub custom_by_id {
774 my ($self, $db, $dbh, $DB, $id) = @_;
775 $id ||= 0; $id =~ s/[^0-9]//g;
776 return undef unless $id;
777 my $row = $db->db_readwrite($dbh, qq~
778 SELECT id, name, bg, bg_2, surface, surface_2,
779 cborder AS border, cborder_2 AS border_2,
780 ctext AS text, ctext_2 AS text_2, ctext_3 AS text_3,
781 accent, accent_2, accent_deep, accent_glow
782 FROM `${DB}`.storefront_custom_themes
783 WHERE id='$id'
784 LIMIT 1
785 ~, $ENV{SCRIPT_NAME}, __LINE__);
786 return undef unless $row && $row->{id};
787 $row->{slug} = 'custom';
788 $row->{tagline} = 'Custom theme';
789 $row->{is_custom} = 1;
790 return $row;
791}
792
793# One-call lookup: given a storefront row, return the theme that should
794# render. If the storefront has a custom_theme_id set, that wins;
795# otherwise fall back to the built-in theme_id; otherwise the default.
796sub resolve_for_storefront {
797 my ($self, $store, $db, $dbh, $DB) = @_;
798 $store ||= {};
799 if ($store->{custom_theme_id} && $db && $dbh) {
800 my $t = $self->custom_by_id($db, $dbh, $DB, $store->{custom_theme_id});
801 return $t if $t;
802 }
803 return $self->by_id($store->{theme_id} || 1);
804}
805
806# Build a tiny mock-storefront HTML thumbnail using only the theme's
807# colors. Shown in the editor's theme picker so a creator can see what
808# their store will look like before they apply the theme. Self-contained
809# inline styles — no extra CSS to load.
810sub thumbnail_html {
811 my ($self, $theme) = @_;
812 $theme ||= $THEMES[0];
813 my $bg = $theme->{bg};
814 my $bg_2 = $theme->{bg_2};
815 my $sf = $theme->{surface};
816 my $bdr = $theme->{border};
817 my $txt = $theme->{text};
818 my $txt_2 = $theme->{text_2};
819 my $a1 = $theme->{accent};
820 my $a2 = $theme->{accent_2};
821 my $grad = "linear-gradient(135deg, $a1 0%, $a2 100%)";
822 return <<"HTML";
823<div style="background:$bg;padding:10px;height:100%;display:flex;flex-direction:column;gap:6px;font-family:system-ui,sans-serif">
824 <div style="background:$bg_2;border-bottom:1px solid $bdr;padding:6px 8px;display:flex;align-items:center;gap:6px;border-radius:4px">
825 <span style="width:16px;height:16px;border-radius:4px;background:$grad;flex-shrink:0"></span>
826 <span style="height:6px;width:38px;background:$txt;opacity:0.85;border-radius:2px"></span>
827 <span style="margin-left:auto;display:flex;gap:5px">
828 <span style="height:4px;width:14px;background:$txt_2;opacity:0.6;border-radius:1px"></span>
829 <span style="height:4px;width:14px;background:$txt_2;opacity:0.6;border-radius:1px"></span>
830 <span style="height:4px;width:14px;background:$txt_2;opacity:0.6;border-radius:1px"></span>
831 </span>
832 </div>
833 <div style="display:flex;flex-direction:column;gap:4px;padding:2px 4px">
834 <span style="height:7px;width:70%;background:$txt;border-radius:2px"></span>
835 <span style="height:7px;width:55%;background:$grad;border-radius:2px"></span>
836 <span style="height:10px;width:46px;background:$grad;border-radius:3px;margin-top:4px"></span>
837 </div>
838 <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:5px;margin-top:auto">
839 <div style="background:$sf;border:1px solid $bdr;border-radius:3px;height:30px;position:relative">
840 <span style="position:absolute;bottom:3px;left:3px;height:3px;width:60%;background:$txt;opacity:0.7;border-radius:1px"></span>
841 </div>
842 <div style="background:$sf;border:1px solid $bdr;border-radius:3px;height:30px;position:relative">
843 <span style="position:absolute;bottom:3px;left:3px;height:3px;width:60%;background:$txt;opacity:0.7;border-radius:1px"></span>
844 </div>
845 <div style="background:$sf;border:1px solid $bdr;border-radius:3px;height:30px;position:relative">
846 <span style="position:absolute;bottom:3px;left:3px;height:3px;width:60%;background:$txt;opacity:0.7;border-radius:1px"></span>
847 </div>
848 </div>
849</div>
850HTML
851}
852
853# Build a CSS variable block ready to drop into a <style> tag.
854# Used by store.cgi to override the page's :root vars per storefront.
855sub css_vars {
856 my ($self, $theme) = @_;
857 $theme ||= $THEMES[0];
858 return join("\n",
859 " --col-bg: $theme->{bg};",
860 " --col-bg-2: $theme->{bg_2};",
861 " --col-surface-1: $theme->{surface};",
862 " --col-surface-2: $theme->{surface_2};",
863 " --col-surface-3: $theme->{surface_2};",
864 " --col-border: $theme->{border};",
865 " --col-border-2: $theme->{border_2};",
866 " --col-text: $theme->{text};",
867 " --col-text-2: $theme->{text_2};",
868 " --col-text-3: $theme->{text_3};",
869 " --col-text-dim: $theme->{text_3};",
870 " --col-accent: $theme->{accent};",
871 " --col-accent-deep: $theme->{accent_deep};",
872 " --col-accent-bright:$theme->{accent_2};",
873 " --col-accent-glow: $theme->{accent_glow};",
874 );
875}
876
8771;
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help