v0.319.0: the app page in panels, the login in one place, a password the box never had is said in words
gates / gates (push) Successful in 52s

- style A (operator 2026-10-16): hero, tab bar and every section are panels on --bg-1, one width, 16px apart;
  the install page's form groups use the same rule; the settings tab's 700px inner wrapper is gone
- „Belépés az alkalmazásba": name + password side by side, fetched on demand (R-254, R-709); pairing in app_login.go
- the empty-value rule: no stored value -> a sentence, never an eye; page and reveal endpoint share storedValuePresent
- „Cím és kulcsok" is rows (no Domain input, no disabled storage select, no install form); hint under the title
- tests red-proved: app_page_tuning_test.go (4); 36 app-page parity fixtures re-captured, 4 new; install fixtures unchanged

Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-16 12:12:06 +02:00
parent 8d44416610
commit d170a2aecf
58 changed files with 6046 additions and 1776 deletions
@@ -218,7 +218,7 @@
<div class="deploy-container">
<div class="app-settings-tab">
<div class="flash flash-success">A mentés sikeresen elkészült.</div>
<div class="flash flash-error">A művelet most nem sikerült.</div>
@@ -240,6 +240,30 @@
<div class="app-sections">
<div class="app-section" id="app-login-panel" data-login-panel="1">
<h3>Belépés az alkalmazásba</h3>
<p>Az első bejelentkezéshez. Ha az alkalmazásban megváltoztatod a jelszót, itt a régi marad.</p>
<div class="app-login-pair">
<div class="app-login-field" data-login-field="ADMIN_USER">
<label class="app-login-label" for="field-ADMIN_USER">Admin név mező</label>
<div class="input-with-button">
<input type="password" id="field-ADMIN_USER" class="form-control" value="" placeholder="••••••••••••" readonly>
<button type="button" class="btn btn-sm btn-outline" data-login-reveal="ADMIN_USER" onclick="revealAutoField('privatebin','ADMIN_USER', this, 'field-ADMIN_USER')">Megjelenítés</button>
</div>
</div>
<div class="app-login-field" data-login-field="ADMIN_PASSWORD">
<label class="app-login-label" for="field-ADMIN_PASSWORD">Admin jelszó mező</label>
<div class="input-with-button">
<input type="password" id="field-ADMIN_PASSWORD" class="form-control" value="" placeholder="••••••••••••" readonly>
<button type="button" class="btn btn-sm btn-outline" data-login-reveal="ADMIN_PASSWORD" onclick="revealAutoField('privatebin','ADMIN_PASSWORD', this, 'field-ADMIN_PASSWORD')">Megjelenítés</button>
</div>
</div>
</div>
</div>
<div class="app-section">
@@ -251,8 +275,8 @@
<div class="deploy-storage-info">
<h4>Adattárolás</h4>
<div class="app-section">
<h3>Adattárolás</h3>
<div class="settings-grid">
<div class="settings-row">
<span class="settings-label">Tárhely</span>
@@ -266,7 +290,7 @@
<div class="app-optional-config">
<div class="app-section">
<h3>Integrációk</h3>
<p class="config-group-desc">
Más telepített alkalmazásokkal való összekapcsolás. Az integráció automatikusan felfüggesztődik, ha bármelyik alkalmazás leáll, és újraaktiválódik indításkor.
@@ -390,7 +414,7 @@
<div class="app-optional-config">
<div class="app-section">
<h3>Földrajzi korlátozás</h3>
<p class="config-group-desc">
Az alkalmazás egyéni országkorlátozás nélkül a globális beállítást követi.
@@ -525,7 +549,7 @@
<div class="app-optional-config">
<div class="app-section">
<h3>Opcionális beállítások</h3>
<div class="config-group">
@@ -624,7 +648,7 @@
<div class="app-optional-config">
<div class="app-section">
<h3>Email-küldés</h3>
<p class="config-group-desc">
Ez az alkalmazás tud emailt küldeni (pl. jelszó-visszaállítás, meghívók) a Felhom-on keresztül,
@@ -644,184 +668,33 @@
</form>
</div>
<div class="app-section">
<div class="app-section" data-address-keys="1">
<h3>Cím és kulcsok</h3>
<p class="app-field-hint" data-readonly-hint="1">Ezek telepítéskor jöttek létre, és nem módosíthatók.</p>
<div class="app-field-row">
<div class="app-field-label">Cím</div>
<div class="app-field-value" data-app-address-row="1">paste.example.hu</div>
</div>
<form id="deploy-form" class="deploy-form">
<div class="form-section">
<h4>Automatikusan generált értékek</h4>
<p class="form-section-desc">Ezek az értékek automatikusan jöttek létre a telepítéskor.</p>
<div class="form-group form-group-auto">
<label>Titkos kulcs érték <span class="auto-generated-badge"><svg class="ico ico-sm"><use href="#i-check"/></svg> Automatikusan generálva</span></label>
<div class="input-with-button">
<input type="password" id="auto-field-SECRET_KEY" class="form-control" value="" placeholder="••••••••••••" readonly>
<button type="button" class="btn btn-sm btn-outline" onclick="revealAutoField('privatebin','SECRET_KEY', this)">Megjelenítés</button>
</div>
</div>
<div class="form-group form-group-auto">
<label>Adatbázis neve itt </label>
<input type="text" id="auto-field-DB_NAME" class="form-control" value="privatebin_db" readonly>
</div>
<div class="form-group form-group-auto">
<label>Üres mező értéke </label>
</div>
<div class="app-field-row">
<div class="app-field-label">Tárhely</div>
<div class="app-field-value" data-app-storage-row="1">/mnt/gone (nem elérhető)</div>
</div>
<div class="form-section">
<h4>Beállítások</h4>
<div class="form-group">
<label for="field-LANG_SEL">
Felület nyelve
</label>
<select id="field-LANG_SEL" name="LANG_SEL" class="form-control"
disabled>
<option value="hu">Magyar nyelv</option>
</select>
<div class="app-field-row" data-setting-row="SECRET_KEY">
<div class="app-field-label">Titkos kulcs érték</div>
<div class="app-field-value input-with-button">
<input type="password" id="auto-field-SECRET_KEY" class="form-control" value="" placeholder="••••••••••••" readonly aria-label="Titkos kulcs érték">
<button type="button" class="btn btn-sm btn-outline" onclick="revealAutoField('privatebin','SECRET_KEY', this)">Megjelenítés</button>
</div>
<div class="form-group">
<label for="field-ADMIN_PASSWORD">
Admin jelszó mező
<span class="required">*</span>
<span class="locked-hint">telepítés után nem módosítható</span>
</label>
<div class="input-with-button">
<input type="password" id="field-ADMIN_PASSWORD" class="form-control" value="" placeholder="••••••••••••" disabled>
<button type="button" class="btn btn-sm btn-outline pw-toggle-btn"
onclick="revealPasswordField('privatebin', 'ADMIN_PASSWORD', this)"
title="Megjelenítés">&#128065;</button>
</div>
<span class="form-hint">Telepítéskor beállított kezdeti jelszó — ha az alkalmazásban megváltoztattad, az itt nem frissül.</span>
</div>
<div class="form-group">
<label for="field-FLAG">
Kapcsoló mező itt
</label>
<label class="toggle">
<input type="checkbox" id="field-FLAG" name="FLAG" value="true"
disabled>
<span class="toggle-label">Igen</span>
</label>
<span class="form-hint">Egy kapcsoló leírása</span>
</div>
<div class="form-group">
<label for="field-HDD_PATH">
Adatok helye itt
<span class="required">*</span>
</label>
<input type="text" id="field-HDD_PATH" name="HDD_PATH"
class="form-control" value=""
placeholder="/mnt/valahol"
required
disabled>
<span class="form-hint" style="color:var(--warn)">Nincs regisztrált adattároló — add meg kézzel az útvonalat</span>
</div>
<div class="form-group">
<label for="field-NOTE">
Megjegyzés mező
</label>
<input type="text" id="field-NOTE" name="NOTE"
class="form-control" value=""
placeholder="Írj ide valamit"
disabled>
</div>
</div>
</form>
<p class="app-field-hint" data-readonly-hint="1">Ezek telepítéskor jöttek létre, és nem módosíthatók.</p>
<div class="app-field-row" data-setting-row="LANG_SEL">
<div class="app-field-label">Felület nyelve</div>
<div class="app-field-value">Magyar nyelv</div>
</div>
</div>
</div>
@@ -859,46 +732,9 @@ function appAfterStart(btn, slug, envVar) {
</script>
<script>
function checkStorageSpace(sel) {
var opt = sel.options[sel.selectedIndex];
var warn = document.getElementById('storage-space-warn');
if (!warn) return;
var freePct = parseFloat(opt.getAttribute('data-free-percent') || '100');
warn.style.display = freePct < 20 ? 'block' : 'none';
}
document.addEventListener('DOMContentLoaded', function() {
var sel = document.querySelector('select[onchange="checkStorageSpace(this)"]');
if (sel) checkStorageSpace(sel);
});
function revealPasswordField(stackName, envVar, btn) {
var el = document.getElementById('field-' + envVar);
if (!el) return;
if (btn.dataset.shown === '1') {
el.value = '';
el.type = 'password';
btn.dataset.shown = '';
return;
}
btn.disabled = true;
fetch('/stacks/' + encodeURIComponent(stackName) + '/auto-field/reveal', {
method: 'POST',
headers: Object.assign({'Content-Type': 'application/x-www-form-urlencoded'}, csrfHeaders()),
credentials: 'same-origin',
body: 'env_var=' + encodeURIComponent(envVar)
}).then(function (r) { return r.json(); }).then(function (j) {
btn.disabled = false;
if (!j.ok) { showAlert(j.error || 'A lekérés nem sikerült.'); return; }
el.value = j.data.value;
el.type = 'text';
el.dataset.revealed = '1';
btn.dataset.shown = '1';
}).catch(function () { btn.disabled = false; showAlert('A lekérés nem sikerült.'); });
}
function revealAutoField(stackName, envVar, btn, elId) {
var el = document.getElementById(elId || ('auto-field-' + envVar));
if (!el) return;