Add Docker deployment and per-player secret-link viewers.

Each player gets an isolated SQLite viewer via a unique URL without login, with landing page warnings to save the link and compose-based hosting for sharing with others.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-19 16:06:13 +02:00
parent fbc2deec45
commit f51f166fa1
14 changed files with 589 additions and 53 deletions
+11
View File
@@ -7,6 +7,7 @@
<link rel="stylesheet" href="/static/style.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js" defer></script>
<script src="/static/i18n.js" defer></script>
<script>window.VIEWER_ID = {{ viewer_id|tojson }};</script>
<script src="/static/app.js" defer></script>
</head>
<body>
@@ -46,6 +47,16 @@
<main class="main">
<header class="topbar">
<div id="viewer-link-banner" class="viewer-banner" hidden>
<div class="viewer-banner-text">
<strong data-i18n="viewer.linkTitle">Your personal link</strong>
<p class="viewer-banner-warning" data-i18n="viewer.linkWarning">
Save this link there is no login. Without it, your data is lost.
</p>
<code id="viewer-link-url" class="viewer-link-url"></code>
</div>
<button type="button" class="viewer-copy-btn" id="viewer-copy-link" data-i18n="viewer.copyLink">Copy link</button>
</div>
<div id="import-report" class="import-report" hidden></div>
<div id="character-header" class="character-header">
<span class="loading" data-i18n="app.loading">Loading save…</span>
+56
View File
@@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Idle Fantasy Viewer</title>
<link rel="stylesheet" href="/static/style.css">
<script src="/static/i18n.js" defer></script>
<script src="/static/landing.js" defer></script>
</head>
<body class="landing-page">
<main class="landing-card">
<div class="brand landing-brand">
<span class="brand-icon"></span>
<div>
<h1 data-i18n="app.title">Idle Fantasy</h1>
<p class="subtitle" data-i18n="app.subtitle">Save Viewer</p>
</div>
</div>
<p class="landing-lead" data-i18n="viewer.landingLead">
Create your personal save viewer. No account just a private link to your data.
</p>
<ul class="landing-features">
<li data-i18n="viewer.featureDashboard">Skills, inventory, quests and history</li>
<li data-i18n="viewer.featureUpload">Import backups in the browser</li>
<li data-i18n="viewer.featurePrivate">Your data stays in your viewer only</li>
</ul>
<div class="landing-actions">
<button type="button" class="upload-btn landing-create" id="create-viewer" data-i18n="viewer.create">
Create my viewer
</button>
<p class="landing-hint" id="create-status" hidden></p>
</div>
<div class="landing-warning">
<strong data-i18n="viewer.warningTitle">Important</strong>
<p data-i18n="viewer.warningBody">
There is no login. Your viewer is only accessible via its unique link.
Bookmark or save the link without it, your data cannot be recovered.
</p>
</div>
<label class="lang-label landing-lang" for="locale-select">
<span data-i18n="settings.language">Language</span>
<select id="locale-select" class="select-input lang-select">
<option value="auto" data-i18n="settings.langAuto">Auto (browser)</option>
<option value="en" data-i18n="settings.langEn">English</option>
<option value="de" data-i18n="settings.langDe">Deutsch</option>
</select>
</label>
</main>
</body>
</html>