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

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

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

Added
+234
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 126eb7402907
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
15 /* ===== TaskForge-style help popup (CSS :target -- no JS needed) ===== */
16 .ac-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
17 .ac-section-head h2 { margin: 0; }
18 .ac-sec-anchor { position: relative; top: -90px; height: 0; width: 0; overflow: hidden; }
19 html { scroll-behavior: smooth; }
20 a.ac-help-toggle { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%; background: rgba(59,130,246,0.16); color: #93c5fd; font-weight: 700; font-size: 13px; cursor: pointer; border: 1px solid rgba(59,130,246,0.36); transition: all 0.16s ease; position: relative; text-decoration: none; }
21 a.ac-help-toggle:hover { background: rgba(59,130,246,0.32); color: #fff; transform: scale(1.08); text-decoration: none; }
22 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(59,130,246,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; }
23 a.ac-help-toggle:hover .ac-help-tip { opacity: 1; }
24
25 .ac-help-content { position: fixed; inset: 0; z-index: 200; display: none; align-items: center; justify-content: center; padding: 24px; }
26 .ac-help-content:target { display: flex; }
27 a.ac-help-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.72); backdrop-filter: blur(4px); display: block; }
28 .ac-help-modal { position: relative; z-index: 1; background: linear-gradient(180deg, #060a14 0%, #03060d 100%); border: 1px solid rgba(59,130,246,0.32); border-radius: 16px; box-shadow: 0 32px 80px rgba(0,0,0,0.8), 0 0 40px rgba(59,130,246,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); }
29 @keyframes ac-pop { from { opacity: 0; transform: scale(0.94) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } }
30 .ac-help-modal-head { position: relative; padding: 22px 24px 18px; display: flex; align-items: baseline; justify-content: space-between; gap: 16px; flex-wrap: wrap;
31 background:
32 radial-gradient(ellipse 140% 90% at 0% 0%, rgba(59,130,246,0.32) 0%, transparent 65%),
33 radial-gradient(ellipse 100% 80% at 100% 40%, rgba(125,211,252,0.14) 0%, transparent 60%),
34 linear-gradient(180deg, #0c1428 0%, #06091a 100%);
35 }
36 .ac-help-modal-head::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 3px; background: linear-gradient(90deg, #0c2554 0%, #3b82f6 38%, #93c5fd 60%, #3b82f6 80%, #0c2554 100%); box-shadow: 0 0 14px rgba(147,197,253,0.55), 0 0 28px rgba(59,130,246,0.32); }
37 .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(147,197,253,0.32); border: 0; }
38 .ac-help-modal-head .ac-sum { color: #93c5fd; font-size: 12px; margin-top: 6px; font-weight: 600; letter-spacing: 0.02em; }
39 a.ac-help-close { background: rgba(0,0,0,0.32); color: #fff; border: 1px solid rgba(147,197,253,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; }
40 a.ac-help-close:hover { background: rgba(59,130,246,0.32); color: #fff; border-color: rgba(59,130,246,0.6); transform: scale(1.06); }
41 .ac-help-modal-body { padding: 18px 24px 22px; overflow-y: auto; color: #cfd6e0; font-size: 13px; line-height: 1.65; }
42 .ac-help-modal-body p { margin: 0 0 12px; }
43 .ac-help-modal-body p:last-child { margin-bottom: 0; }
44 .ac-help-modal-body code { background: rgba(255,255,255,0.06); padding: 1px 6px; border-radius: 4px; font-size: 11.5px; color: #93c5fd; }
45 .ac-help-modal-body strong { color: #fff; }
46 .ac-help-modal-body em { color: #cbd5e1; font-style: italic; }
47 .ac-flash {
48 border-radius: 8px; padding: 10px 14px; font-size: 13px;
49 margin-bottom: 16px;
50 }
51 .ac-flash.ok { background: rgba(34,197,94,0.15); color: #4ade80; border: 1px solid rgba(34,197,94,0.35); }
52 .ac-flash.danger { background: rgba(239,68,68,0.15); color: #fca5a5; border: 1px solid rgba(239,68,68,0.35); }
53 .ac-group {
54 background: var(--col-surface-1);
55 border: 1px solid var(--col-border);
56 border-radius: 12px;
57 padding: 18px 20px;
58 margin-bottom: 18px;
59 }
60 .ac-group h2 {
61 font-size: 16px; font-weight: 600; color: var(--col-text);
62 margin: 0 0 4px;
63 }
64 .ac-group p.intro {
65 color: var(--col-text-2); font-size: 12.5px; line-height: 1.55;
66 margin: 0 0 14px;
67 }
68 .ac-field {
69 display: grid; grid-template-columns: 220px 1fr 80px;
70 gap: 14px; align-items: center;
71 padding: 10px 0; border-top: 1px solid var(--col-border);
72 }
73 .ac-field:first-of-type { border-top: 0; }
74 .ac-field label { font-size: 13px; color: var(--col-text); }
75 .ac-field label .k {
76 display: block; font-size: 11px; color: var(--col-text-3);
77 font-family: var(--font-mono, monospace); margin-top: 2px;
78 }
79 .ac-field input[type=text],
80 .ac-field input[type=password] {
81 width: 100%; padding: 8px 10px; border-radius: 6px;
82 background: #0f172a; border: 1px solid var(--col-border);
83 color: #fff; font-family: var(--font-mono, monospace); font-size: 13px;
84 }
85 .ac-field .desc {
86 grid-column: 2 / 3;
87 font-size: 11.5px; line-height: 1.55;
88 color: var(--col-text-3);
89 margin-top: 6px;
90 }
91 .ac-intro {
92 background: rgba(59,130,246,0.08);
93 border: 1px solid rgba(59,130,246,0.25);
94 border-radius: 10px;
95 padding: 14px 18px;
96 margin-bottom: 20px;
97 color: var(--col-text-2);
98 font-size: 12.5px;
99 line-height: 1.65;
100 }
101 .ac-intro h3 {
102 font-size: 13px; color: #93c5fd;
103 margin: 0 0 6px;
104 text-transform: uppercase; letter-spacing: 1.5px; font-weight: 700;
105 }
106 .ac-intro ul { margin: 6px 0 0 16px; padding: 0; }
107 .ac-intro ul li { margin: 3px 0; }
108 .ac-intro code {
109 background: rgba(15,23,42,0.6); padding: 1px 6px; border-radius: 4px;
110 font-family: var(--font-mono, monospace); font-size: 11.5px; color: #fde68a;
111 }
112 .ac-pill {
113 display: inline-block; font-size: 10.5px; font-weight: 700;
114 padding: 3px 8px; border-radius: 5px; letter-spacing: 1px; text-transform: uppercase;
115 }
116 .ac-pill.set { background: rgba(34,197,94,0.18); color: #86efac; }
117 .ac-pill.empty { background: rgba(148,163,184,0.18); color: #cbd5e1; }
118 .ac-pill.src-db { background: rgba(124,58,237,0.18); color: #c4b5fd; }
119 .ac-pill.src-file { background: rgba(251,191,36,0.18); color: #fde68a; }
120 .ac-pill.src-default { background: rgba(148,163,184,0.18); color: #cbd5e1; }
121 .ac-codebox {
122 background: var(--col-surface-1); border: 1px solid var(--col-border);
123 border-radius: 12px; padding: 14px 18px; margin-top: 8px;
124 }
125 .ac-codebox h2 { font-size: 14px; color: var(--col-text); margin: 0 0 8px; }
126 .ac-codebox table { width: 100%; border-collapse: collapse; }
127 .ac-codebox td {
128 font-size: 12.5px; color: var(--col-text-2);
129 padding: 6px 8px; border-top: 1px solid var(--col-border);
130 vertical-align: top;
131 }
132 .ac-codebox td.k {
133 font-family: var(--font-mono, monospace); color: #fff; width: 220px;
134 }
135 .ac-actions {
136 display: flex; justify-content: flex-end; gap: 10px; margin: 4px 0 20px;
137 }
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/WebSTLs/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/WebSTLs/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 [loop:@loop1.rows]
177 <div class="ac-field">
178 <label>
179 $loop2.label
180 <span class="k">$loop2.key</span>
181 </label>
182 <div>
183 [if:$loop2.secret]
184 <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">
185 [/if]
186 [if:!$loop2.secret]
187 <input type="text" name="cfg_$loop2.key" value="$loop2.value" autocomplete="off">
188 [/if]
189 <div class="desc">$loop2.description</div>
190 </div>
191 <div style="text-align:right">
192 [if:$loop2.is_set]<span class="ac-pill set">Set</span>[/if]
193 [if:!$loop2.is_set]<span class="ac-pill empty">Empty</span>[/if]
194 <div style="margin-top:4px"><span class="ac-pill src-$loop2.source">$loop2.source</span></div>
195 </div>
196 </div>
197 [/loop]
198
199 [if:$loop1.has_help]
200 <div class="ac-help-content" id="ac-help-$loop1.slug">
201 <a class="ac-help-backdrop" href="#sec-$loop1.slug" aria-label="Close help"></a>
202 <div class="ac-help-modal" role="dialog" aria-modal="true">
203 <div class="ac-help-modal-head">
204 <div>
205 <h2>$loop1.name</h2>
206 <div class="ac-sum">$loop1.help_summary</div>
207 </div>
208 <a href="#sec-$loop1.slug" class="ac-help-close" aria-label="Close">&times;</a>
209 </div>
210 <div class="ac-help-modal-body">$loop1.help_detail</div>
211 </div>
212 </div>
213 [/if]
214 </div>
215 [/loop]
216
217 <div class="ac-actions">
218 <button type="submit" class="btn btn-primary">Save changes</button>
219 </div>
220 </form>
221
222 <div class="ac-codebox">
223 <h2>Lives in code (not editable here)</h2>
224 <table>
225 [loop:@code_only]
226 <tr>
227 <td class="k">$loop1.key</td>
228 <td>$loop1.note</td>
229 </tr>
230 [/loop]
231 </table>
232 </div>
233
234</div>
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help