diff options
| author | Paul Buetow <paul@buetow.org> | 2025-06-22 22:06:43 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-06-22 22:06:43 +0300 |
| commit | 3af674aebad9e3792fbf13b3cbda7b1691b1f4f3 (patch) | |
| tree | c70f6033d21628579d96044c89a060e9031dbf8b /extras/html/themes/index.html | |
| parent | 99078f90bf5222c618a60e536cb148850e4b89e2 (diff) | |
Add 50 new experimental HTML themes for Gemtexter
- Generated 50 unique themes with creative layouts and color schemes
- Each theme includes:
- Custom CSS with W3C validated styles
- Example HTML preview page
- Font files with proper licensing
- Theme configuration file
- License documentation
- Layout types include: centered, wide, magazine, card, brutalist,
terminal, book, hero, sidebar, and more creative designs
- All themes support both light and dark color schemes
- Fixed CSS validation issues for W3C compliance
- Created theme gallery page at extras/html/themes/index.html
- Added screenshot previews for all themes
- Utility scripts included:
- generate_50_themes.py - Main theme generator
- fix_css_validation.py - CSS validator/fixer
- create_theme_previews.py - Screenshot generator
- Theme gallery with filtering at index.html
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'extras/html/themes/index.html')
| -rw-r--r-- | extras/html/themes/index.html | 469 |
1 files changed, 469 insertions, 0 deletions
diff --git a/extras/html/themes/index.html b/extras/html/themes/index.html new file mode 100644 index 0000000..ecef268 --- /dev/null +++ b/extras/html/themes/index.html @@ -0,0 +1,469 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Gemtexter Theme Gallery - 50 Unique Themes</title> + <style> + * { + box-sizing: border-box; + margin: 0; + padding: 0; + } + + body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + background-color: #f5f5f5; + color: #333; + line-height: 1.6; + } + + .header { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + text-align: center; + padding: 4em 2em; + box-shadow: 0 4px 20px rgba(0,0,0,0.1); + } + + .header h1 { + font-size: 3em; + margin-bottom: 0.5em; + text-shadow: 2px 2px 4px rgba(0,0,0,0.2); + } + + .header p { + font-size: 1.2em; + opacity: 0.9; + max-width: 600px; + margin: 0 auto; + } + + .container { + max-width: 1400px; + margin: 0 auto; + padding: 2em; + } + + .filters { + background: white; + padding: 2em; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0,0,0,0.05); + margin-bottom: 3em; + text-align: center; + } + + .filters h2 { + margin-bottom: 1em; + color: #667eea; + } + + .filter-buttons { + display: flex; + flex-wrap: wrap; + gap: 1em; + justify-content: center; + } + + .filter-btn { + padding: 0.5em 1.5em; + border: 2px solid #667eea; + background: white; + color: #667eea; + border-radius: 25px; + cursor: pointer; + transition: all 0.3s ease; + font-size: 1em; + } + + .filter-btn:hover, .filter-btn.active { + background: #667eea; + color: white; + } + + .theme-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); + gap: 2em; + } + + .theme-card { + background: white; + border-radius: 12px; + overflow: hidden; + box-shadow: 0 4px 20px rgba(0,0,0,0.08); + transition: transform 0.3s ease, box-shadow 0.3s ease; + position: relative; + } + + .theme-card:hover { + transform: translateY(-4px); + box-shadow: 0 8px 30px rgba(0,0,0,0.12); + } + + .theme-preview { + height: 200px; + background: #f0f0f0; + position: relative; + overflow: hidden; + } + + .theme-preview img { + width: 100%; + height: 100%; + object-fit: cover; + } + + .theme-preview-placeholder { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + font-size: 3em; + font-weight: bold; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + } + + .theme-info { + padding: 1.5em; + } + + .theme-name { + font-size: 1.3em; + font-weight: bold; + margin-bottom: 0.5em; + color: #333; + } + + .theme-details { + color: #666; + font-size: 0.9em; + margin-bottom: 1em; + } + + .theme-tags { + display: flex; + flex-wrap: wrap; + gap: 0.5em; + margin-bottom: 1em; + } + + .tag { + padding: 0.2em 0.8em; + background: #f0f0f0; + border-radius: 15px; + font-size: 0.85em; + color: #666; + } + + .tag.layout { + background: #e3f2fd; + color: #1976d2; + } + + .tag.color { + background: #fce4ec; + color: #c2185b; + } + + .theme-actions { + display: flex; + gap: 1em; + } + + .btn { + flex: 1; + padding: 0.8em; + text-align: center; + text-decoration: none; + border-radius: 8px; + transition: all 0.3s ease; + font-weight: 500; + } + + .btn-preview { + background: #667eea; + color: white; + } + + .btn-preview:hover { + background: #5a67d8; + } + + .btn-download { + background: white; + color: #667eea; + border: 2px solid #667eea; + } + + .btn-download:hover { + background: #667eea; + color: white; + } + + .footer { + text-align: center; + padding: 3em 2em; + color: #666; + background: white; + margin-top: 4em; + } + + .stats { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 2em; + margin: 3em 0; + text-align: center; + } + + .stat { + background: white; + padding: 2em; + border-radius: 12px; + box-shadow: 0 2px 10px rgba(0,0,0,0.05); + } + + .stat-number { + font-size: 3em; + font-weight: bold; + color: #667eea; + } + + .stat-label { + color: #666; + margin-top: 0.5em; + } + + @media (max-width: 768px) { + .header h1 { + font-size: 2em; + } + + .theme-grid { + grid-template-columns: 1fr; + } + } + </style> +</head> +<body> + <div class="header"> + <h1>Gemtexter Theme Gallery</h1> + <p>50 unique, hand-crafted themes for your Gemtext content. Each theme features carefully selected fonts, harmonious color palettes, and distinctive layouts.</p> + </div> + + <div class="container"> + <div class="stats"> + <div class="stat"> + <div class="stat-number">50</div> + <div class="stat-label">Unique Themes</div> + </div> + <div class="stat"> + <div class="stat-number">24</div> + <div class="stat-label">Layout Types</div> + </div> + <div class="stat"> + <div class="stat-number">15</div> + <div class="stat-label">Font Families</div> + </div> + <div class="stat"> + <div class="stat-number">∞</div> + <div class="stat-label">Possibilities</div> + </div> + </div> + + <div class="filters"> + <h2>Filter by Layout</h2> + <div class="filter-buttons"> + <button class="filter-btn active" onclick="filterThemes('all')">All Themes</button> + <button class="filter-btn" onclick="filterThemes('centered')">Centered</button> + <button class="filter-btn" onclick="filterThemes('wide')">Wide</button> + <button class="filter-btn" onclick="filterThemes('magazine')">Magazine</button> + <button class="filter-btn" onclick="filterThemes('card')">Card</button> + <button class="filter-btn" onclick="filterThemes('minimal')">Minimal</button> + <button class="filter-btn" onclick="filterThemes('brutalist')">Brutalist</button> + <button class="filter-btn" onclick="filterThemes('terminal')">Terminal</button> + <button class="filter-btn" onclick="filterThemes('book')">Book</button> + <button class="filter-btn" onclick="filterThemes('hero')">Hero</button> + <button class="filter-btn" onclick="filterThemes('dark')">Dark Themes</button> + <button class="filter-btn" onclick="filterThemes('light')">Light Themes</button> + </div> + </div> + + <div class="theme-grid" id="themeGrid"> + <!-- Themes will be inserted here by JavaScript --> + </div> + </div> + + <div class="footer"> + <p>All themes are free to use and include properly licensed fonts.</p> + <p>Generated with love for the Gemtexter community.</p> + </div> + + <script> + // Theme data + const themes = [ + {name: "vibrant_garden", layout: "hero", colorType: "light", fonts: ["Abril Fatface", "Lato"]}, + {name: "pure_voyage", layout: "brutalist", colorType: "dark", fonts: ["Oxygen", "Lato"]}, + {name: "twilight_nebula", layout: "floating", colorType: "dark", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "mystic_canyon", layout: "future", colorType: "dark", fonts: ["Merriweather", "Oxygen"]}, + {name: "dynamic_forest", layout: "future", colorType: "light", fonts: ["Higher Jump", "Lato"]}, + {name: "soft_horizon", layout: "geometric", colorType: "light", fonts: ["Pixelon", "Oxygen"]}, + {name: "pastel_crystal", layout: "newspaper", colorType: "light", fonts: ["Repetition Scrolling", "Merriweather"]}, + {name: "bright_light", layout: "magazine", colorType: "light", fonts: ["Typewriter", "Roboto Slab"]}, + {name: "crisp_oasis", layout: "asymmetric", colorType: "light", fonts: ["Khand", "Lato"]}, + {name: "sharp_canyon", layout: "card", colorType: "dark", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "strong_breeze", layout: "terminal", colorType: "dark", fonts: ["Oxygen", "Merriweather"]}, + {name: "aurora_dawn", layout: "swiss", colorType: "dark", fonts: ["Merriweather", "Roboto Slab"]}, + {name: "mystic_meadow", layout: "artistic", colorType: "light", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "vibrant_nebula", layout: "overlap", colorType: "dark", fonts: ["Higher Jump", "Oxygen"]}, + {name: "sleek_river", layout: "sidebar", colorType: "light", fonts: ["Pixelon", "Roboto Slab"]}, + {name: "clear_forest", layout: "gradient", colorType: "light", fonts: ["Repetition Scrolling", "Merriweather"]}, + {name: "bold_pulse", layout: "book", colorType: "dark", fonts: ["Typewriter", "Roboto Slab"]}, + {name: "fresh_field", layout: "organic", colorType: "light", fonts: ["Oxygen", "Lato"]}, + {name: "clear_frost", layout: "newspaper", colorType: "dark", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "ember_mountain", layout: "brutalist", colorType: "light", fonts: ["Oxygen", "Lato"]}, + {name: "refined_oasis", layout: "centered", colorType: "dark", fonts: ["Abril Fatface", "Lato"]}, + {name: "sharp_mountain", layout: "wide", colorType: "light", fonts: ["Roboto Slab", "Lato"]}, + {name: "deep_crystal", layout: "geometric", colorType: "dark", fonts: ["Abril Fatface", "Merriweather"]}, + {name: "cozy_wave", layout: "overlap", colorType: "light", fonts: ["Roboto Slab", "Lato"]}, + {name: "ember_mist", layout: "hero", colorType: "dark", fonts: ["Oxygen", "Merriweather"]}, + {name: "vibrant_storm", layout: "technical", colorType: "light", fonts: ["Merriweather", "Roboto Slab"]}, + {name: "pure_storm", layout: "organic", colorType: "dark", fonts: ["Higher Jump", "Oxygen"]}, + {name: "cool_breeze", layout: "artistic", colorType: "light", fonts: ["Pixelon", "Roboto Slab"]}, + {name: "ethereal_mist", layout: "minimal_grid", colorType: "dark", fonts: ["Repetition Scrolling", "Merriweather"]}, + {name: "modern_rhythm", layout: "split", colorType: "light", fonts: ["Typewriter", "Roboto Slab"]}, + {name: "aurora_breeze", layout: "terminal", colorType: "dark", fonts: ["Khand", "Lato"]}, + {name: "muted_oasis", layout: "centered", colorType: "light", fonts: ["Oxygen", "Lato"]}, + {name: "ember_night", layout: "masonry", colorType: "dark", fonts: ["Roboto Slab", "Lato"]}, + {name: "modern_storm", layout: "book", colorType: "light", fonts: ["Oxygen", "Oxygen"]}, + {name: "amber_glacier", layout: "magazine", colorType: "dark", fonts: ["Roboto Slab", "Merriweather"]}, + {name: "twilight_horizon", layout: "card", colorType: "light", fonts: ["Merriweather", "Roboto Slab"]}, + {name: "gentle_glacier", layout: "swiss", colorType: "dark", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "deep_sky", layout: "future", colorType: "light", fonts: ["Higher Jump", "Oxygen"]}, + {name: "smooth_echo", layout: "sidebar", colorType: "dark", fonts: ["Pixelon", "Roboto Slab"]}, + {name: "refined_aurora", layout: "wide", colorType: "light", fonts: ["Repetition Scrolling", "Merriweather"]}, + {name: "radiant_voyage", layout: "gradient", colorType: "dark", fonts: ["Typewriter", "Roboto Slab"]}, + {name: "cosmic_odyssey", layout: "hero", colorType: "light", fonts: ["Oxygen", "Lato"]}, + {name: "neon_storm", layout: "brutalist", colorType: "dark", fonts: ["Abril Fatface", "Lato"]}, + {name: "cosmic_dusk", layout: "retro", colorType: "light", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "cozy_crystal", layout: "asymmetric", colorType: "dark", fonts: ["Oxygen", "Lato"]}, + {name: "clean_rhythm", layout: "floating", colorType: "light", fonts: ["Merriweather", "Oxygen"]}, + {name: "pastel_canyon", layout: "minimal_grid", colorType: "dark", fonts: ["Higher Jump", "Lato"]}, + {name: "clean_garden", layout: "newspaper", colorType: "light", fonts: ["Pixelon", "Oxygen"]}, + {name: "twilight_meadow", layout: "masonry", colorType: "dark", fonts: ["Roboto Slab", "Oxygen"]}, + {name: "bright_spark", layout: "split", colorType: "light", fonts: ["Roboto Slab", "Oxygen"]} + ]; + + // Generate theme cards + function generateThemeCards() { + const grid = document.getElementById('themeGrid'); + + themes.forEach(theme => { + const card = document.createElement('div'); + card.className = 'theme-card'; + card.setAttribute('data-layout', theme.layout); + card.setAttribute('data-color', theme.colorType); + + const initial = theme.name.split('_').map(w => w[0].toUpperCase()).join(''); + + card.innerHTML = ` + <div class="theme-preview"> + ${getThemePreview(theme)} + </div> + <div class="theme-info"> + <div class="theme-name">${theme.name.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase())}</div> + <div class="theme-details">${theme.fonts.join(' + ')}</div> + <div class="theme-tags"> + <span class="tag layout">${theme.layout.replace(/_/g, ' ')}</span> + <span class="tag color">${theme.colorType}</span> + </div> + <div class="theme-actions"> + <a href="${theme.name}/example.html" class="btn btn-preview">Preview</a> + <a href="#" class="btn btn-download" onclick="downloadTheme('${theme.name}'); return false;">Download</a> + </div> + </div> + `; + + grid.appendChild(card); + }); + } + + function getThemePreview(theme) { + // Check if screenshot exists and use it, otherwise show placeholder + const screenshotPath = `screenshots/${theme.name}.png`; + + // Use the actual screenshot image + return ` + <img src="${screenshotPath}" alt="${theme.name} preview" + onerror="this.onerror=null; this.outerHTML=getFallbackPreview('${theme.name}', '${theme.layout}', '${theme.colorType}');" + style="width: 100%; height: 100%; object-fit: cover;"> + `; + } + + function getFallbackPreview(name, layout, colorType) { + // Fallback placeholder if image fails to load + const colors = { + 'dark': ['#0a0a0a', '#1a1a1a', '#2a2a2a'], + 'light': ['#ffffff', '#f8f8f8', '#eeeeee'] + }; + + const bgColor = colors[colorType][0]; + const accentColor = colorType === 'dark' ? '#667eea' : '#764ba2'; + const textColor = colorType === 'dark' ? '#ffffff' : '#1a1a1a'; + + return ` + <div class="theme-preview-placeholder" style="background: ${bgColor}; color: ${textColor}; position: relative; overflow: hidden;"> + <div style="position: absolute; top: 0; left: 0; right: 0; height: 60px; background: ${accentColor}; opacity: 0.8;"></div> + <div style="position: relative; z-index: 1; font-size: 2.5em; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);"> + ${name.split('_').map(w => w[0].toUpperCase()).join('')} + </div> + <div style="position: absolute; bottom: 10px; left: 10px; right: 10px; font-size: 0.8em; opacity: 0.7;"> + ${layout.replace(/_/g, ' ')} + </div> + </div> + `; + } + + // Filter themes + function filterThemes(filter) { + const cards = document.querySelectorAll('.theme-card'); + const buttons = document.querySelectorAll('.filter-btn'); + + // Update active button + buttons.forEach(btn => { + btn.classList.remove('active'); + if (btn.textContent.toLowerCase().includes(filter) || (filter === 'all' && btn.textContent === 'All Themes')) { + btn.classList.add('active'); + } + }); + + // Filter cards + cards.forEach(card => { + if (filter === 'all') { + card.style.display = 'block'; + } else if (filter === 'dark' || filter === 'light') { + card.style.display = card.getAttribute('data-color') === filter ? 'block' : 'none'; + } else { + const layout = card.getAttribute('data-layout'); + card.style.display = layout.includes(filter) ? 'block' : 'none'; + } + }); + } + + // Download theme (placeholder function) + function downloadTheme(themeName) { + alert(`To use the "${themeName}" theme:\n\n1. Copy the ${themeName} directory to your themes folder\n2. Set HTML_THEME_DIR=./extras/html/themes/${themeName} in your gemtexter.conf\n3. Run ./gemtexter --generate to apply the theme`); + } + + // Make getFallbackPreview available globally for onerror handler + window.getFallbackPreview = getFallbackPreview; + + // Initialize + generateThemeCards(); + </script> +</body> +</html>
\ No newline at end of file |
