Fixing theme button
Homelab Main / deploy (push) Successful in 1m21s Details

This commit is contained in:
juvdiaz 2026-05-29 11:12:20 -06:00
parent 47c018b6dc
commit b5fb1d1190
8 changed files with 409 additions and 21 deletions

View File

@ -385,3 +385,142 @@ pre {
flex-direction: column; flex-direction: column;
} }
} }
body.theme-dark {
background: #000;
color: #39ff14;
font-family: "Courier New", "Lucida Console", Monaco, monospace;
font-size: 1rem;
line-height: 1.56;
}
body.theme-light {
background: #fffff0;
color: #1b1610;
font-family: "Brush Script MT", "Segoe Script", "Snell Roundhand", "Apple Chancery", cursive;
font-size: 1.12rem;
line-height: 1.68;
}
body.theme-dark .topline a,
body.theme-dark .site-theme-toolbar,
body.theme-dark .kicker,
body.theme-dark h1,
body.theme-dark h2,
body.theme-dark h3,
body.theme-dark label,
body.theme-dark strong,
body.theme-dark a {
color: #7cff7c;
font-family: inherit;
}
body.theme-dark p,
body.theme-dark span,
body.theme-dark li,
body.theme-dark .note,
body.theme-dark .catalog-card p,
body.theme-dark .result-row span,
body.theme-dark .stats span {
color: #39ff14;
}
body.theme-dark .hero,
body.theme-dark .panel,
body.theme-dark .catalog-card,
body.theme-dark .drop-zone,
body.theme-dark .result-row,
body.theme-dark .stats span {
background: #000;
border-color: #1fbf3a;
color: #39ff14;
box-shadow: 0 0 16px rgba(57, 255, 20, 0.16);
}
body.theme-dark button,
body.theme-dark .download-link,
body.theme-dark .site-theme-option {
background: #000;
border: 1px solid #39ff14;
color: #39ff14;
font-family: inherit;
}
body.theme-dark button:hover,
body.theme-dark .download-link:hover,
body.theme-dark .site-theme-option.is-active {
background: #062b06;
color: #b6ffb6;
}
body.theme-dark select,
body.theme-dark input,
body.theme-dark textarea,
body.theme-dark canvas,
body.theme-dark .output,
body.theme-dark pre {
background: #000;
border-color: #1fbf3a;
color: #39ff14;
font-family: inherit;
}
body.theme-light .topline a,
body.theme-light .site-theme-toolbar,
body.theme-light .kicker,
body.theme-light h1,
body.theme-light h2,
body.theme-light h3,
body.theme-light label,
body.theme-light strong,
body.theme-light a,
body.theme-light p,
body.theme-light span,
body.theme-light li,
body.theme-light .note,
body.theme-light .catalog-card p,
body.theme-light .result-row span,
body.theme-light .stats span {
color: #1b1610;
font-family: inherit;
}
body.theme-light .hero,
body.theme-light .panel,
body.theme-light .catalog-card,
body.theme-light .drop-zone,
body.theme-light .result-row,
body.theme-light .stats span {
background: #fffff0;
border-color: #1b1610;
color: #1b1610;
box-shadow: none;
}
body.theme-light button,
body.theme-light .download-link,
body.theme-light .site-theme-option {
background: #fffff0;
border: 1px solid #1b1610;
color: #1b1610;
font-family: inherit;
}
body.theme-light button:hover,
body.theme-light .download-link:hover,
body.theme-light .site-theme-option.is-active {
background: #1b1610;
color: #fffff0;
}
body.theme-light select,
body.theme-light input,
body.theme-light textarea,
body.theme-light canvas,
body.theme-light .output,
body.theme-light pre {
background: #fffff0;
border-color: #1b1610;
color: #1b1610;
font-family: inherit;
}

View File

@ -1,32 +1,40 @@
const demoThemeButtons = [];
const demoThemeStorageKey = 'site-theme'; const demoThemeStorageKey = 'site-theme';
const legacyDemoThemeStorageKey = 'cv-theme';
function normalizeDemoTheme(theme) { function normalizeDemoTheme(theme) {
return theme === 'light' ? 'light' : 'dark'; return theme === 'light' || theme === 'fancy' ? 'light' : 'dark';
} }
function getStoredDemoTheme() { function getStoredDemoTheme() {
try { try {
return localStorage.getItem(demoThemeStorageKey); return localStorage.getItem(demoThemeStorageKey) || localStorage.getItem(legacyDemoThemeStorageKey);
} catch (_error) { } catch (_error) {
return null; return null;
} }
} }
function storeDemoTheme(theme) { function storeDemoTheme(theme) {
const nextTheme = normalizeDemoTheme(theme);
try { try {
localStorage.setItem(demoThemeStorageKey, theme); localStorage.setItem(demoThemeStorageKey, nextTheme);
localStorage.removeItem(legacyDemoThemeStorageKey);
} catch (_error) { } catch (_error) {
} }
} }
function getDemoThemeButtons() {
return [...document.querySelectorAll('[data-site-theme]')];
}
function setDemoTheme(theme) { function setDemoTheme(theme) {
const nextTheme = normalizeDemoTheme(theme); const nextTheme = normalizeDemoTheme(theme);
document.documentElement.classList.toggle('theme-light', nextTheme === 'light');
document.documentElement.classList.toggle('theme-dark', nextTheme === 'dark');
document.body.classList.toggle('theme-light', nextTheme === 'light'); document.body.classList.toggle('theme-light', nextTheme === 'light');
document.body.classList.toggle('theme-dark', nextTheme === 'dark'); document.body.classList.toggle('theme-dark', nextTheme === 'dark');
demoThemeButtons.forEach((button) => { getDemoThemeButtons().forEach((button) => {
const active = button.dataset.siteTheme === nextTheme; const active = normalizeDemoTheme(button.dataset.siteTheme) === nextTheme;
button.classList.toggle('is-active', active); button.classList.toggle('is-active', active);
button.setAttribute('aria-pressed', active ? 'true' : 'false'); button.setAttribute('aria-pressed', active ? 'true' : 'false');
}); });
@ -43,12 +51,13 @@ function installDemoThemeToolbar() {
toolbar.setAttribute('aria-label', 'Theme'); toolbar.setAttribute('aria-label', 'Theme');
toolbar.innerHTML = '<span>Theme</span><button type="button" class="site-theme-option" data-site-theme="dark">Dark</button><span class="site-theme-separator" aria-hidden="true">|</span><button type="button" class="site-theme-option" data-site-theme="light">Light</button>'; toolbar.innerHTML = '<span>Theme</span><button type="button" class="site-theme-option" data-site-theme="dark">Dark</button><span class="site-theme-separator" aria-hidden="true">|</span><button type="button" class="site-theme-option" data-site-theme="light">Light</button>';
nav.appendChild(toolbar); nav.appendChild(toolbar);
demoThemeButtons.push(...toolbar.querySelectorAll('[data-site-theme]'));
demoThemeButtons.forEach((button) => {
button.addEventListener('click', () => setDemoTheme(button.dataset.siteTheme));
});
} }
document.addEventListener('click', (event) => {
const button = event.target.closest('[data-site-theme]');
if (!button) return;
setDemoTheme(button.dataset.siteTheme);
});
installDemoThemeToolbar(); installDemoThemeToolbar();
setDemoTheme(getStoredDemoTheme() || 'dark'); setDemoTheme(getStoredDemoTheme() || 'dark');

View File

@ -890,7 +890,7 @@ function renderStackSourceLinks(string $stackKey, array $sourceLinks, string $so
</main> </main>
<script> <script>
const OTHER_PAGES = ['/index.php', '/cv.php', '/homelab-tree.php']; window.OTHER_PAGES = ['/index.php', '/cv.php', '/homelab-tree.php'];
</script> </script>
<script src="cv-theme.js"></script> <script src="cv-theme.js"></script>
<?php require_once __DIR__ . '/partials/translation_ui.php'; ?> <?php require_once __DIR__ . '/partials/translation_ui.php'; ?>

View File

@ -1,4 +1,3 @@
const siteThemeButtons = [...document.querySelectorAll('[data-site-theme]')];
const cvPortrait = document.getElementById('cv-portrait-orbit'); const cvPortrait = document.getElementById('cv-portrait-orbit');
const siteThemeStorageKey = 'site-theme'; const siteThemeStorageKey = 'site-theme';
const legacyCvThemeStorageKey = 'cv-theme'; const legacyCvThemeStorageKey = 'cv-theme';
@ -16,20 +15,27 @@ function getStoredSiteTheme() {
} }
function storeSiteTheme(theme) { function storeSiteTheme(theme) {
const nextTheme = normalizeSiteTheme(theme);
try { try {
localStorage.setItem(siteThemeStorageKey, theme); localStorage.setItem(siteThemeStorageKey, nextTheme);
localStorage.removeItem(legacyCvThemeStorageKey); localStorage.removeItem(legacyCvThemeStorageKey);
} catch (_error) { } catch (_error) {
} }
} }
function getSiteThemeButtons() {
return [...document.querySelectorAll('[data-site-theme]')];
}
function setSiteTheme(theme) { function setSiteTheme(theme) {
const nextTheme = normalizeSiteTheme(theme); const nextTheme = normalizeSiteTheme(theme);
document.documentElement.classList.toggle('theme-light', nextTheme === 'light');
document.documentElement.classList.toggle('theme-dark', nextTheme === 'dark');
document.body.classList.toggle('theme-light', nextTheme === 'light'); document.body.classList.toggle('theme-light', nextTheme === 'light');
document.body.classList.toggle('theme-dark', nextTheme === 'dark'); document.body.classList.toggle('theme-dark', nextTheme === 'dark');
siteThemeButtons.forEach((button) => { getSiteThemeButtons().forEach((button) => {
const active = button.dataset.siteTheme === nextTheme; const active = normalizeSiteTheme(button.dataset.siteTheme) === nextTheme;
button.classList.toggle('is-active', active); button.classList.toggle('is-active', active);
button.setAttribute('aria-pressed', active ? 'true' : 'false'); button.setAttribute('aria-pressed', active ? 'true' : 'false');
}); });
@ -37,8 +43,10 @@ function setSiteTheme(theme) {
storeSiteTheme(nextTheme); storeSiteTheme(nextTheme);
} }
siteThemeButtons.forEach((button) => { document.addEventListener('click', (event) => {
button.addEventListener('click', () => setSiteTheme(button.dataset.siteTheme)); const button = event.target.closest('[data-site-theme]');
if (!button) return;
setSiteTheme(button.dataset.siteTheme);
}); });
document.addEventListener('pointermove', (event) => { document.addEventListener('pointermove', (event) => {

View File

@ -259,7 +259,7 @@ $recruiterKeys = [
</div> </div>
<script> <script>
const OTHER_PAGES = ['index.php', 'blog.php']; window.OTHER_PAGES = ['index.php', 'blog.php'];
</script> </script>
<script src="cv-theme.js"></script> <script src="cv-theme.js"></script>
<?php require_once __DIR__ . '/partials/translation_ui.php'; ?> <?php require_once __DIR__ . '/partials/translation_ui.php'; ?>

View File

@ -155,7 +155,7 @@ $homeProofCards = [
</section> </section>
<script> <script>
const OTHER_PAGES = ['cv.php', 'blog.php', 'demos.php']; window.OTHER_PAGES = ['cv.php', 'blog.php', 'demos.php'];
</script> </script>
<script src="cv-theme.js"></script> <script src="cv-theme.js"></script>
<?php require_once __DIR__ . '/partials/translation_ui.php'; ?> <?php require_once __DIR__ . '/partials/translation_ui.php'; ?>

View File

@ -44,6 +44,6 @@
const SAVE_URL = '/save_lang.php'; const SAVE_URL = '/save_lang.php';
const CURRENT_LANG = '<?php echo $lang; ?>'; const CURRENT_LANG = '<?php echo $lang; ?>';
const STATIC_LANGS = <?php echo json_encode(array_values($availableLangs)); ?>; const STATIC_LANGS = <?php echo json_encode(array_values($availableLangs)); ?>;
if (typeof OTHER_PAGES === 'undefined') { var OTHER_PAGES = []; } window.OTHER_PAGES = Array.isArray(window.OTHER_PAGES) ? window.OTHER_PAGES : [];
</script> </script>
<script src="/translation.js"></script> <script src="/translation.js"></script>

View File

@ -2019,3 +2019,235 @@ body.theme-light .source-links a {
font-size: 2.35rem; font-size: 2.35rem;
} }
} }
body.theme-dark {
background: #000;
color: #39ff14;
font-family: "Courier New", "Lucida Console", Monaco, monospace;
font-size: 1rem;
line-height: 1.56;
}
body.theme-light {
background: #fffff0;
color: #1b1610;
font-family: "Brush Script MT", "Segoe Script", "Snell Roundhand", "Apple Chancery", cursive;
font-size: 1.12rem;
line-height: 1.68;
}
body.theme-dark .top-nav,
body.theme-dark .site-theme-toolbar,
body.theme-dark .nav-left,
body.theme-dark .nav-right a,
body.theme-dark a,
body.theme-dark .blog-kicker,
body.theme-dark .section-kicker,
body.theme-dark .demo-label,
body.theme-dark h1,
body.theme-dark h2,
body.theme-dark h3,
body.theme-dark h4,
body.theme-dark strong {
color: #7cff7c;
font-family: inherit;
}
body.theme-dark p,
body.theme-dark li,
body.theme-dark label,
body.theme-dark span,
body.theme-dark .blog-subtitle,
body.theme-dark .hero-role,
body.theme-dark .bio-intro,
body.theme-dark .bio-story,
body.theme-dark .cta,
body.theme-dark .diagram-caption,
body.theme-dark .source-links span,
body.theme-dark .visitor-idea-card footer {
color: #39ff14;
}
body.theme-dark .container,
body.theme-dark.home-page .hero,
body.theme-dark .blog-hero,
body.theme-dark .demos-hero,
body.theme-dark .architecture-section,
body.theme-dark .case-studies,
body.theme-dark .activity-log,
body.theme-dark .homelab-todo,
body.theme-dark .tech-notes,
body.theme-dark .home-proof-card,
body.theme-dark .case-card,
body.theme-dark .demo-card,
body.theme-dark .message,
body.theme-dark .todo-list li,
body.theme-dark .activity-list li,
body.theme-dark .visitor-idea-card,
body.theme-dark .idea-status,
body.theme-dark .source-links a,
body.theme-dark .cv-impact-grid p,
body.theme-dark .cv-skill-grid article,
body.theme-dark .cv-recruiter-panel,
body.theme-dark .cv-proof-section,
body.theme-dark .cv-skill-section {
background: #000;
border-color: #1fbf3a;
color: #39ff14;
box-shadow: 0 0 16px rgba(57, 255, 20, 0.16);
}
body.theme-dark .hero-actions a,
body.theme-dark .cv-recruiter-actions a,
body.theme-dark .case-card a,
body.theme-dark .idea-form button,
body.theme-dark .site-theme-option {
background: #000;
border-color: #39ff14;
color: #39ff14;
font-family: inherit;
}
body.theme-dark .site-theme-option.is-active,
body.theme-dark .hero-actions a:hover,
body.theme-dark .cv-recruiter-actions a:hover,
body.theme-dark .case-card a:hover,
body.theme-dark .idea-form button:hover {
background: #062b06;
color: #b6ffb6;
}
body.theme-dark .idea-form input,
body.theme-dark .idea-form textarea,
body.theme-dark .diagram-shell {
background: #000;
border-color: #1fbf3a;
color: #39ff14;
font-family: inherit;
}
body.theme-dark .diagram-zone,
body.theme-dark .diagram-node rect {
fill: #000;
stroke: #1fbf3a;
}
body.theme-dark .diagram-zone-title,
body.theme-dark .diagram-node text,
body.theme-dark .diagram-link-label,
body.theme-dark .diagram-node .diagram-small,
body.theme-dark .diagram-small {
fill: #39ff14;
}
body.theme-dark .diagram-link {
stroke: #39ff14;
}
body.theme-light .top-nav,
body.theme-light .site-theme-toolbar,
body.theme-light .nav-left,
body.theme-light .nav-right a,
body.theme-light a,
body.theme-light .blog-kicker,
body.theme-light .section-kicker,
body.theme-light .demo-label,
body.theme-light h1,
body.theme-light h2,
body.theme-light h3,
body.theme-light h4,
body.theme-light strong {
color: #1b1610;
font-family: inherit;
}
body.theme-light p,
body.theme-light li,
body.theme-light label,
body.theme-light span,
body.theme-light .blog-subtitle,
body.theme-light .hero-role,
body.theme-light .bio-intro,
body.theme-light .bio-story,
body.theme-light .cta,
body.theme-light .diagram-caption,
body.theme-light .source-links span,
body.theme-light .visitor-idea-card footer {
color: #1b1610;
}
body.theme-light .container,
body.theme-light.home-page .hero,
body.theme-light .blog-hero,
body.theme-light .demos-hero,
body.theme-light .architecture-section,
body.theme-light .case-studies,
body.theme-light .activity-log,
body.theme-light .homelab-todo,
body.theme-light .tech-notes,
body.theme-light .home-proof-card,
body.theme-light .case-card,
body.theme-light .demo-card,
body.theme-light .message,
body.theme-light .todo-list li,
body.theme-light .activity-list li,
body.theme-light .visitor-idea-card,
body.theme-light .idea-status,
body.theme-light .source-links a,
body.theme-light .cv-impact-grid p,
body.theme-light .cv-skill-grid article,
body.theme-light .cv-recruiter-panel,
body.theme-light .cv-proof-section,
body.theme-light .cv-skill-section {
background: #fffff0;
border-color: #1b1610;
color: #1b1610;
box-shadow: none;
}
body.theme-light .hero-actions a,
body.theme-light .cv-recruiter-actions a,
body.theme-light .case-card a,
body.theme-light .idea-form button,
body.theme-light .site-theme-option {
background: #fffff0;
border-color: #1b1610;
color: #1b1610;
font-family: inherit;
}
body.theme-light .site-theme-option.is-active,
body.theme-light .hero-actions a:hover,
body.theme-light .cv-recruiter-actions a:hover,
body.theme-light .case-card a:hover,
body.theme-light .idea-form button:hover {
background: #1b1610;
color: #fffff0;
}
body.theme-light .idea-form input,
body.theme-light .idea-form textarea,
body.theme-light .diagram-shell {
background: #fffff0;
border-color: #1b1610;
color: #1b1610;
font-family: inherit;
}
body.theme-light .diagram-zone,
body.theme-light .diagram-node rect {
fill: #fffff0;
stroke: #1b1610;
}
body.theme-light .diagram-zone-title,
body.theme-light .diagram-node text,
body.theme-light .diagram-link-label,
body.theme-light .diagram-node .diagram-small,
body.theme-light .diagram-small {
fill: #1b1610;
}
body.theme-light .diagram-link {
stroke: #1b1610;
}