Diff -- /var/www/vhosts/3dshawn.com/shop.3dshawn.com/MODS/ShopCart/StoreChrome.pm
Diff

/var/www/vhosts/3dshawn.com/shop.3dshawn.com/MODS/ShopCart/StoreChrome.pm

added on local at 2026-07-01 22:09:40

Added
+127
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to c2194c9cc4a4
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::ShopCart::StoreChrome;
2#======================================================================
3# ShopCart - shared storefront header chrome (brand + search + sign in
4# + cart). Used by every buyer-facing page that isn't store.cgi itself
5# (cart.cgi, listing_details.cgi, my_orders.cgi, checkout.cgi, ...).
6#
7# The store.cgi page builds these as tvars its layout templates render
8# inline. The other CGIs don't go through a layout template -- they
9# emit their body directly -- so they prepend the output of
10# header_html(\%opts) to keep one consistent header across every
11# buyer-facing surface.
12#
13# Public surface:
14# $html = MODS::ShopCart::StoreChrome->header_html(\%opts);
15#
16# Required opts:
17# store_id -- numeric storefront id (used in href links)
18# store_name -- display name
19#
20# Optional opts:
21# store_initials -- 1-2 char brand mark text (auto-derived if absent)
22# is_buyer_in -- 1 if a buyer session is active, else 0
23# cart_count -- integer; renders as badge on the Cart button
24# signin_label -- defaults to "Sign in"
25# cart_label -- defaults to "Cart"
26# search_query -- pre-fill text for the search input
27# nav_pages -- arrayref of {href, title}; renders as nav links
28# between the brand and the search bar
29# db, dbh, DB -- pass these (instead of nav_pages) to have the
30# helper query storefront_pages itself
31#======================================================================
32
33use strict;
34use warnings;
35
36sub header_html {
37 my ($class, $opts) = @_;
38 $opts ||= {};
39 my $sid = ($opts->{store_id} // 0) + 0;
40 return '' unless $sid;
41
42 my $name = defined $opts->{store_name} ? $opts->{store_name} : '';
43 my $init = defined $opts->{store_initials} && length $opts->{store_initials}
44 ? $opts->{store_initials}
45 : (length $name ? uc(substr($name, 0, 1)) : '?');
46 my $is_buyer = $opts->{is_buyer_in} ? 1 : 0;
47 my $cart_n = ($opts->{cart_count} // 0) + 0;
48 my $signin = defined $opts->{signin_label} ? $opts->{signin_label} : 'Sign in';
49 my $cartlbl = defined $opts->{cart_label} ? $opts->{cart_label} : 'Cart';
50 my $q = defined $opts->{search_query} ? $opts->{search_query} : '';
51
52 for ($name, $init, $signin, $cartlbl, $q) {
53 $_ = '' unless defined $_;
54 s/&/&amp;/g; s/"/&quot;/g; s/</&lt;/g; s/>/&gt;/g;
55 }
56
57 my $left_action = $is_buyer
58 ? qq~<a href="/my_orders.cgi?id=$sid" class="btn btn-secondary btn-sm">My orders</a>~
59 : qq~<a href="/buyer_login.cgi?id=$sid" class="btn btn-secondary btn-sm">$signin</a>~;
60 my $badge = ($cart_n > 0)
61 ? qq~<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;text-align:center">$cart_n</span>~
62 : '';
63 my $cart_btn = qq~<a href="/cart.cgi?id=$sid" id="we-cart-link" class="btn btn-primary btn-sm" style="position:relative">$cartlbl$badge</a>~;
64
65 # Optional nav links from @nav_pages -- shown between the brand
66 # and the search bar. Home is always first, then the seller's
67 # published pages (with their menu_label override). Identical to
68 # the storefront layout's nav so the header looks the same
69 # everywhere.
70 my @nav_pages;
71 if ($opts->{nav_pages} && ref $opts->{nav_pages} eq 'ARRAY') {
72 @nav_pages = @{ $opts->{nav_pages} };
73 } elsif ($opts->{db} && $opts->{dbh} && $opts->{DB}) {
74 # Auto-fetch from storefront_pages so callers that don't
75 # build their own @nav_pages (cart, checkout, my_orders, ...)
76 # still get menu links.
77 my $sid_safe = $sid + 0;
78 my $DB_safe = $opts->{DB};
79 my @rows = $opts->{db}->db_readwrite_multiple($opts->{dbh}, qq~
80 SELECT slug, title, menu_label
81 FROM `${DB_safe}`.storefront_pages
82 WHERE storefront_id='$sid_safe'
83 AND status='published'
84 AND page_type != 'home'
85 AND show_in_menu = 1
86 ORDER BY page_type ASC, title ASC
87 ~, $ENV{SCRIPT_NAME}, __LINE__);
88 foreach my $p (@rows) {
89 my $slug = $p->{slug} || ''; $slug =~ s/[^a-z0-9\-_]//g;
90 next unless length $slug;
91 my $label = (defined $p->{menu_label} && length $p->{menu_label})
92 ? $p->{menu_label}
93 : ($p->{title} || ucfirst($slug));
94 push @nav_pages, {
95 href => "/store.cgi?id=$sid_safe&page=$slug",
96 title => $label,
97 };
98 }
99 }
100 my $nav_html = qq~<a href="/store.cgi?id=$sid" style="font-size:13px;color:var(--col-text-2,#9aa5b3);font-weight:500;text-decoration:none">Home</a>~;
101 foreach my $np (@nav_pages) {
102 my $href = defined $np->{href} ? $np->{href} : '';
103 my $title = defined $np->{title} ? $np->{title} : '';
104 for ($href, $title) { s/&/&amp;/g; s/"/&quot;/g; s/</&lt;/g; s/>/&gt;/g; }
105 $nav_html .= qq~<a href="$href" style="font-size:13px;color:var(--col-text-2,#9aa5b3);font-weight:500;text-decoration:none">$title</a>~;
106 }
107
108 return qq~
109<header id="store-topbar" style="background:var(--col-bg-2,#161b22);border-bottom:1px solid var(--col-border,#363f4d);padding:14px 28px;display:flex;align-items:center;gap:18px;flex-wrap:wrap;font-family:inherit">
110 <a href="/store.cgi?id=$sid" style="display:flex;align-items:center;gap:12px;text-decoration:none;flex-shrink:0">
111 <div class="brand-mark" style="background:linear-gradient(130deg, var(--col-accent,#0b1f47) 0%, var(--col-accent-bright,#6a90d2) 100%)">$init</div>
112 <span style="font-family:var(--font-display,inherit);font-size:20px;font-weight:700;color:var(--col-text,#e6ebf2)">$name</span>
113 </a>
114 <nav style="display:flex;gap:18px;align-items:center;flex-wrap:wrap">$nav_html</nav>
115 <form action="/store.cgi" method="GET" role="search" style="flex:1;min-width:0;max-width:420px;display:flex;align-items:center;gap:8px;background:var(--col-surface-2,#262e3a);border:1px solid var(--col-border,#363f4d);border-radius:8px;padding:7px 12px;margin:0">
116 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink:0;opacity:0.6;color:var(--col-text-2,#9aa5b3)"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
117 <input type="hidden" name="id" value="$sid">
118 <input type="text" name="q" value="$q" placeholder="Search this store..." autocomplete="off" style="background:none;border:none;outline:none;color:var(--col-text,#e6ebf2);font-size:13px;flex:1;min-width:0;font-family:inherit">
119 </form>
120 <div style="display:inline-flex;gap:8px;align-items:center;margin-left:auto">
121 $left_action
122 $cart_btn
123 </div>
124</header>~;
125}
126
1271;
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help