80 lines
3.1 KiB
Python
80 lines
3.1 KiB
Python
"""Iteration 2: assemble self-contained pages.
|
|||
|
|
|
||
|
|
Each screen = v3 tokens (fonts inlined as base64) + iteration-1 app.css
|
||
|
|
utilities + components.css + page CSS, then data.js + app.js + page script.
|
||
|
|
Run: python3 build.py (writes ../screens/*.html)
|
||
|
|
"""
|
||
|
|
import base64, pathlib, re
|
||
|
|
|
||
|
|
HERE = pathlib.Path(__file__).resolve().parent
|
||
|
|
ROOT = HERE.parent.parent # ~/Design/extrudex-v3
|
||
|
|
OUT = HERE.parent / 'screens'
|
||
|
|
OUT.mkdir(exist_ok=True)
|
||
|
|
|
||
|
|
tokens = (ROOT / 'design-system-v3.css').read_text()
|
||
|
|
tokens = re.sub(r"url\('\./fonts/([^']+)'\)",
|
||
|
|
lambda m: "url('data:font/woff2;base64," + base64.b64encode((ROOT / 'fonts' / m.group(1)).read_bytes()).decode() + "')",
|
||
|
|
tokens)
|
||
|
|
base_css = (ROOT / 'source' / 'app.css').read_text()
|
||
|
|
comp_css = (HERE / 'components.css').read_text()
|
||
|
|
data_js = (HERE / 'data.js').read_text()
|
||
|
|
app_js = (HERE / 'app.js').read_text()
|
||
|
|
|
||
|
|
THEME = """<script>
|
||
|
|
(function () { var t = null; try { t = localStorage.getItem('extrudex-v3-theme'); } catch (e) {}
|
||
|
|
var q = /[?&]theme=(light|dark)/.exec(location.search); if (q) t = q[1];
|
||
|
|
if (t !== 'light' && t !== 'dark') t = window.matchMedia && matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||
|
|
document.documentElement.setAttribute('data-theme', t); })();
|
||
|
|
</script>"""
|
||
|
|
|
||
|
|
def build(slug, title, desc):
|
||
|
|
src = (HERE / 'pages' / f'{slug}.html').read_text()
|
||
|
|
css = ''.join(re.findall(r'<style>(.*?)</style>', src, re.S))
|
||
|
|
js = ''.join(re.findall(r'<script>(.*?)</script>', src, re.S))
|
||
|
|
html = f"""<!doctype html>
|
||
|
|
<html lang="en" data-theme="dark">
|
||
|
|
<head>
|
||
|
|
<meta charset="utf-8">
|
||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
|
|
<title>{title}</title>
|
||
|
|
<meta name="description" content="{desc}">
|
||
|
|
{THEME}
|
||
|
|
<style>
|
||
|
|
{tokens}
|
||
|
|
{base_css}
|
||
|
|
{comp_css}
|
||
|
|
{css}
|
||
|
|
</style>
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<script>
|
||
|
|
{data_js}
|
||
|
|
{app_js}
|
||
|
|
</script>
|
||
|
|
<script>
|
||
|
|
{js}
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|
||
|
|
"""
|
||
|
|
(OUT / f'{slug}.html').write_text(html)
|
||
|
|
print(slug, len(html) // 1024, 'KB')
|
||
|
|
|
||
|
|
PAGES = [
|
||
|
|
('index', 'Extrudex Flow Map', 'How the iteration-2 screens connect, with guided flows.'),
|
||
|
|
('01-dashboard', 'Extrudex Dashboard', 'Attention-first dashboard, iteration 3.'),
|
||
|
|
('02-filament', 'Extrudex Filament', 'Filament inventory with drawer, filters and weigh session, iteration 3.'),
|
||
|
|
('03-prints', 'Extrudex Prints', 'Print history and attribution queue, iteration 3.'),
|
||
|
|
('04-printers', 'Extrudex Printers', 'Printers with holders, load flow, admin panels and connection state.'),
|
||
|
|
('05-lists', 'Extrudex Lists', 'Taxonomy lists the spool name is built from.'),
|
||
|
|
('06-labels', 'Extrudex Labels', 'Spool and holder QR labels.'),
|
||
|
|
('07-access', 'Extrudex Access', 'People, sessions, machines and API tokens.'),
|
||
|
|
('08-system', 'Extrudex System', 'Low-filament report, audit log and this device.'),
|
||
|
|
('09-scan-holder', 'Extrudex Holder Scan', 'Phone-first holder scan session.'),
|
||
|
|
('10-scan-spool', 'Extrudex Spool Scan', 'Phone-first scanned spool and weigh-in.'),
|
||
|
|
('devices', 'Extrudex Devices', 'Every screen in phone and tablet frames.'),
|
||
|
|
]
|
||
|
|
for p in PAGES:
|
||
|
|
if (HERE / 'pages' / f'{p[0]}.html').exists():
|
||
|
|
build(*p)
|