MeshiTrack/docs/design/MeshiTrack.html

145 lines
6.9 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>MeshiTrack</title>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
<link href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@400;500;600&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"/>
<link rel="stylesheet" href="styles/tokens.css"/>
<link rel="stylesheet" href="styles/shell.css"/>
<link rel="stylesheet" href="styles/cabinet.css"/>
<link rel="stylesheet" href="styles/dashboard.css"/>
<link rel="stylesheet" href="styles/schedule.css?v=2"/>
<link rel="stylesheet" href="styles/other.css?v=2"/>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" integrity="sha384-hD6/rw4ppMLGNu3tX5cjIb+uRZ7UkRJ6BPkLpg4hAu/6onKUg4lLsHAs9EBPT82L" crossorigin="anonymous"></script>
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" integrity="sha384-u6aeetuaXnQ38mYT8rp6sbXaQe3NL9t+IBXmnYxwkUI2Hw4bsp2Wvmx4yRQF1uAm" crossorigin="anonymous"></script>
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
<script type="text/babel" src="src/data.jsx"></script>
<script type="text/babel" src="src/Icon.jsx"></script>
<script type="text/babel" src="src/Shell.jsx"></script>
<script type="text/babel" src="src/Cabinet.jsx"></script>
<script type="text/babel" src="src/Dashboard.jsx"></script>
<script type="text/babel" src="src/Schedule.jsx"></script>
<script type="text/babel" src="src/OtherPages.jsx"></script>
<script type="text/babel">
const { useState, useEffect } = React;
const TWEAKS = /*EDITMODE-BEGIN*/{
"theme": "light",
"accent": "sage"
}/*EDITMODE-END*/;
const ACCENTS = {
sage: { brand: '#2f6b4a', deep: '#1e4a32', soft: '#e6efe8' },
cobalt: { brand: '#2e5aa8', deep: '#1d3d75', soft: '#e4eaf5' },
terracotta: { brand: '#b55438', deep: '#7d3825', soft: '#f6e6de' },
graphite: { brand: '#2c2c28', deep: '#000', soft: '#e8e6df' },
};
const App = () => {
const [route, setRoute] = useState('dashboard');
const [theme, setTheme] = useState(TWEAKS.theme || 'light');
const [accent, setAccent] = useState(TWEAKS.accent || 'sage');
const [tweaksOpen, setTweaksOpen] = useState(false);
useEffect(() => {
document.documentElement.setAttribute('data-theme', theme);
const a = ACCENTS[accent] || ACCENTS.sage;
document.documentElement.style.setProperty('--brand', a.brand);
document.documentElement.style.setProperty('--brand-deep', a.deep);
document.documentElement.style.setProperty('--brand-soft', a.soft);
document.documentElement.style.setProperty('--brand-soft-ink', a.deep);
document.documentElement.style.setProperty('--viz-1', a.brand);
}, [theme, accent]);
useEffect(() => {
const onMsg = (e) => {
if (!e.data || typeof e.data !== 'object') return;
if (e.data.type === '__activate_edit_mode') setTweaksOpen(true);
if (e.data.type === '__deactivate_edit_mode') setTweaksOpen(false);
};
window.addEventListener('message', onMsg);
window.parent.postMessage({ type: '__edit_mode_available' }, '*');
return () => window.removeEventListener('message', onMsg);
}, []);
const setTweak = (key, val) => {
window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [key]: val } }, '*');
};
const { Sidebar, Topbar, NAV } = window.Shell;
const current = NAV.find(n => n.id === route);
const pages = {
dashboard: { title: 'Dashboard', subtitle: 'Household: Red Panda Den', Page: window.DashboardPage },
cabinet: { title: 'Medicine Cabinet', subtitle: 'Everything on hand, with days of supply', Page: window.CabinetPage },
schedule: { title: 'Schedule & Log', subtitle: 'Today and this week', Page: window.SchedulePage },
regimens: { title: 'Regimens', subtitle: 'Daily medication schedules', crumbs: ['Medicines', 'Regimens'], Page: window.RegimensPage },
organizer: { title: 'Pill Organizer', subtitle: 'Fill a week of pills at once', crumbs: ['Medicines', 'Organizer'], Page: window.OrganizerPage },
activity: { title: 'Activity', subtitle: 'Spending and cabinet changes', crumbs: ['Medicines', 'Activity'], Page: window.ActivityPage },
library: { title: 'Library', subtitle: 'All known medicines', crumbs: ['Medicines', 'Library'], Page: window.LibraryPage },
refills: { title: 'Refills', subtitle: 'Running-low alerts and shopping lists', Page: window.RefillsPage },
purchases: { title: 'Purchases', subtitle: 'Order history and pending arrivals', Page: window.PurchasesPage },
prices: { title: 'Prices', subtitle: 'Track & compare across stores', Page: window.PricesPage },
stores: { title: 'Stores', subtitle: 'Pharmacies and vendors', Page: window.StoresPage },
settings: { title: 'Settings', subtitle: 'Household and account', Page: window.SettingsPage },
};
const pg = pages[route];
const Page = pg.Page;
return (
<div className="mt-app">
<Sidebar route={route} onNav={setRoute} />
<div className="mt-main" data-screen-label={'MT / ' + pg.title}>
<Topbar
title={pg.title}
subtitle={pg.subtitle}
crumbs={pg.crumbs}
theme={theme}
onToggleTheme={() => { const t = theme === 'light' ? 'dark' : 'light'; setTheme(t); setTweak('theme', t); }}
actions={route === 'cabinet' ? <button className="mt-btn mt-btn--primary"><span></span> Add to cabinet</button> : null}
/>
<Page onNav={setRoute} />
</div>
<div className={'mt-tweaks' + (tweaksOpen ? ' is-open' : '')}>
<div className="mt-tweaks__title">
<span>Tweaks</span>
<button className="mt-btn mt-btn--subtle" onClick={() => setTweaksOpen(false)} style={{padding:'2px 6px'}}>×</button>
</div>
<div className="mt-tweaks__row">
<span>Theme</span>
<div className="mt-seg">
<button className={theme==='light'?'is-active':''} onClick={()=>{setTheme('light'); setTweak('theme','light');}}>Light</button>
<button className={theme==='dark'?'is-active':''} onClick={()=>{setTheme('dark'); setTweak('theme','dark');}}>Dark</button>
</div>
</div>
<div className="mt-tweaks__row">
<span>Accent</span>
<div className="mt-seg">
{Object.keys(ACCENTS).map(k => (
<button key={k} className={accent===k?'is-active':''} onClick={()=>{setAccent(k); setTweak('accent',k);}} style={{textTransform:'capitalize'}}>{k}</button>
))}
</div>
</div>
<div style={{fontSize: 10, color: 'var(--ink-faint)', marginTop: 8, lineHeight: 1.5}}>
See alt-directions canvas for 3 novel cabinet layouts.
</div>
</div>
</div>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
</script>
</body>
</html>