feat: Legal Tools v1 — multilingual landing, dashboard, SSO bridge
- Public landing page at / for unauthenticated users (EN/NO/UK/PL) - Authenticated / shows Case Workbench dashboard with manifesto strip, stats, and launched-tool grid (Transcribe, Timeline, BVJ, Advocate, Deep Research, Corpus) - Added includes/i18n.php with full 4-language translation layer - Extended layout.php to Case Workbench shell with tool rail, lang switcher - AI output language normalization extended to en/no/uk/pl in PHP agents - SSO token validation in bootstrap.php / index.php (dobetternorge.no bridge) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,461 @@
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
/* Do Better Norge v1 workbench */
|
||||
:root {
|
||||
--dbn-paper: #f6f2ea;
|
||||
--dbn-ink: #16130f;
|
||||
--dbn-blue: #00205b;
|
||||
--dbn-red: #ba0c2f;
|
||||
--dbn-teal: #0f766e;
|
||||
--dbn-line: rgba(22, 19, 15, 0.16);
|
||||
}
|
||||
|
||||
body {
|
||||
background:
|
||||
linear-gradient(90deg, rgba(0, 32, 91, 0.055) 1px, transparent 1px),
|
||||
linear-gradient(180deg, rgba(186, 12, 47, 0.04), transparent 38rem),
|
||||
var(--dbn-paper);
|
||||
background-size: 44px 44px, auto, auto;
|
||||
}
|
||||
|
||||
.app-shell {
|
||||
padding: 18px clamp(14px, 2vw, 28px) 34px;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
align-items: flex-start;
|
||||
border-bottom: 2px solid rgba(22, 19, 15, 0.14);
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.topbar h1 {
|
||||
color: var(--dbn-ink);
|
||||
font-size: clamp(1.8rem, 2.8vw, 3.2rem);
|
||||
line-height: 0.95;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.title-mark {
|
||||
color: var(--dbn-red);
|
||||
}
|
||||
|
||||
.case-no {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-top: 9px;
|
||||
color: #5d574e;
|
||||
font-size: 0.86rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.case-sep {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.pulse {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: var(--dbn-teal);
|
||||
box-shadow: 0 0 0 5px rgba(15, 118, 110, 0.12);
|
||||
}
|
||||
|
||||
.shell-lang-switcher {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--dbn-line);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.64);
|
||||
}
|
||||
|
||||
.shell-lang-switcher a {
|
||||
display: inline-flex;
|
||||
min-width: 36px;
|
||||
min-height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
color: var(--dbn-blue);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.shell-lang-switcher a.is-active,
|
||||
.shell-lang-switcher a:hover {
|
||||
background: var(--dbn-blue);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.manifesto {
|
||||
max-width: 1500px;
|
||||
margin: 0 auto 12px;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.15fr) minmax(360px, 0.85fr);
|
||||
gap: 14px;
|
||||
border: 1px solid rgba(22, 19, 15, 0.18);
|
||||
border-radius: 8px;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(186, 12, 47, 0.14), transparent 44%),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0.42));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.manifesto-copy {
|
||||
padding: clamp(20px, 3vw, 36px);
|
||||
}
|
||||
|
||||
.manifesto-eyebrow {
|
||||
margin: 0 0 8px;
|
||||
color: var(--dbn-red);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.manifesto-title {
|
||||
max-width: 780px;
|
||||
margin: 0;
|
||||
color: var(--dbn-ink);
|
||||
font-size: clamp(2rem, 5vw, 5.4rem);
|
||||
line-height: 0.92;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.manifesto-sub {
|
||||
max-width: 760px;
|
||||
margin: 14px 0 0;
|
||||
color: #3f3932;
|
||||
font-size: clamp(1rem, 1.3vw, 1.18rem);
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.manifesto-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
border-left: 1px solid rgba(22, 19, 15, 0.16);
|
||||
}
|
||||
|
||||
.manifesto-stat {
|
||||
min-height: 120px;
|
||||
padding: 20px;
|
||||
border: 0 solid rgba(22, 19, 15, 0.13);
|
||||
border-bottom-width: 1px;
|
||||
border-right-width: 1px;
|
||||
background: rgba(255, 255, 255, 0.38);
|
||||
}
|
||||
|
||||
.manifesto-stat strong {
|
||||
display: block;
|
||||
color: var(--dbn-blue);
|
||||
font-size: clamp(1.8rem, 3vw, 3.2rem);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.manifesto-stat span {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
color: #4b453d;
|
||||
font-size: 0.82rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.workspace {
|
||||
grid-template-columns: 204px minmax(0, 1fr) 370px;
|
||||
}
|
||||
|
||||
.tool-rail,
|
||||
.tool-panel,
|
||||
.reasoning-panel,
|
||||
.gate-panel,
|
||||
.cap-card,
|
||||
.dashboard-tool-card {
|
||||
border-color: rgba(22, 19, 15, 0.15);
|
||||
box-shadow: 0 18px 45px rgba(22, 19, 15, 0.08);
|
||||
}
|
||||
|
||||
.tool-tab {
|
||||
position: relative;
|
||||
min-height: 74px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.tool-tab em {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 8px;
|
||||
color: rgba(0, 32, 91, 0.22);
|
||||
font-size: 1.25rem;
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.tool-tab.is-active {
|
||||
background: #fdf8ef;
|
||||
border-color: rgba(186, 12, 47, 0.28);
|
||||
color: var(--dbn-ink);
|
||||
}
|
||||
|
||||
.tool-tab.is-active::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0 auto 0 0;
|
||||
width: 4px;
|
||||
background: var(--dbn-red);
|
||||
}
|
||||
|
||||
.dashboard-shell .disclaimer {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.tool-dashboard-grid {
|
||||
max-width: 1500px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.dashboard-tool-card {
|
||||
position: relative;
|
||||
min-height: 250px;
|
||||
padding: 22px;
|
||||
border: 1px solid var(--dbn-line);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.82);
|
||||
color: var(--dbn-ink);
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dashboard-tool-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(186, 12, 47, 0.36);
|
||||
}
|
||||
|
||||
.dashboard-tool-card__icon {
|
||||
color: rgba(0, 32, 91, 0.14);
|
||||
font-size: 4.8rem;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.dashboard-tool-card__badge {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 18px;
|
||||
color: var(--dbn-red);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 900;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.dashboard-tool-card h2 {
|
||||
margin: 12px 0 8px;
|
||||
font-size: 1.45rem;
|
||||
}
|
||||
|
||||
.dashboard-tool-card p {
|
||||
color: #514b43;
|
||||
line-height: 1.48;
|
||||
}
|
||||
|
||||
.dashboard-tool-card strong {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
color: var(--dbn-blue);
|
||||
}
|
||||
|
||||
.dbn-public-tools {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.showcase-header {
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
border-bottom: 1px solid var(--dbn-line);
|
||||
}
|
||||
|
||||
.showcase-header-inner {
|
||||
align-items: flex-start;
|
||||
padding-top: 22px;
|
||||
padding-bottom: 22px;
|
||||
}
|
||||
|
||||
.showcase-header-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.showcase-title {
|
||||
max-width: 980px;
|
||||
color: var(--dbn-ink);
|
||||
font-size: clamp(2.4rem, 6vw, 6.4rem);
|
||||
line-height: 0.9;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.showcase-tagline {
|
||||
max-width: 780px;
|
||||
color: #403a33;
|
||||
font-size: clamp(1.05rem, 1.6vw, 1.32rem);
|
||||
}
|
||||
|
||||
.landing-hero {
|
||||
max-width: 1500px;
|
||||
margin: 18px auto;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(280px, 420px);
|
||||
gap: 14px;
|
||||
padding: clamp(22px, 4vw, 54px);
|
||||
border: 1px solid var(--dbn-line);
|
||||
border-radius: 8px;
|
||||
background:
|
||||
linear-gradient(135deg, rgba(0, 32, 91, 0.12), transparent 34%),
|
||||
linear-gradient(315deg, rgba(186, 12, 47, 0.16), transparent 40%),
|
||||
#fffaf2;
|
||||
}
|
||||
|
||||
.landing-hero h2 {
|
||||
max-width: 840px;
|
||||
margin: 0;
|
||||
font-size: clamp(2rem, 5vw, 5.3rem);
|
||||
line-height: 0.92;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.landing-hero p {
|
||||
max-width: 740px;
|
||||
color: #403a33;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.landing-hero__stats {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.landing-hero__stats div {
|
||||
padding: 18px;
|
||||
border: 1px solid rgba(0, 32, 91, 0.16);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.landing-hero__stats strong {
|
||||
display: block;
|
||||
color: var(--dbn-blue);
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.landing-hero__stats span {
|
||||
color: #514b43;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.cap-grid--six {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.evidence-inner {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.evidence-inner article {
|
||||
padding: 20px;
|
||||
border-left: 4px solid rgba(186, 12, 47, 0.45);
|
||||
background: rgba(255, 255, 255, 0.58);
|
||||
}
|
||||
|
||||
.google-access-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 48px;
|
||||
margin: 18px 0;
|
||||
border-radius: 8px;
|
||||
background: var(--dbn-blue);
|
||||
color: #fff;
|
||||
font-weight: 900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.fallback-login {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--dbn-line);
|
||||
}
|
||||
|
||||
.fallback-login summary {
|
||||
cursor: pointer;
|
||||
color: #655d53;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
.workspace {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tool-rail {
|
||||
flex-direction: row;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.tool-tab {
|
||||
min-width: 170px;
|
||||
}
|
||||
|
||||
.manifesto,
|
||||
.landing-hero {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.manifesto-stats {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.tool-dashboard-grid,
|
||||
.cap-grid--six,
|
||||
.evidence-inner {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.topbar,
|
||||
.showcase-header-inner {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.topbar-actions,
|
||||
.showcase-header-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.manifesto-stats,
|
||||
.tool-dashboard-grid,
|
||||
.cap-grid--six,
|
||||
.evidence-inner {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.dashboard-tool-card {
|
||||
min-height: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -3712,3 +4167,46 @@ a.dr-source-title-link:hover {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
/* v1 final cascade overrides */
|
||||
body {
|
||||
background:
|
||||
linear-gradient(90deg, rgba(0, 32, 91, 0.055) 1px, transparent 1px),
|
||||
linear-gradient(180deg, rgba(186, 12, 47, 0.04), transparent 38rem),
|
||||
var(--dbn-paper);
|
||||
background-size: 44px 44px, auto, auto;
|
||||
color: var(--dbn-ink);
|
||||
}
|
||||
|
||||
.app-shell { padding: 18px clamp(14px, 2vw, 28px) 34px; }
|
||||
.topbar { align-items: flex-start; border-bottom: 2px solid rgba(22, 19, 15, 0.14); padding-bottom: 16px; }
|
||||
.topbar h1 { color: var(--dbn-ink); font-size: clamp(1.8rem, 2.8vw, 3.2rem); line-height: .95; letter-spacing: 0; }
|
||||
.workspace { grid-template-columns: 204px minmax(0, 1fr) 370px; }
|
||||
.tool-rail, .tool-panel, .reasoning-panel, .gate-panel, .cap-card, .dashboard-tool-card {
|
||||
border-color: rgba(22, 19, 15, 0.15);
|
||||
box-shadow: 0 18px 45px rgba(22, 19, 15, 0.08);
|
||||
}
|
||||
.tool-tab { position: relative; min-height: 74px; overflow: hidden; }
|
||||
.tool-tab em { position: absolute; right: 10px; bottom: 8px; color: rgba(0, 32, 91, .22); font-size: 1.25rem; font-style: normal; font-weight: 900; }
|
||||
.tool-tab.is-active { background: #fdf8ef; border-color: rgba(186, 12, 47, .28); color: var(--dbn-ink); }
|
||||
.tool-tab.is-active::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 4px; background: var(--dbn-red); }
|
||||
.showcase-title { max-width: 980px; color: var(--dbn-ink); font-size: clamp(2.4rem, 6vw, 6.4rem); line-height: .9; letter-spacing: 0; }
|
||||
.showcase-tagline { max-width: 780px; color: #403a33; font-size: clamp(1.05rem, 1.6vw, 1.32rem); }
|
||||
.cap-grid--six { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||
.evidence-inner { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||||
.google-access-button { display: flex; align-items: center; justify-content: center; min-height: 48px; margin: 18px 0; border-radius: 8px; background: var(--dbn-blue); color: #fff; font-weight: 900; text-decoration: none; }
|
||||
.fallback-login { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--dbn-line); }
|
||||
.fallback-login summary { cursor: pointer; color: #655d53; font-weight: 800; }
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
.workspace { grid-template-columns: 1fr; }
|
||||
.tool-rail { flex-direction: row; overflow-x: auto; }
|
||||
.tool-tab { min-width: 170px; }
|
||||
.tool-dashboard-grid, .cap-grid--six, .evidence-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.topbar, .showcase-header-inner { flex-direction: column; }
|
||||
.topbar-actions, .showcase-header-actions { width: 100%; justify-content: flex-start; }
|
||||
.manifesto-stats, .tool-dashboard-grid, .cap-grid--six, .evidence-inner { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'use strict';
|
||||
|
||||
const els = {};
|
||||
let lang = 'en';
|
||||
let lang = window.DBN_TOOLS_LANG || localStorage.getItem('dbn-ui-lang') || 'en';
|
||||
let uploadFiles = [];
|
||||
let lastResult = null;
|
||||
let branchContext = null;
|
||||
@@ -121,10 +121,12 @@
|
||||
|
||||
function bindLang() {
|
||||
els.langButtons.forEach((b) => {
|
||||
b.classList.toggle('is-active', b.dataset.lang === lang);
|
||||
b.addEventListener('click', () => {
|
||||
els.langButtons.forEach((x) => x.classList.remove('is-active'));
|
||||
b.classList.add('is-active');
|
||||
lang = b.dataset.lang || 'en';
|
||||
localStorage.setItem('dbn-ui-lang', lang);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'use strict';
|
||||
|
||||
const els = {};
|
||||
let lang = 'en';
|
||||
let lang = window.DBN_TOOLS_LANG || localStorage.getItem('dbn-ui-lang') || 'en';
|
||||
let uploadFiles = [];
|
||||
let lastResult = null;
|
||||
let branchContext = null;
|
||||
@@ -148,10 +148,12 @@
|
||||
|
||||
function bindLang() {
|
||||
els.langButtons.forEach((b) => {
|
||||
b.classList.toggle('is-active', b.dataset.lang === lang);
|
||||
b.addEventListener('click', () => {
|
||||
els.langButtons.forEach((x) => x.classList.remove('is-active'));
|
||||
b.classList.add('is-active');
|
||||
lang = b.dataset.lang || 'en';
|
||||
localStorage.setItem('dbn-ui-lang', lang);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
'use strict';
|
||||
|
||||
const els = {};
|
||||
let lang = 'en';
|
||||
let lang = window.DBN_TOOLS_LANG || localStorage.getItem('dbn-ui-lang') || 'en';
|
||||
let uploadFiles = [];
|
||||
let lastResult = null;
|
||||
let branchContext = null;
|
||||
@@ -102,10 +102,12 @@
|
||||
|
||||
function bindLang() {
|
||||
els.langButtons.forEach((b) => {
|
||||
b.classList.toggle('is-active', b.dataset.lang === lang);
|
||||
b.addEventListener('click', () => {
|
||||
els.langButtons.forEach((x) => x.classList.remove('is-active'));
|
||||
b.classList.add('is-active');
|
||||
lang = b.dataset.lang || 'en';
|
||||
localStorage.setItem('dbn-ui-lang', lang);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
+36
-9
@@ -391,7 +391,14 @@ const VOCAB_PRESETS = {
|
||||
custom: '',
|
||||
};
|
||||
|
||||
let uiLang = localStorage.getItem('dbn-ui-lang') || 'en';
|
||||
let uiLang = window.DBN_TOOLS_LANG || localStorage.getItem('dbn-ui-lang') || 'en';
|
||||
|
||||
function syncOutputLanguage(lang) {
|
||||
const normalized = ['en', 'no', 'uk', 'pl'].includes(lang) ? lang : 'en';
|
||||
document.querySelectorAll('input[name="language"]').forEach((input) => {
|
||||
if (input.value === normalized) input.checked = true;
|
||||
});
|
||||
}
|
||||
|
||||
const TRANSCRIBE_I18N = {
|
||||
en: {
|
||||
@@ -670,6 +677,7 @@ function currentUiT(key, ...args) {
|
||||
function applyTranscribeI18n(lang) {
|
||||
uiLang = lang;
|
||||
localStorage.setItem('dbn-ui-lang', lang);
|
||||
syncOutputLanguage(lang);
|
||||
document.querySelectorAll('[data-i18n]').forEach((el) => {
|
||||
const text = currentUiT(el.dataset.i18n);
|
||||
if (text != null) el.textContent = text;
|
||||
@@ -695,6 +703,7 @@ function currentRedactT(key) {
|
||||
function applyRedactI18n(lang) {
|
||||
uiLang = lang;
|
||||
localStorage.setItem('dbn-ui-lang', lang);
|
||||
syncOutputLanguage(lang);
|
||||
document.querySelectorAll('[data-i18n]').forEach((el) => {
|
||||
const text = currentRedactT(el.dataset.i18n);
|
||||
if (text != null) el.textContent = text;
|
||||
@@ -750,6 +759,7 @@ function currentTimelineT(key) {
|
||||
function applyTimelineI18n(lang) {
|
||||
uiLang = lang;
|
||||
localStorage.setItem('dbn-ui-lang', lang);
|
||||
syncOutputLanguage(lang);
|
||||
document.querySelectorAll('[data-i18n]').forEach((el) => {
|
||||
const text = currentTimelineT(el.dataset.i18n);
|
||||
if (text != null) el.textContent = text;
|
||||
@@ -952,7 +962,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
els.form?.addEventListener('submit', runTool);
|
||||
els.passcodeForm?.addEventListener('submit', submitPasscode);
|
||||
els.healthButton.addEventListener('click', checkHealth);
|
||||
els.healthButton?.addEventListener('click', checkHealth);
|
||||
setupUpload();
|
||||
setupAliases();
|
||||
setupAudio();
|
||||
@@ -968,7 +978,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (document.getElementById('uiLangSwitcher')) {
|
||||
applyTranscribeI18n(uiLang);
|
||||
}
|
||||
els.results.addEventListener('click', (e) => {
|
||||
els.results?.addEventListener('click', (e) => {
|
||||
if (e.target.closest('#exportCsvBtn')) exportTimelineCSV(lastTimelineEvents);
|
||||
if (e.target.closest('#dlTxt')) downloadTranscriptTxt();
|
||||
if (e.target.closest('#dlSrt')) downloadTranscriptSrt();
|
||||
@@ -978,7 +988,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (e.target.closest('#rdlDocx')) downloadRedactedDocx();
|
||||
});
|
||||
const activeTool = document.body.dataset.activeTool || state.activeTool;
|
||||
setTool(activeTool);
|
||||
if (els.form && tools[activeTool]) {
|
||||
setTool(activeTool);
|
||||
}
|
||||
|
||||
if (state.authenticated) {
|
||||
checkHealth();
|
||||
@@ -990,18 +1002,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
function setTool(toolName) {
|
||||
state.activeTool = toolName;
|
||||
const tool = tools[toolName];
|
||||
if (!tool || !els.toolKind || !els.input) return;
|
||||
const serverRenderedShell = els.tabs.some((tab) => tab.tagName === 'A');
|
||||
els.tabs.forEach((button) => {
|
||||
const active = button.dataset.tool === toolName;
|
||||
button.classList.toggle('is-active', active);
|
||||
button.setAttribute('aria-pressed', String(active));
|
||||
});
|
||||
|
||||
els.toolKind.textContent = tool.kind;
|
||||
els.toolTitle.textContent = tool.title;
|
||||
els.toolBadge.textContent = tool.badge;
|
||||
els.inputLabel.textContent = tool.label;
|
||||
if (!serverRenderedShell) {
|
||||
els.toolKind.textContent = tool.kind;
|
||||
els.toolTitle.textContent = tool.title;
|
||||
els.toolBadge.textContent = tool.badge;
|
||||
els.inputLabel.textContent = tool.label;
|
||||
}
|
||||
els.input.value = '';
|
||||
els.input.placeholder = tool.placeholder;
|
||||
if (!serverRenderedShell) {
|
||||
els.input.placeholder = tool.placeholder;
|
||||
}
|
||||
els.languageControl.classList.toggle('is-hidden', !tool.usesLanguage);
|
||||
els.redactionControl.classList.toggle('is-hidden', toolName !== 'redact');
|
||||
els.uploadZone.classList.toggle('is-hidden', toolName !== 'redact' && toolName !== 'timeline');
|
||||
@@ -1031,6 +1049,12 @@ async function submitPasscode(event) {
|
||||
throw new Error(data.error?.message || 'Credentials were not accepted.');
|
||||
}
|
||||
state.authenticated = true;
|
||||
if (!els.app) {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
const dest = params.get('return') || '/';
|
||||
window.location.href = dest.startsWith('/') && !dest.startsWith('//') ? dest : '/';
|
||||
return;
|
||||
}
|
||||
els.gate.classList.add('is-hidden');
|
||||
els.app.classList.remove('is-hidden');
|
||||
els.loginPassword.value = '';
|
||||
@@ -1116,6 +1140,7 @@ function resetUpload() {
|
||||
}
|
||||
|
||||
function setupUpload() {
|
||||
if (!els.uploadZone || !els.uploadInput) return;
|
||||
els.uploadZone.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
els.uploadZone.classList.add('is-drag-over');
|
||||
@@ -1217,6 +1242,7 @@ async function handleFiles(fileList) {
|
||||
}
|
||||
|
||||
function setupAliases() {
|
||||
if (!els.addAliasRow || !els.aliasRows) return;
|
||||
els.addAliasRow.addEventListener('click', () => {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'alias-row';
|
||||
@@ -1287,6 +1313,7 @@ async function postJson(url, payload) {
|
||||
|
||||
function setBusy(isBusy) {
|
||||
const button = document.querySelector('#runButton');
|
||||
if (!button) return;
|
||||
button.disabled = isBusy;
|
||||
if (state.activeTool === 'transcribe') {
|
||||
button.textContent = isBusy ? currentUiT('running') : currentUiT('run');
|
||||
|
||||
Reference in New Issue
Block a user