Files
ObsidianDragon/scripts/expand_themes.py
dan_s 9e94952e0a v1.1.0: explorer tab, bootstrap fixes, full theme overlay merge
Explorer tab:
- New block explorer tab with search, chain stats, mempool info,
  recent blocks table, block detail modal with tx expansion
- Sidebar nav entry, i18n strings, ui.toml layout values

Bootstrap fixes:
- Move wizard Done handler into render() — was dead code, preventing
  startEmbeddedDaemon() and tryConnect() from firing post-wizard
- Stop deleting BDB database/ dir during cleanup — caused LSN mismatch
  that salvaged wallet.dat into wallet.{timestamp}.bak
- Add banlist.dat, db.log, .lock to cleanup file list
- Fatal extraction failure for blocks/ and chainstate/ files
- Verification progress: split SHA-256 (0-50%) and MD5 (50-100%)

Theme system:
- Expand overlay merge to apply ALL sections (tabs, dialogs, components,
  screens, flat sections), not just theme+backdrop+effects
- Add screens and security section parsing to UISchema
- Build-time theme expansion via expand_themes.py (CMake + build.sh)

Other:
- Version bump to 1.1.0
- WalletState::clear() resets all fields (sync, daemon info, etc.)
- Sidebar item-height 42 → 36
2026-03-17 18:49:46 -05:00

123 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""
Build-time theme expander — merges layout sections from ui.toml into skin files.
Called by CMake during build. Reads source skin files + ui.toml, writes merged
output files to the build directory. Source files are never modified.
Usage:
python3 expand_themes.py <source_themes_dir> <output_themes_dir>
For each .toml file in source_themes_dir (except ui.toml), the script:
1. Copies the skin file contents (theme/palette/backdrop/effects)
2. Appends all layout sections from ui.toml (fonts, tabs, components, etc.)
3. Writes the merged result to output_themes_dir/<filename>
ui.toml itself is copied unchanged.
"""
import re
import sys
import os
# Sections to SKIP when extracting from ui.toml (theme-specific, already in skins)
SKIP_SECTIONS = {"theme", "theme.palette", "backdrop", "effects"}
def extract_layout_sections(ui_toml_path):
"""Extract non-theme sections from ui.toml as a string."""
sections = []
current_section = None
current_lines = []
section_re = re.compile(r'^\[{1,2}([^\]]+)\]{1,2}\s*$')
with open(ui_toml_path, 'r') as f:
for line in f:
m = section_re.match(line.strip())
if m:
if current_section is not None or current_lines:
sections.append((current_section, current_lines))
current_section = m.group(1).strip()
current_lines = [line]
else:
current_lines.append(line)
if current_section is not None or current_lines:
sections.append((current_section, current_lines))
layout_parts = []
for section_name, lines in sections:
if section_name is None:
# Preamble: only include top-level key=value lines
kv_lines = [l for l in lines
if l.strip() and not l.strip().startswith('#') and '=' in l]
if kv_lines:
layout_parts.append(''.join(kv_lines))
continue
if section_name in SKIP_SECTIONS:
continue
layout_parts.append(''.join(lines))
return '\n'.join(layout_parts)
def main():
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <source_themes_dir> <output_themes_dir>")
sys.exit(1)
src_dir = sys.argv[1]
out_dir = sys.argv[2]
ui_toml = os.path.join(src_dir, "ui.toml")
if not os.path.exists(ui_toml):
print(f"ERROR: ui.toml not found at {ui_toml}")
sys.exit(1)
os.makedirs(out_dir, exist_ok=True)
layout_content = extract_layout_sections(ui_toml)
separator = (
"\n# ===========================================================================\n"
"# Layout & Component Properties\n"
"# All values below can be customized per-theme. Edit and save to see\n"
"# changes reflected in the app in real time via hot-reload.\n"
"# ===========================================================================\n\n"
)
for fname in sorted(os.listdir(src_dir)):
if not fname.endswith('.toml'):
continue
src_path = os.path.join(src_dir, fname)
dst_path = os.path.join(out_dir, fname)
if fname == "ui.toml":
# Copy ui.toml unchanged
with open(src_path, 'r') as f:
content = f.read()
with open(dst_path, 'w') as f:
f.write(content)
print(f" COPY {fname}")
continue
# Skin file — append layout sections
with open(src_path, 'r') as f:
skin = f.read()
if not skin.endswith('\n'):
skin += '\n'
merged = skin + separator + layout_content
if not merged.endswith('\n'):
merged += '\n'
with open(dst_path, 'w') as f:
f.write(merged)
lines = merged.count('\n')
print(f" MERGE {fname}{lines} lines")
print("Done.")
if __name__ == "__main__":
main()