feat: add in-app release notes and what's new dialog
This commit is contained in:
@@ -57,6 +57,13 @@
|
||||
</p>
|
||||
<a href="{{ url_for('user_manual') }}">Open User Manual</a>
|
||||
</article>
|
||||
<article class="help-card">
|
||||
<h2>Recent Changes</h2>
|
||||
<p>
|
||||
Compact release notes for relevant user-facing changes in RollCalc.
|
||||
</p>
|
||||
<a href="{{ url_for('recent_changes') }}">Open Recent Changes</a>
|
||||
</article>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -146,6 +146,59 @@
|
||||
background: #b8c7bf;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.whats-new-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
background: rgba(20, 28, 34, 0.55);
|
||||
}
|
||||
.whats-new-overlay.is-hidden { display: none; }
|
||||
.whats-new-dialog {
|
||||
width: min(520px, 100%);
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.24);
|
||||
overflow: hidden;
|
||||
}
|
||||
.whats-new-header {
|
||||
padding: 16px 20px;
|
||||
background: #1F5438;
|
||||
color: #fff;
|
||||
}
|
||||
.whats-new-header h2 { font-size: 18px; margin: 0 0 4px; }
|
||||
.whats-new-version { font-size: 12px; opacity: 0.88; }
|
||||
.whats-new-content {
|
||||
padding: 18px 20px 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
}
|
||||
.whats-new-content ul { margin: 8px 0 0 20px; }
|
||||
.whats-new-content li { margin-bottom: 5px; }
|
||||
.whats-new-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding: 16px 20px 18px;
|
||||
border-top: 1px solid #e0e8f0;
|
||||
background: #f8fafa;
|
||||
}
|
||||
.whats-new-btn {
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
padding: 9px 14px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
.whats-new-btn-primary { background: #2BAC70; color: #fff; }
|
||||
.whats-new-btn-primary:hover { background: #1F5438; }
|
||||
.whats-new-btn-secondary { background: #fff; color: #1F5438; border: 1px solid #a8c8ba; }
|
||||
.whats-new-btn-secondary:hover { background: #eef4f1; }
|
||||
|
||||
/* ============================================
|
||||
LOAD OPTIMIZER STYLES
|
||||
@@ -453,6 +506,8 @@
|
||||
@media (max-width: 768px) {
|
||||
.header { padding: 18px 16px; }
|
||||
.header-inner { align-items: flex-start; }
|
||||
.whats-new-actions { flex-direction: column; }
|
||||
.whats-new-btn { width: 100%; }
|
||||
.lo-accordion-header h3 { font-size: 14px; }
|
||||
.lo-preset-buttons { flex-direction: column; }
|
||||
.lo-preset-btn { width: 100%; }
|
||||
@@ -496,13 +551,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="whats-new-overlay is-hidden" id="whatsNewOverlay" role="dialog" aria-modal="true" aria-labelledby="whatsNewTitle">
|
||||
<div class="whats-new-dialog">
|
||||
<div class="whats-new-header">
|
||||
<h2 id="whatsNewTitle">What’s New</h2>
|
||||
<div class="whats-new-version">Version: <span id="whatsNewVersion">–</span></div>
|
||||
</div>
|
||||
<div class="whats-new-content">
|
||||
<ul id="whatsNewList"></ul>
|
||||
</div>
|
||||
<div class="whats-new-actions">
|
||||
<button class="whats-new-btn whats-new-btn-secondary" id="whatsNewOpenChangesBtn" type="button">Open Recent Changes</button>
|
||||
<button class="whats-new-btn whats-new-btn-primary" id="whatsNewContinueBtn" type="button">Continue</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="header-inner">
|
||||
<div>
|
||||
<h1>Naue Roll Diameter Calculator</h1>
|
||||
<p>Roll Diameter • Product Length • Roll Weight • Load Optimizer</p>
|
||||
</div>
|
||||
<a class="header-help-link" href="{{ url_for('help_index') }}">Help</a>
|
||||
<a class="header-help-link" href="{{ url_for('user_manual') }}">User Manual</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1573,12 +1644,81 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
window.loadOptimizerUI = new LoadOptimizerUI();
|
||||
});
|
||||
|
||||
const ROLLCALC_BUILD_VERSION = {{ build_info.version|tojson }};
|
||||
const ROLLCALC_WHATS_NEW_ITEMS = {{ whats_new_summary|tojson }};
|
||||
const ROLLCALC_LAST_SEEN_VERSION_KEY = 'rollcalc_last_seen_version';
|
||||
|
||||
function shouldShowWhatsNew(currentVersion, storedVersion) {
|
||||
return !!currentVersion &&
|
||||
currentVersion !== 'unknown' &&
|
||||
currentVersion !== storedVersion;
|
||||
}
|
||||
|
||||
function markWhatsNewSeen(currentVersion) {
|
||||
if (!currentVersion || currentVersion === 'unknown') return;
|
||||
try {
|
||||
localStorage.setItem(ROLLCALC_LAST_SEEN_VERSION_KEY, currentVersion);
|
||||
} catch (e) {
|
||||
console.warn('Could not store RollCalc release note state', e);
|
||||
}
|
||||
}
|
||||
|
||||
function renderWhatsNewItems(items) {
|
||||
const list = document.getElementById('whatsNewList');
|
||||
if (!list) return;
|
||||
|
||||
list.innerHTML = '';
|
||||
items.forEach(item => {
|
||||
const li = document.createElement('li');
|
||||
li.textContent = item;
|
||||
list.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
function maybeShowWhatsNew() {
|
||||
const overlay = document.getElementById('whatsNewOverlay');
|
||||
const versionValue = document.getElementById('whatsNewVersion');
|
||||
const continueBtn = document.getElementById('whatsNewContinueBtn');
|
||||
const openChangesBtn = document.getElementById('whatsNewOpenChangesBtn');
|
||||
const items = Array.isArray(ROLLCALC_WHATS_NEW_ITEMS)
|
||||
? ROLLCALC_WHATS_NEW_ITEMS
|
||||
: [];
|
||||
|
||||
if (!overlay || !versionValue || !continueBtn || !openChangesBtn || items.length === 0) return;
|
||||
|
||||
let storedVersion = null;
|
||||
try {
|
||||
storedVersion = localStorage.getItem(ROLLCALC_LAST_SEEN_VERSION_KEY);
|
||||
} catch (e) {
|
||||
storedVersion = null;
|
||||
}
|
||||
|
||||
if (!shouldShowWhatsNew(ROLLCALC_BUILD_VERSION, storedVersion)) return;
|
||||
|
||||
versionValue.textContent = ROLLCALC_BUILD_VERSION;
|
||||
renderWhatsNewItems(items);
|
||||
overlay.classList.remove('is-hidden');
|
||||
|
||||
continueBtn.addEventListener('click', () => {
|
||||
markWhatsNewSeen(ROLLCALC_BUILD_VERSION);
|
||||
overlay.classList.add('is-hidden');
|
||||
}, { once: true });
|
||||
|
||||
openChangesBtn.addEventListener('click', () => {
|
||||
markWhatsNewSeen(ROLLCALC_BUILD_VERSION);
|
||||
window.location.href = {{ url_for('recent_changes')|tojson }};
|
||||
}, { once: true });
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const overlay = document.getElementById('disclaimerOverlay');
|
||||
const checkbox = document.getElementById('disclaimerAccepted');
|
||||
const confirmBtn = document.getElementById('disclaimerConfirmBtn');
|
||||
|
||||
if (!overlay || !checkbox || !confirmBtn) return;
|
||||
if (!overlay || !checkbox || !confirmBtn) {
|
||||
maybeShowWhatsNew();
|
||||
return;
|
||||
}
|
||||
|
||||
checkbox.addEventListener('change', () => {
|
||||
confirmBtn.disabled = !checkbox.checked;
|
||||
@@ -1587,6 +1727,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
confirmBtn.addEventListener('click', () => {
|
||||
if (!checkbox.checked) return;
|
||||
overlay.classList.add('is-hidden');
|
||||
maybeShowWhatsNew();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="RollCalc User Manual">
|
||||
<title>RollCalc User Manual</title>
|
||||
<meta name="description" content="RollCalc {{ document_title }}">
|
||||
<title>RollCalc {{ document_title }}</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html { scroll-behavior: smooth; }
|
||||
@@ -62,8 +62,8 @@
|
||||
<header class="help-header">
|
||||
<div class="help-header-inner">
|
||||
<div>
|
||||
<h1>User Manual</h1>
|
||||
<p>RollCalc technical user documentation</p>
|
||||
<h1>{{ document_title }}</h1>
|
||||
<p>{{ document_subtitle }}</p>
|
||||
</div>
|
||||
<nav class="help-nav" aria-label="Help navigation">
|
||||
<a href="{{ url_for('index') }}">Calculator</a>
|
||||
@@ -75,7 +75,7 @@
|
||||
<main class="manual-shell">
|
||||
{% if render_error %}
|
||||
<section class="manual-error" role="alert">
|
||||
<strong>User Manual unavailable</strong>
|
||||
<strong>{{ error_title }}</strong>
|
||||
<p>{{ render_error }}</p>
|
||||
</section>
|
||||
{% else %}
|
||||
|
||||
Reference in New Issue
Block a user