diff --git a/containers/libreportal/frontend/components/apps/core/css/apps.css b/containers/libreportal/frontend/components/apps/core/css/apps.css index f8f1dd7..3bb1600 100644 --- a/containers/libreportal/frontend/components/apps/core/css/apps.css +++ b/containers/libreportal/frontend/components/apps/core/css/apps.css @@ -686,6 +686,41 @@ color: var(--text-secondary); min-height: 14px; } +/* LAN-only toggle. Row-oriented, unlike .lp-instance-field, so the label sits + beside the box; the checkbox keeps its intrinsic size rather than inheriting + the full-width input rule above. */ +.lp-instance-check { + display: flex; + align-items: center; + gap: 9px; + margin-bottom: 14px; + font-size: 13px; + color: var(--text-primary); + cursor: pointer; +} +.lp-instance-check input { + width: 15px; + height: 15px; + flex: 0 0 auto; + accent-color: var(--accent); + cursor: pointer; +} +.lp-instance-check input:disabled { + cursor: default; +} +.lp-instance-check:has(input:disabled) { + cursor: default; + opacity: 0.75; +} +/* The "no domain configured" note sits between the toggle and the preview line. + .lp-instance-hint carries no bottom margin (it normally hangs under a field + that supplies its own), so without this it butts straight into "Will be served + at" and the two read as one run-on paragraph. */ +.lp-instance-check + .lp-instance-hint { + display: block; + margin: -6px 0 14px; + line-height: 1.45; +} .lp-instance-row { display: flex; gap: 12px; diff --git a/containers/libreportal/frontend/components/apps/core/js/instance-manager.js b/containers/libreportal/frontend/components/apps/core/js/instance-manager.js index 8fa6b51..e29ba2e 100644 --- a/containers/libreportal/frontend/components/apps/core/js/instance-manager.js +++ b/containers/libreportal/frontend/components/apps/core/js/instance-manager.js @@ -61,9 +61,14 @@ class InstanceManager { const title = this._typeTitle(typeSlug); this.domains = await this._loadDomains(); - const domainOptions = this.domains.length + // With no CFG_DOMAIN_n set, a subdomain has nothing to attach to — the backend + // would stamp Host(`sub.`) and an unreachable APP_URL. So the modal drops to + // LAN-only and locks the choice, matching what initializeAppVariables enforces + // server-side. Presenting a domain picker here would have been a lie. + const hasDomains = this.domains.length > 0; + const domainOptions = hasDomains ? this.domains.map(d => ``).join('') - : ''; + : ''; const overlay = document.createElement('div'); overlay.id = 'lp-instance-modal'; @@ -74,7 +79,7 @@ class InstanceManager {

New ${this._esc(title)} instance

-

A fully isolated second copy — its own data, database, subdomain, backups and update cadence.

+

A fully isolated second copy — its own data, database, ports, backups and update cadence.

-
+ + ${hasDomains ? '' : 'No domain is configured, so instances are LAN-only. Add one in Admin → Config to route them on a subdomain.'} + +