e09ee62c62
New dbn-tools-redesign.css with warm paper surface, navy tools nav, gold accent, and per-tool themes via body[data-active-tool]. Updated all 21 tool PHP pages, shared layout/nav/footer includes, and advocate route (new). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
257 lines
14 KiB
PHP
257 lines
14 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/bootstrap.php';
|
|
require_once __DIR__ . '/includes/FreeTier.php';
|
|
|
|
if (!dbnToolsIsAuthenticated()) {
|
|
header('Location: /?return=' . urlencode($_SERVER['REQUEST_URI'] ?? '/dashboard.php'));
|
|
exit;
|
|
}
|
|
|
|
$uiLang = dbnToolsCurrentLanguage();
|
|
$tools = dbnToolsLaunchedTools($uiLang);
|
|
$workbench = dbnToolsWorkbenchMeta($uiLang);
|
|
$langPath = '/dashboard.php';
|
|
|
|
// Tier + balance for SSO users (CaveauAI sessions get no panel)
|
|
$dashIsSso = dbnToolsIsFreeTier();
|
|
$dashTier = $dashIsSso ? FreeTier::tier((int)$_SESSION['dbn_tools_sso_uid']) : 'caveau';
|
|
$dashDetail = $dashIsSso ? FreeTier::balanceDetail((int)$_SESSION['dbn_tools_sso_uid']) : null;
|
|
$tierLabels = [
|
|
'free' => ['Gratis', '#f3f4f6', '#374151'],
|
|
'plus' => ['Plus', '#ddd6fe', '#5b21b6'],
|
|
'pro' => ['Pro Familie', '#bfdbfe', '#1e40af'],
|
|
];
|
|
$tierLabel = $tierLabels[$dashTier] ?? ['CaveauAI', '#d1fae5', '#065f46'];
|
|
$showSurveyCta = $dashIsSso && empty($dashDetail['survey_completed_at']);
|
|
|
|
require_once __DIR__ . '/includes/tool-svgs.php';
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= htmlspecialchars($uiLang) ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title><?= htmlspecialchars(dbnToolsT('dashboard_title', $uiLang)) ?> — Do Better Norge</title>
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<meta name="theme-color" content="#00205B">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap">
|
|
<link rel="stylesheet" href="assets/css/tools.css">
|
|
<link rel="stylesheet" href="assets/css/dbn-tools-redesign.css">
|
|
</head>
|
|
<body data-authenticated="true" class="lt-app">
|
|
<script>
|
|
window.DBN_TOOLS_AUTHENTICATED = true;
|
|
window.DBN_TOOLS_LANG = <?= json_encode($uiLang, JSON_UNESCAPED_UNICODE) ?>;
|
|
</script>
|
|
|
|
<?php include __DIR__ . '/includes/nav.php'; ?>
|
|
|
|
<main id="appShell" class="app-shell dashboard-shell">
|
|
|
|
<?php if ($dashIsSso && $dashDetail): ?>
|
|
<section class="dashboard-status-row" style="display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap:1rem; margin: 1.5rem 0;">
|
|
<div class="status-card" style="background:#fff; border:1px solid #e5e7eb; border-radius:10px; padding:1.1rem 1.25rem;">
|
|
<p style="margin:0; color:#6b7280; font-size:0.85rem; text-transform:uppercase; letter-spacing:0.06em;"><?= htmlspecialchars(dbnToolsT('credits_available', $uiLang)) ?></p>
|
|
<p style="margin:0.35rem 0 0; font-size:1.8rem; font-weight:700; color:#00205B;">
|
|
<?php $eff = (int)$dashDetail['balance'] + (int)$dashDetail['bonus_balance']; ?>
|
|
<?= number_format($eff, 0, ',', ' ') ?>
|
|
</p>
|
|
<p style="margin:0; color:#6b7280; font-size:0.85rem;"><?= (int)$dashDetail['balance'] ?> <?= htmlspecialchars(dbnToolsT('credits_monthly', $uiLang)) ?> · <?= (int)$dashDetail['bonus_balance'] ?> <?= htmlspecialchars(dbnToolsT('credits_bonus', $uiLang)) ?> · <a href="/billing.php"><?= htmlspecialchars(dbnToolsT('details_link', $uiLang)) ?></a></p>
|
|
</div>
|
|
<?php if (in_array($dashTier, ['plus','pro'], true)): ?>
|
|
<a class="status-card" href="/min-sak.php" style="background:#fff; border:1px solid #e5e7eb; border-radius:10px; padding:1.1rem 1.25rem; text-decoration:none; color:inherit;">
|
|
<p style="margin:0; color:#6b7280; font-size:0.85rem; text-transform:uppercase; letter-spacing:0.06em;"><?= htmlspecialchars(dbnToolsT('my_case', $uiLang)) ?></p>
|
|
<p style="margin:0.35rem 0 0; font-size:1.4rem; font-weight:700; color:#00205B;"><?= htmlspecialchars(dbnToolsT('build_your_case', $uiLang)) ?> →</p>
|
|
<?php
|
|
$used = (int)$dashDetail['storage_used_bytes'];
|
|
$quota = (int)$dashDetail['storage_quota_bytes'];
|
|
$usedMb = $used > 0 ? round($used / 1048576, 1) : 0;
|
|
$quotaMb = $quota > 0 ? round($quota / 1048576, 0) : 0;
|
|
?>
|
|
<p style="margin:0; color:#6b7280; font-size:0.85rem;"><?= $usedMb ?> MB / <?= $quotaMb ?> MB</p>
|
|
</a>
|
|
<?php else: ?>
|
|
<a class="status-card" href="/pricing.php" style="background:linear-gradient(135deg,#00205B,#003478); color:#fff; border-radius:10px; padding:1.1rem 1.25rem; text-decoration:none;">
|
|
<p style="margin:0; opacity:0.85; font-size:0.85rem; text-transform:uppercase; letter-spacing:0.06em;"><?= htmlspecialchars(dbnToolsT('build_your_case', $uiLang)) ?></p>
|
|
<p style="margin:0.35rem 0 0; font-size:1.4rem; font-weight:700;"><?= htmlspecialchars(dbnToolsT('upload_documents', $uiLang)) ?> →</p>
|
|
<p style="margin:0; opacity:0.85; font-size:0.85rem;"><?= htmlspecialchars(dbnToolsT('upgrade_from_plus', $uiLang)) ?></p>
|
|
</a>
|
|
<?php endif; ?>
|
|
<!-- Corpus summary widget — populated via fetch('/api/corpus-summary.php') -->
|
|
<a id="corpusSummaryCard" class="status-card" href="/dashboard/" style="background:#fff; border:1px solid #e5e7eb; border-radius:10px; padding:1.1rem 1.25rem; text-decoration:none; color:inherit; display:block;">
|
|
<p style="margin:0; color:#6b7280; font-size:0.85rem; text-transform:uppercase; letter-spacing:0.06em;"><?= htmlspecialchars(dbnToolsT('my_corpus', $uiLang)) ?></p>
|
|
<p id="corpusDocCount" style="margin:0.35rem 0 0; font-size:1.4rem; font-weight:700; color:#00205B;">—</p>
|
|
<p id="corpusUpdated" style="margin:0; color:#6b7280; font-size:0.85rem;"><?= htmlspecialchars(dbnToolsT('open_corpus', $uiLang)) ?> →</p>
|
|
</a>
|
|
<?php if ($showSurveyCta): ?>
|
|
<a class="status-card" href="https://dobetternorge.no/survey.php" style="background:#fef3c7; color:#92400e; border-radius:10px; padding:1.1rem 1.25rem; text-decoration:none;">
|
|
<p style="margin:0; font-size:0.85rem; text-transform:uppercase; letter-spacing:0.06em; opacity:0.85;"><?= htmlspecialchars(dbnToolsT('earn_credits_eyebrow', $uiLang)) ?></p>
|
|
<p style="margin:0.35rem 0 0; font-size:1.2rem; font-weight:700;"><?= htmlspecialchars(dbnToolsT('survey_btn', $uiLang)) ?> →</p>
|
|
<p style="margin:0; font-size:0.85rem; opacity:0.85;"><?= htmlspecialchars(dbnToolsT('survey_cta_text', $uiLang)) ?></p>
|
|
</a>
|
|
<?php endif; ?>
|
|
</section>
|
|
<?php endif; ?>
|
|
|
|
<section class="manifesto dashboard-manifesto">
|
|
<div class="manifesto-copy">
|
|
<p class="manifesto-eyebrow"><?= htmlspecialchars(dbnToolsT('dashboard_eyebrow', $uiLang)) ?></p>
|
|
<h2 class="manifesto-title"><?= htmlspecialchars(dbnToolsT('manifesto_title', $uiLang)) ?></h2>
|
|
<p class="manifesto-sub"><?= htmlspecialchars(dbnToolsT('dashboard_sub', $uiLang)) ?></p>
|
|
</div>
|
|
<div class="manifesto-stats" aria-label="Headline statistics">
|
|
<div class="manifesto-stat"><strong>23</strong><span><?= htmlspecialchars(dbnToolsT('stat_echr', $uiLang)) ?></span></div>
|
|
<div class="manifesto-stat"><strong>64%</strong><span><?= htmlspecialchars(dbnToolsT('stat_loss', $uiLang)) ?></span></div>
|
|
<div class="manifesto-stat"><strong>1,731</strong><span><?= htmlspecialchars(dbnToolsT('stat_tribunal', $uiLang)) ?></span></div>
|
|
<div class="manifesto-stat"><strong>20+</strong><span><?= htmlspecialchars(dbnToolsT('stat_pending', $uiLang)) ?></span></div>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="disclaimer" role="note"><?= htmlspecialchars(dbnToolsT('disclaimer', $uiLang)) ?></div>
|
|
|
|
<section class="tool-dashboard-grid" aria-label="Available tools">
|
|
<a class="dashboard-tool-card dashboard-tool-card--workbench" href="<?= htmlspecialchars($workbench['url']) ?>">
|
|
<span class="dashboard-tool-card__icon"><?= htmlspecialchars($workbench['icon']) ?></span>
|
|
<span class="dashboard-tool-card__badge"><?= htmlspecialchars($workbench['badge']) ?></span>
|
|
<h2><?= htmlspecialchars($workbench['label']) ?></h2>
|
|
<p><?= htmlspecialchars($workbench['description']) ?></p>
|
|
<strong><?= htmlspecialchars(dbnToolsT('enter_workbench', $uiLang)) ?></strong>
|
|
</a>
|
|
<?php foreach ($tools as $slug => $item): ?>
|
|
<a class="dashboard-tool-card" href="<?= htmlspecialchars($item['url']) ?>">
|
|
<span class="dashboard-tool-card__icon"><?= htmlspecialchars($item['icon']) ?></span>
|
|
<span class="dashboard-tool-card__badge"><?= htmlspecialchars($item['badge']) ?></span>
|
|
<h2><?= htmlspecialchars($item['label']) ?></h2>
|
|
<p><?= htmlspecialchars($item['description']) ?></p>
|
|
<strong><?= htmlspecialchars(dbnToolsT('open_tool', $uiLang)) ?></strong>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</section>
|
|
|
|
<!-- Welcome modal — shown once per browser until dismissed with "don't show again" -->
|
|
<div id="welcomeModal" class="wlc-backdrop" role="dialog" aria-modal="true" aria-labelledby="wlcTitle" hidden>
|
|
<div class="wlc-card">
|
|
<div class="wlc-header">
|
|
<p class="wlc-eyebrow"><?= htmlspecialchars(dbnToolsT('brand_line', $uiLang)) ?></p>
|
|
<h2 class="wlc-title" id="wlcTitle">Welcome to Do Better Norge Legal Tools</h2>
|
|
<p class="wlc-sub">Here’s a quick look at what each tool does — click any card on the dashboard to go straight in.</p>
|
|
</div>
|
|
<div class="wlc-workbench-tip">
|
|
<span class="wlc-tip-icon" aria-hidden="true">💡</span>
|
|
<span><strong>Start with the Case Workbench</strong> — frame your situation first, then use the tools below with context already loaded.</span>
|
|
</div>
|
|
<div class="wlc-tools-grid">
|
|
<?php
|
|
$welcomeTips = [
|
|
'transcribe' => 'Upload a hearing recording to get an accurate, speaker-separated transcript',
|
|
'timeline' => 'Paste case notes to instantly map all key dates and Barnevernet milestones',
|
|
'redact' => 'Strip names and ID numbers before sharing any document with third parties',
|
|
'korrespond' => 'Draft authority letters in Norwegian + your language with verified citations',
|
|
'barnevernet' => 'Upload child-welfare documents to flag procedural violations and red flags',
|
|
'advocate' => 'Generate a fully-cited brief for your position from ECHR and Lovdata',
|
|
'deep-research' => 'Ask a complex legal question and get a multi-angle cited research brief',
|
|
'discrepancy' => 'Upload two doc versions to surface deleted facts or new allegations',
|
|
'corpus' => 'Browse the 220 K+ indexed legal passages behind every AI answer',
|
|
'citations' => 'Trace how cases cite each other to find supporting precedents',
|
|
];
|
|
$toolIcons = [
|
|
'transcribe' => '🎙',
|
|
'timeline' => '📅',
|
|
'redact' => '🔒',
|
|
'korrespond' => '✉️',
|
|
'barnevernet' => '🔍',
|
|
'advocate' => '⚖️',
|
|
'deep-research' => '🔬',
|
|
'discrepancy' => '🔎',
|
|
'corpus' => '📚',
|
|
'citations' => '🔗',
|
|
];
|
|
foreach ($tools as $slug => $item):
|
|
$tip = $welcomeTips[$slug] ?? $item['description'];
|
|
$icon = $toolIcons[$slug] ?? '🛠';
|
|
?>
|
|
<a class="wlc-tool-item" href="<?= htmlspecialchars($item['url']) ?>">
|
|
<span class="wlc-tool-icon" aria-hidden="true"><?= $icon ?></span>
|
|
<span class="wlc-tool-name"><?= htmlspecialchars($item['label']) ?></span>
|
|
<span class="wlc-tool-tip"><?= htmlspecialchars($tip) ?></span>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<div class="wlc-footer">
|
|
<label class="wlc-no-show">
|
|
<input type="checkbox" id="wlcDontShow" checked>
|
|
Don’t show this again
|
|
</label>
|
|
<button id="wlcGetStarted" class="wlc-btn-start" type="button">Get started →</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
|
<script src="assets/js/tools.js" defer></script>
|
|
<script>
|
|
(function () {
|
|
var STORAGE_KEY = 'dbn-welcome-v1-seen';
|
|
var modal = document.getElementById('welcomeModal');
|
|
var btnStart = document.getElementById('wlcGetStarted');
|
|
var chkDontShow = document.getElementById('wlcDontShow');
|
|
|
|
function closeModal(saveFlag) {
|
|
modal.hidden = true;
|
|
document.body.style.overflow = '';
|
|
if (saveFlag) {
|
|
try { localStorage.setItem(STORAGE_KEY, '1'); } catch (e) {}
|
|
}
|
|
}
|
|
|
|
if (modal && !localStorage.getItem(STORAGE_KEY)) {
|
|
modal.hidden = false;
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
|
|
if (btnStart) {
|
|
btnStart.addEventListener('click', function () {
|
|
closeModal(chkDontShow && chkDontShow.checked);
|
|
});
|
|
}
|
|
|
|
if (modal) {
|
|
modal.addEventListener('click', function (e) {
|
|
if (e.target === modal) closeModal(false);
|
|
});
|
|
document.addEventListener('keydown', function (e) {
|
|
if (e.key === 'Escape' && !modal.hidden) closeModal(false);
|
|
});
|
|
}
|
|
}());
|
|
</script>
|
|
<?php if ($dashIsSso): ?>
|
|
<script>
|
|
(function () {
|
|
var card = document.getElementById('corpusSummaryCard');
|
|
var countEl = document.getElementById('corpusDocCount');
|
|
var updEl = document.getElementById('corpusUpdated');
|
|
if (!card || !countEl) return;
|
|
fetch('/api/corpus-summary.php')
|
|
.then(function (r) { return r.ok ? r.json() : null; })
|
|
.then(function (data) {
|
|
if (!data) return;
|
|
countEl.textContent = data.doc_count !== undefined
|
|
? data.doc_count.toLocaleString() + ' docs'
|
|
: '—';
|
|
if (data.last_updated && updEl) {
|
|
var d = new Date(data.last_updated);
|
|
updEl.textContent = d.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric' });
|
|
}
|
|
})
|
|
.catch(function () {});
|
|
}());
|
|
</script>
|
|
<?php endif; ?>
|
|
</body>
|
|
</html>
|