- {layouts.map(l => (
-
applyLayout(l)}
- className={`flex items-center gap-1 text-xs rounded px-2 py-0.5 cursor-pointer border transition-colors
- ${activeLayoutId === l.id ? 'bg-blue-50 border-blue-300 text-blue-700' : 'bg-white border-gray-200 text-gray-600 hover:border-gray-400'}`}>
- {l.name}
-
-
- ))}
+ {/* Layouts group */}
+
+
Layout
+ {layouts.map(l => (
+
applyLayout(l)}
+ className={`flex items-center gap-1 rounded px-2 py-0.5 cursor-pointer border transition-colors
+ ${activeLayoutId === l.id ? 'bg-blue-900 border-blue-600 text-blue-300' : 'bg-gray-800 border-gray-600 text-gray-400 hover:border-gray-400 hover:text-gray-200'}`}>
+ {l.name}
+
+
+ ))}
+ {showSaveAs ? (
+
+ setSaveAsName(e.target.value)}
+ onKeyDown={e => { if (e.key === 'Enter') handleSaveAs(); if (e.key === 'Escape') { setShowSaveAs(false); setSaveAsName('') } }}
+ placeholder="Layout name…" className="border border-gray-600 rounded px-2 py-0.5 w-32 bg-gray-800 text-gray-200 focus:outline-none focus:border-blue-500 placeholder:text-gray-600" />
+
+
+
+ ) : (
+ <>
+ {activeLayoutId !== null && (
+
+ )}
+
+ {activeLayoutId !== null && (
+
+ )}
+ >
+ )}
+
- {activeLayoutId !== null && !showSaveAs && (
-
- )}
+
- {showSaveAs ? (
-
- setSaveAsName(e.target.value)}
- onKeyDown={e => { if (e.key === 'Enter') handleSaveAs(); if (e.key === 'Escape') { setShowSaveAs(false); setSaveAsName('') } }}
- placeholder="Layout name…" className="text-xs border border-gray-300 rounded px-2 py-0.5 w-32 focus:outline-none focus:border-blue-400" />
-
-
-
- ) : (
-
- )}
-
- {activeLayoutId !== null && (
-
- )}
-
-
-
- {/* Depth controls */}
-
-
depth
+ {/* Expand depth group */}
+
+ Expand
{[0, 1, 2, 3].map(d => (
))}
+
+
+
+
+ {/* Data group */}
+
+
+
+ {msg && (
+
+ {msg.text}
+
+ )}
+
{/* History modal */}
{showLog && (
-
setShowLog(false)}>
-
e.stopPropagation()}>
-
-
Change History
-
+
setShowLog(false)}>
+
e.stopPropagation()}>
+
+ Change log
+
{logLoading ? (
-
Loading…
+
Loading…
) : logEntries.length === 0 ? (
-
No log entries yet.
+
No log entries yet.
) : (
-
+
| Time |
Op |
@@ -493,15 +509,15 @@ export default function Forecast() {
{logEntries.map(entry => (
-
- | {fmtStamp(entry.stamp)} |
+
+ | {fmtStamp(entry.stamp)} |
{entry.operation}
|
- {fmtSlice(entry.slice)} |
-
+ | {fmtSlice(entry.slice)} |
+
{editingNote?.id === entry.id ? (
-
-
+ className="border border-blue-600 rounded px-1.5 py-0.5 text-xs flex-1 bg-gray-800 text-gray-200 focus:outline-none" />
+
+
) : (
setEditingNote({ id: entry.id, text: entry.note || '' })}
- className="cursor-text hover:bg-blue-50 rounded px-1 -mx-1 block truncate"
+ className="cursor-text hover:bg-gray-700 rounded px-1 -mx-1 block truncate"
title={entry.note || 'Click to add note'}>
- {entry.note || add note}
+ {entry.note || add note}
)}
|
@@ -527,7 +543,7 @@ export default function Forecast() {
@@ -546,40 +562,40 @@ export default function Forecast() {
{/* Perspective viewer */}
{loading && (
-
-
Loading…
+
+ Loading…
)}
{/* Drag handle */}
-
+
{/* Operation panel */}
-
-
-
Slice
+
+
+
Slice
{!hasSlice ? (
-
Click a pivot row to select a slice
+
Click a pivot row to select a slice
) : (
{Object.entries(slice).map(([k, v]) => (
-
-
{k} =
{v}
+
+ {k} = {v}
))}
-
+
)}
{hasSlice && (
<>
-
+
{['scale', 'recode', 'clone'].map(op => (
))}
@@ -588,10 +604,10 @@ export default function Forecast() {
{activeOp === 'scale' && <>
{/* Mode toggle */}
-
+
{[['target','= Target'],['delta','Δ Increment']].map(([m, label]) => (
))}
@@ -600,9 +616,9 @@ export default function Forecast() {
{/* Value row */}
{currentTotals?.valueCol && (
-
+
{currentTotals.valueCol}
- {currentTotals.value?.toLocaleString(undefined, {maximumFractionDigits:2})}
+ {currentTotals.value?.toLocaleString(undefined, {maximumFractionDigits:2})}
setScaleValue(e.target.value)}
@@ -614,9 +630,9 @@ export default function Forecast() {
{/* Units row */}
{currentTotals?.unitsCol && (
-
+
{currentTotals.unitsCol}
- {currentTotals.units?.toLocaleString(undefined, {maximumFractionDigits:2})}
+ {currentTotals.units?.toLocaleString(undefined, {maximumFractionDigits:2})}
setScaleUnits(e.target.value)}
@@ -636,7 +652,7 @@ export default function Forecast() {
>}
{activeOp === 'recode' && <>
-
New values for dimensions to replace. Leave blank to keep.
+
New values for dimensions to replace. Leave blank to keep.
{dimCols.map(c => (
setRecodeSet(s => ({ ...s, [c.cname]: e.target.value }))}
@@ -648,7 +664,7 @@ export default function Forecast() {
>}
{activeOp === 'clone' && <>
- Override dimensions on cloned rows. Leave blank to keep.
+ Override dimensions on cloned rows. Leave blank to keep.
{dimCols.map(c => (
setCloneSet(s => ({ ...s, [c.cname]: e.target.value }))}
@@ -668,7 +684,7 @@ export default function Forecast() {
)
}
-const inp = 'border border-gray-200 rounded px-2 py-1 text-xs flex-1 bg-white min-w-0'
+const inp = 'border border-gray-700 rounded px-2 py-1 text-xs flex-1 bg-gray-800 text-gray-200 placeholder:text-gray-600 min-w-0 focus:outline-none focus:border-blue-600'
function fmtStamp(stamp) {
return new Date(stamp).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' })
@@ -680,18 +696,18 @@ function fmtSlice(slice) {
}
const OP_BADGE = {
- baseline: 'bg-gray-100 text-gray-600',
- reference: 'bg-blue-50 text-blue-600',
- scale: 'bg-green-50 text-green-700',
- recode: 'bg-amber-50 text-amber-700',
- clone: 'bg-purple-50 text-purple-700',
+ baseline: 'bg-gray-700 text-gray-300',
+ reference: 'bg-blue-900 text-blue-300',
+ scale: 'bg-green-900 text-green-400',
+ recode: 'bg-amber-900 text-amber-400',
+ clone: 'bg-purple-900 text-purple-400',
}
-function opBadge(op) { return OP_BADGE[op] || 'bg-gray-100 text-gray-500' }
+function opBadge(op) { return OP_BADGE[op] || 'bg-gray-700 text-gray-400' }
function Row({ label, children }) {
return (
- {label}
+ {label}
{children}
)
@@ -699,7 +715,7 @@ function Row({ label, children }) {
function Submit({ onClick, children }) {
return (
-