Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/TEMPLATES/repricer_admin_config.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/TEMPLATES/repricer_admin_config.html

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

Added
+235
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to e9238aec001c
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 Software Configuration (super-admin only)
3 1. Page header + flash
4 2. Each editable group rendered as a card with labeled inputs
5 3. Read-only "Lives in code" reference at the bottom
6 Backed by /admin_config.cgi -> /admin_config_action.cgi.
7 Secret fields are masked in the source server-side (Config.pm
8 returns empty for is_secret rows with a value) and the form
9 shows a "set" pill so the admin knows it's populated.
10===================================================================== -->
11
12<style>
13 .ac-wrap { max-width: 100%; margin: 0; }
14 .ac-flash {
15 border-radius: 8px; padding: 10px 14px; font-size: 13px;
16 margin-bottom: 16px;
17 }
18 .ac-flash.ok { background: rgba(34,197,94,0.15); color: #4ade80; border: 1px solid rgba(34,197,94,0.35); }
19 .ac-flash.danger { background: rgba(239,68,68,0.15); color: #fca5a5; border: 1px solid rgba(239,68,68,0.35); }
20 .ac-group {
21 background: var(--col-surface-1);
22 border: 1px solid var(--col-border);
23 border-radius: 12px;
24 padding: 18px 20px;
25 margin-bottom: 18px;
26 }
27 .ac-group h2 {
28 font-size: 16px; font-weight: 600; color: var(--col-text);
29 margin: 0 0 4px;
30 }
31 .ac-group p.intro {
32 color: var(--col-text-2); font-size: 12.5px; line-height: 1.55;
33 margin: 0 0 14px;
34 }
35 .ac-field {
36 display: grid; grid-template-columns: 220px 1fr 80px;
37 gap: 14px; align-items: center;
38 padding: 10px 0; border-top: 1px solid var(--col-border);
39 }
40 .ac-field:first-of-type { border-top: 0; }
41 .ac-field label { font-size: 13px; color: var(--col-text); }
42 .ac-field label .k {
43 display: block; font-size: 11px; color: var(--col-text-3);
44 font-family: var(--font-mono, monospace); margin-top: 2px;
45 }
46 .ac-field input[type=text],
47 .ac-field input[type=password] {
48 width: 100%; padding: 8px 10px; border-radius: 6px;
49 background: #0f172a; border: 1px solid var(--col-border);
50 color: #fff; font-family: var(--font-mono, monospace); font-size: 13px;
51 }
52 .ac-field .desc {
53 grid-column: 2 / 3;
54 font-size: 11.5px; line-height: 1.55;
55 color: var(--col-text-3);
56 margin-top: 6px;
57 }
58 .ac-intro {
59 background: rgba(5,150,105,0.08);
60 border: 1px solid rgba(5,150,105,0.25);
61 border-radius: 10px;
62 padding: 14px 18px;
63 margin-bottom: 20px;
64 color: var(--col-text-2);
65 font-size: 12.5px;
66 line-height: 1.65;
67 }
68 .ac-intro h3 {
69 font-size: 13px; color: #6ee7b7;
70 margin: 0 0 6px;
71 text-transform: uppercase; letter-spacing: 1.5px; font-weight: 700;
72 }
73 .ac-intro ul { margin: 6px 0 0 16px; padding: 0; }
74 .ac-intro ul li { margin: 3px 0; }
75 .ac-intro code {
76 background: rgba(15,23,42,0.6); padding: 1px 6px; border-radius: 4px;
77 font-family: var(--font-mono, monospace); font-size: 11.5px; color: #fde68a;
78 }
79 .ac-pill {
80 display: inline-block; font-size: 10.5px; font-weight: 700;
81 padding: 3px 8px; border-radius: 999px; letter-spacing: 1px; text-transform: uppercase;
82 }
83 .ac-pill.set { background: rgba(34,197,94,0.18); color: #86efac; }
84 .ac-pill.empty { background: rgba(148,163,184,0.18); color: #cbd5e1; }
85 .ac-pill.src-db { background: rgba(15,118,110,0.18); color: #6ee7b7; }
86 .ac-pill.src-file { background: rgba(251,191,36,0.18); color: #fde68a; }
87 .ac-pill.src-default { background: rgba(148,163,184,0.18); color: #cbd5e1; }
88 .ac-codebox {
89 background: var(--col-surface-1); border: 1px solid var(--col-border);
90 border-radius: 12px; padding: 14px 18px; margin-top: 8px;
91 }
92 .ac-codebox h2 { font-size: 14px; color: var(--col-text); margin: 0 0 8px; }
93 .ac-codebox table { width: 100%; border-collapse: collapse; }
94 .ac-codebox td {
95 font-size: 12.5px; color: var(--col-text-2);
96 padding: 6px 8px; border-top: 1px solid var(--col-border);
97 vertical-align: top;
98 }
99 .ac-codebox td.k {
100 font-family: var(--font-mono, monospace); color: #fff; width: 220px;
101 }
102 .ac-actions {
103 display: flex; justify-content: flex-end; gap: 10px; margin: 4px 0 20px;
104 }
105
106
107 /* Help popup (CSS :target -- no JS needed) */
108 .ac-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
109 .ac-section-head h2 { margin: 0; }
110 .ac-sec-anchor { position: relative; top: -90px; height: 0; width: 0; overflow: hidden; }
111 html { scroll-behavior: smooth; }
112 a.ac-help-toggle { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(16,185,129,0.16); color: rgb(110,231,183); font-weight: 700; font-size: 13px; cursor: pointer; border: 1px solid rgba(16,185,129,0.36); transition: all 0.16s ease; position: relative; text-decoration: none; }
113 a.ac-help-toggle:hover { background: rgba(16,185,129,0.32); color: #fff; transform: scale(1.08); text-decoration: none; }
114 a.ac-help-toggle .ac-help-tip { position: absolute; right: calc(100% + 10px); top: 50%; transform: translateY(-50%); padding: 8px 12px; background: rgba(8,12,20,0.98); border: 1px solid rgba(16,185,129,0.4); border-radius: 8px; color: #cfd6e0; font-size: 12px; font-weight: 400; white-space: nowrap; opacity: 0; box-shadow: 0 10px 24px rgba(0,0,0,0.5); transition: opacity 0.16s ease; pointer-events: none; }
115 a.ac-help-toggle:hover .ac-help-tip { opacity: 1; }
116 .ac-help-content { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; padding: 24px; }
117 .ac-help-content:target { display: flex; }
118 a.ac-help-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.72); backdrop-filter: blur(4px); display: block; }
119 .ac-help-modal { position: relative; z-index: 1; background: linear-gradient(180deg, #031310 0%, #020806 100%); border: 1px solid rgba(16,185,129,0.32); border-radius: 16px; box-shadow: 0 32px 80px rgba(0,0,0,0.8), 0 0 40px rgba(16,185,129,0.18); max-width: 640px; width: 100%; max-height: 85vh; overflow: hidden; display: flex; flex-direction: column; animation: ac-pop 0.22s cubic-bezier(.4,0,.2,1); }
120 @keyframes ac-pop { from { opacity: 0; transform: scale(0.94) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } }
121 .ac-help-modal-head { position: relative; padding: 22px 24px 18px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap;
122 background:
123 radial-gradient(ellipse 140% 90% at 0% 0%, rgba(16,185,129,0.32) 0%, transparent 65%),
124 radial-gradient(ellipse 100% 80% at 100% 40%, rgba(167,243,208,0.14) 0%, transparent 60%),
125 linear-gradient(180deg, #05201a 0%, #020806 100%);
126 }
127 .ac-help-modal-head::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: linear-gradient(90deg, rgb(6,78,59) 0%, rgb(16,185,129) 38%, rgb(110,231,183) 60%, rgb(16,185,129) 80%, rgb(6,78,59) 100%); box-shadow: 0 0 14px rgba(110,231,183,0.55), 0 0 28px rgba(16,185,129,0.32); }
128 .ac-help-modal-head h2 { margin: 0; color: #fff; font-size: 22px; font-weight: 700; letter-spacing: -0.01em; text-shadow: 0 2px 14px rgba(110,231,183,0.32); border: 0; }
129 .ac-help-modal-head .ac-sum { color: rgb(110,231,183); font-size: 12px; margin-top: 6px; font-weight: 600; letter-spacing: 0.02em; }
130 a.ac-help-close { background: rgba(0,0,0,0.32); color: #fff; border: 1px solid rgba(110,231,183,0.32); width: 32px; height: 32px; border-radius: 8px; font-size: 18px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; flex-shrink: 0; transition: all 0.15s ease; }
131 a.ac-help-close:hover { background: rgba(16,185,129,0.32); color: #fff; border-color: rgba(16,185,129,0.6); transform: scale(1.06); }
132 .ac-help-modal-body { padding: 18px 24px 22px; overflow-y: auto; color: #cfd6e0; font-size: 13px; line-height: 1.65; }
133 .ac-help-modal-body p { margin: 0 0 12px; }
134 .ac-help-modal-body p:last-child { margin-bottom: 0; }
135 .ac-help-modal-body code { background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 4px; font-size: 11.5px; color: rgb(110,231,183); }
136 .ac-help-modal-body strong { color: #fff; }
137 .ac-help-modal-body em { color: #cbd5e1; font-style: italic; }
138</style>
139
140<div class="ac-wrap">
141
142 <div style="margin-bottom:14px">
143 <h1 style="font-size:22px;color:var(--col-text);margin:0 0 6px">Configuration</h1>
144 <p class="text-sm text-dim" style="margin:0">
145 Edit platform-wide settings. Saved values land in <code>platform_settings</code> and override the hardcoded defaults in <code>MODS/RePricer/Config.pm</code>.
146 </p>
147 </div>
148
149 <div class="ac-intro">
150 <h3>How this page works</h3>
151 Each row below is one platform-wide setting. Paste the value you want, then click <strong>Save changes</strong> at the bottom. Changes take effect immediately on the next page render &mdash; no deploy, no restart.
152 <ul>
153 <li><strong>Source pills</strong> show where each value comes from right now:
154 <span class="ac-pill src-db">db</span> = stored here in <code>platform_settings</code>;
155 <span class="ac-pill src-file">file</span> = read from <code>/private/stripe.conf</code> (legacy bootstrap path);
156 <span class="ac-pill src-default">default</span> = the hardcoded fallback in <code>MODS/RePricer/Config.pm</code>.</li>
157 <li><strong>Secret fields</strong> (Stripe secret key, webhook signing secret) are masked once set &mdash; the actual value is never sent back to the browser. Leave the field blank to keep the existing value; type a new value to replace it.</li>
158 <li><strong>Empty non-secret fields</strong> clear the override, so the lookup falls back to <code>stripe.conf</code> or the hardcoded default. Useful for resetting a field to its built-in value.</li>
159 <li><strong>Stripe section first</strong> &mdash; paste the keys from your Stripe Dashboard there before anything else. Recurring charges and the buyer checkout flow both stay inert until those keys are real (the dashboard ships with <code>pk_test_REPLACE_ME</code> placeholders).</li>
160 </ul>
161 </div>
162
163 [if:$has_flash]
164 <div class="ac-flash $flash_kind">$flash_msg</div>
165 [/if]
166
167 <form method="POST" action="/admin_config_action.cgi">
168
169 [loop:@group_blocks]
170 <div class="ac-sec-anchor" id="sec-$loop1.slug"></div>
171 <div class="ac-group">
172 <div class="ac-section-head">
173 <h2>$loop1.name</h2>
174 [if:$loop1.has_help]<a class="ac-help-toggle" href="#ac-help-$loop1.slug" aria-label="Open help">?<span class="ac-help-tip">$loop1.help_summary &mdash; click for details</span></a>[/if]
175 </div>
176
177 [loop:@loop1.rows]
178 <div class="ac-field">
179 <label>
180 $loop2.label
181 <span class="k">$loop2.key</span>
182 </label>
183 <div>
184 [if:$loop2.secret]
185 <input type="password" name="cfg_$loop2.key" value="" placeholder="[if:$loop2.is_set]Already set &middot;&middot;&middot;&middot; leave blank to keep[/if][if:!$loop2.is_set]Not set[/if]" autocomplete="off">
186 [/if]
187 [if:!$loop2.secret]
188 <input type="text" name="cfg_$loop2.key" value="$loop2.value" autocomplete="off">
189 [/if]
190 <div class="desc">$loop2.description</div>
191 </div>
192 <div style="text-align:right">
193 [if:$loop2.is_set]<span class="ac-pill set">Set</span>[/if]
194 [if:!$loop2.is_set]<span class="ac-pill empty">Empty</span>[/if]
195 <div style="margin-top:4px"><span class="ac-pill src-$loop2.source">$loop2.source</span></div>
196 </div>
197 </div>
198 [/loop]
199
200 [if:$loop1.has_help]
201 <div class="ac-help-content" id="ac-help-$loop1.slug">
202 <a class="ac-help-backdrop" href="#sec-$loop1.slug" aria-label="Close help"></a>
203 <div class="ac-help-modal" role="dialog" aria-modal="true">
204 <div class="ac-help-modal-head">
205 <div>
206 <h2>$loop1.name</h2>
207 <div class="ac-sum">$loop1.help_summary</div>
208 </div>
209 <a href="#sec-$loop1.slug" class="ac-help-close" aria-label="Close">&times;</a>
210 </div>
211 <div class="ac-help-modal-body">$loop1.help_detail</div>
212 </div>
213 </div>
214 [/if]
215 </div>
216 [/loop]
217
218 <div class="ac-actions">
219 <button type="submit" class="btn btn-primary">Save changes</button>
220 </div>
221 </form>
222
223 <div class="ac-codebox">
224 <h2>Lives in code (not editable here)</h2>
225 <table>
226 [loop:@code_only]
227 <tr>
228 <td class="k">$loop1.key</td>
229 <td>$loop1.note</td>
230 </tr>
231 [/loop]
232 </table>
233 </div>
234
235</div>