Living documentation for maintaining UI consistency across all pages
This style guide defines the design system for the Tanach project. All user-facing pages MUST follow these guidelines to ensure a consistent user experience.
Key Principles:
tanach-common.css
Design tokens are defined in src/css/tanach-common.css. All pages MUST use these tokens instead of hardcoded values.
All user-facing pages MUST include the theme toggle component using the Web Component.
The theme toggle appears in the lower left corner (see bottom of page).
<!-- In the <body> tag -->
<script type="module" src="src/js/components/ThemeToggle.js"></script>
<theme-toggle></theme-toggle>
<!-- For subdirectories, add path-prefix attribute -->
<theme-toggle path-prefix="../"></theme-toggle>
<!-- Theme Toggle -->
<div id="theme-toggle" class="btn-group position-fixed"
style="bottom: 20px; left: 20px; z-index: 1000; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<button class="btn btn-outline-secondary" data-theme="light" title="Light Theme">
<i class="bi bi-sun-fill"></i>
</button>
<button class="btn btn-outline-secondary" data-theme="dark" title="Dark Theme">
<i class="bi bi-moon-fill"></i>
</button>
<button class="btn btn-outline-secondary" data-theme="system" title="System Theme">
<i class="bi bi-display"></i>
</button>
</div>
<!-- Theme Manager Script -->
<script src="src/js/ThemeManager.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
ThemeManager.initialize();
});
</script>
bottom: 20px, left: 20pxbtn-outline-secondary class (NOT btn-secondary)bi-sun-fill for light themebi-moon-fill for dark themebi-display for system themez-index: 10000 2px 10px rgba(0,0,0,0.2)bi-moon-stars-fill, bi-circle-half)The language switcher allows users to change the interface language. All user-facing pages MUST include the language switcher with flag menu to allow users to switch between English, Hebrew, and French interfaces. The switcher uses the Lang system lang.js for dynamic translation loading.
<!-- Include Language CSS -->
<link rel="stylesheet" href="src/css/lang.css" type="text/css">
<!-- Language Switcher (in <body> tag) -->
<div class="language-flag-container" style="position: fixed; left: 20px; top: 20px; z-index: 1001;">
<button class="current-flag-btn" id="current-flag-btn" title="Change Language">
<img id="current-flag-icon" src="src/images/flags/gb.svg" alt="English" class="flag-icon">
</button>
<div class="flag-menu" id="flag-menu">
<button class="flag-menu-item" onclick="Lang.load('en')" data-lang="en">
<img src="src/images/flags/gb.svg" alt="English" class="flag-icon">
<span>English</span>
</button>
<button class="flag-menu-item" onclick="Lang.load('he')" data-lang="he">
<img src="src/images/flags/il.svg" alt="עברית" class="flag-icon">
<span>עברית</span>
</button>
<button class="flag-menu-item" onclick="Lang.load('fr')" data-lang="fr">
<img src="src/images/flags/fr.svg" alt="Français" class="flag-icon">
<span>Français</span>
</button>
</div>
</div>
<!-- Language Manager Script -->
<script src="src/js/lang.js"></script>
Add data-i18n attributes to elements that need translation:
<h1 data-i18n="page_title">Default English Text</h1>
<button data-i18n="submit_button">Submit</button>
<label for="input" data-i18n="field_label">Field Label</label>
Translation files are located in build/nodejs/public/locales/:
en.json - English translationshe.json - Hebrew translationsfr.json - French translationstop: 20px, left: 20pxz-index: 1001 (above theme toggle)lang.css stylesheetlang.js scriptdata-i18n attributes to all translatable textasync function initializePage() {
// Initialize Lang system FIRST
if (window.Lang && window.Lang.init) {
await window.Lang.init();
if (window.Lang.initializeFlagMenu) {
window.Lang.initializeFlagMenu();
}
}
// ... rest of initialization
}
The page header component provides consistent headers across pages.
<script type="module" src="src/js/components/PageHeader.js"></script>
<page-header title="התנ"ך - Hebrew Bible" subtitle="Optional subtitle"></page-header>
Web Components provide reusable, consistent UI elements.
| Component | File | Usage | Status |
|---|---|---|---|
<theme-toggle> |
src/js/components/ThemeToggle.js |
Theme switching buttons | MANDATORY |
| Language Switcher | src/js/lang.js |
Language selection menu | RECOMMENDED |
<page-header> |
src/js/components/PageHeader.js |
Page title and subtitle | OPTIONAL |
Typography tokens ensure consistent font sizing and hierarchy.
--font-size-xs: 0.75rem (12px)--font-size-sm: 0.875rem (14px)--font-size-base: 1rem (16px)--font-size-lg: 1.125rem (18px)--font-size-xl: 1.25rem (20px)--font-size-2xl: 1.5rem (24px)--font-size-3xl: 1.75rem (28px)--font-size-4xl: 2rem (32px)--font-size-5xl: 2.5rem (40px)Color tokens automatically adapt to light and dark themes.
Use spacing tokens for consistent margins and padding.
/* Use spacing tokens instead of hardcoded values */
.my-element {
margin: var(--spacing-lg); /* Good ✅ */
margin: 20px; /* Bad ❌ */
padding: var(--spacing-md); /* Good ✅ */
padding: 12px; /* Bad ❌ */
}
tanach-common.cssleft: 20px; bottom: 20px;tanach-common.css for colors, spacing, typographyStandard Layout Pattern:
top: 20px; left: 20px;1001 (above theme toggle)pasuk.html, Book selector in BasicTropsMulti.htmlbottom: 20px; left: 20px;1000Rationale: Separating settings (top) from theme controls (bottom) creates clear visual hierarchy and prevents button overlap.