diff options
| author | Matt Kosarek <matt.kosarek@canonical.com> | 2026-03-18 08:17:44 -0400 |
|---|---|---|
| committer | Matt Kosarek <matt.kosarek@canonical.com> | 2026-03-18 08:17:44 -0400 |
| commit | ce455b41a2a3d520a2f37c2d4c69bf6ab33a65f7 (patch) | |
| tree | d5ed04d3c1ec4d4a2b18ee57faf6bad659065f2e /src | |
| parent | 5256e50987e8173080bb84cfe881ac0e5f089847 (diff) | |
Diffstat (limited to 'src')
| -rw-r--r-- | src/layouts/BaseLayout.astro | 42 | ||||
| -rw-r--r-- | src/layouts/PostLayout.astro | 4 | ||||
| -rw-r--r-- | src/styles/index.css | 84 | ||||
| -rw-r--r-- | src/styles/post.css | 53 | ||||
| -rw-r--r-- | src/styles/resume.css | 65 |
5 files changed, 218 insertions, 30 deletions
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 76dc4cc..57077ec 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -24,6 +24,17 @@ const { <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap" rel="stylesheet"> <link rel="shortcut icon" href="/favicon/favicon.ico" type="image/x-icon"> <meta name="description" content={description}> + <script is:inline> + (function() { + var saved = localStorage.getItem('theme'); + var prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + if (saved === 'dark' || (!saved && prefersDark)) { + document.documentElement.setAttribute('data-theme', 'dark'); + } else if (saved === 'light') { + document.documentElement.setAttribute('data-theme', 'light'); + } + })(); + </script> </head> <body> <header> @@ -32,9 +43,40 @@ const { <li><a href='/'>🏡 Home</a></li> <li><a href='/resume'>📘 CV</a></li> <li><a href='/posts'>📝 Posts</a></li> + <li style="margin-left: auto"> + <button id="theme-toggle" aria-label="Toggle color theme">Dark</button> + </li> </ul> </nav> </header> <slot /> + <script is:inline> + (function() { + var btn = document.getElementById('theme-toggle'); + var root = document.documentElement; + + function getCurrentTheme() { + var explicit = root.getAttribute('data-theme'); + if (explicit) return explicit; + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + + function setTheme(theme) { + root.setAttribute('data-theme', theme); + localStorage.setItem('theme', theme); + updateButton(theme); + } + + function updateButton(theme) { + btn.textContent = theme === 'dark' ? '🌗 Light' : '🌗 Dark'; + } + + updateButton(getCurrentTheme()); + + btn.addEventListener('click', function() { + setTheme(getCurrentTheme() === 'dark' ? 'light' : 'dark'); + }); + })(); + </script> </body> </html> diff --git a/src/layouts/PostLayout.astro b/src/layouts/PostLayout.astro index 31d0ac6..7b9d85c 100644 --- a/src/layouts/PostLayout.astro +++ b/src/layouts/PostLayout.astro @@ -14,5 +14,7 @@ const { title } = Astro.props; <h1>{title}</h1> <a href="/posts/feed.xml">RSS Feed</a> </div> - <slot /> + <div class="org-article-content"> + <slot /> + </div> </BaseLayout> diff --git a/src/styles/index.css b/src/styles/index.css index b5b923d..3856449 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -1,10 +1,54 @@ +:root { + --bg: transparent; + --color: black; + --link-color: darkviolet; + --image-border: rgba(0, 0, 0, 0.3); + --image-border-hover: rgba(0, 0, 0, 0.7); + --image-overlay: rgba(0, 0, 0, 0.7); + --theme-btn-bg: white; + --theme-btn-border: gray; + --theme-btn-color: black; + --input-focus-border: lightgray; + --action-button-border: #f0f0f0; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) { + --bg: rgba(13, 17, 23, 0.92); + --color: #e6edf3; + --link-color: #b083f0; + --image-border: rgba(255, 255, 255, 0.2); + --image-border-hover: rgba(255, 255, 255, 0.5); + --image-overlay: rgba(0, 0, 0, 0.85); + --theme-btn-bg: #21262d; + --theme-btn-border: #444c56; + --theme-btn-color: #e6edf3; + --input-focus-border: #586069; + --action-button-border: #30363d; + } +} + +[data-theme="dark"] { + --bg: rgba(13, 17, 23, 0.92); + --color: #e6edf3; + --link-color: #b083f0; + --image-border: rgba(255, 255, 255, 0.2); + --image-border-hover: rgba(255, 255, 255, 0.5); + --image-overlay: rgba(0, 0, 0, 0.85); + --theme-btn-bg: #21262d; + --theme-btn-border: #444c56; + --theme-btn-color: #e6edf3; + --input-focus-border: #586069; + --action-button-border: #30363d; +} + body { width: 50vw; height: calc(100vh - 2rem); font-family: "Noto Sans", 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 14px; - background-color: transparent; - color: black; + background-color: var(--bg); + color: var(--color); padding: 0; margin: auto; } @@ -43,7 +87,7 @@ header > nav > ul > li { header > nav > ul a { text-decoration: none; - color: darkviolet; + color: var(--link-color); font-size: 1rem; border-bottom: 1px solid transparent; } @@ -72,13 +116,29 @@ p { } a { - color: darkviolet; + color: var(--link-color); } a:hover { opacity: 0.7; } +/* Theme toggle button */ +#theme-toggle { + background: none; + border: 1px solid var(--theme-btn-border); + color: var(--link-color); + border-radius: 3px; + padding: 0.1rem 0.5rem; + cursor: pointer; + font-size: 0.85rem; + font-family: inherit; +} + +#theme-toggle:hover { + opacity: 0.8; +} + /* Image styling */ #image_container { display: flex; @@ -100,7 +160,7 @@ a:hover { } #image_container .image_item:hover > img { - border: 2px solid rgba(0, 0, 0, 0.7); + border: 2px solid var(--image-border-hover); } .image_item > figcaption { @@ -111,14 +171,14 @@ a:hover { .image_item > img { width: inherit; border-radius: 3px; - border: 2px solid rgba(0, 0, 0, 0.3); + border: 2px solid var(--image-border); } .image_item_expanded_container { position: fixed; width: 100vw; height: 100vh; - background-color: rgba(0, 0, 0, 0.7); + background-color: var(--image-overlay); display: flex; flex-direction: column; justify-content: center; @@ -140,11 +200,11 @@ input { } input:focus { - border: 1px solid lightgray; + border: 1px solid var(--input-focus-border); } .action_button { - border: 1px solid #f0f0f0; + border: 1px solid var(--action-button-border); border-radius: 2px; width: 108px; height: 2rem; @@ -201,9 +261,9 @@ input:focus { width: 6rem; height: 2rem; border-radius: 3px; - border: 1px solid gray; - color: black; - background-color: white; + border: 1px solid var(--theme-btn-border); + color: var(--theme-btn-color); + background-color: var(--theme-btn-bg); cursor: pointer; transition: opacity 100ms linear; } diff --git a/src/styles/post.css b/src/styles/post.css index 8ae1513..32e69c2 100644 --- a/src/styles/post.css +++ b/src/styles/post.css @@ -1,6 +1,29 @@ +:root { + --code-bg: #F5F0FF; + --code-border: #D5C8F0; + --code-inline-color: #D0372D; + --meta-color: #707183; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) { + --code-bg: #1e1b2e; + --code-border: #3d3560; + --code-inline-color: #ff9090; + --meta-color: #8b929e; + } +} + +[data-theme="dark"] { + --code-bg: #1e1b2e; + --code-border: #3d3560; + --code-inline-color: #ff9090; + --meta-color: #8b929e; +} + pre { - background-color: #FEFEFE; - border: 1px solid #D5D5D5; + background-color: var(--code-bg); + border: 1px solid var(--code-border); border-radius: 2px; padding: 1rem; overflow: auto; @@ -8,7 +31,27 @@ pre { code { font-family: "Consolas" sans-serif; - color: #D0372D; + color: var(--code-inline-color); +} + +/* Shiki dual-theme support */ +.astro-code, .astro-code span { + color: var(--shiki-light) !important; + background-color: var(--shiki-light-bg) !important; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) .astro-code, + :root:not([data-theme="light"]) .astro-code span { + color: var(--shiki-dark) !important; + background-color: var(--shiki-dark-bg) !important; + } +} + +[data-theme="dark"] .astro-code, +[data-theme="dark"] .astro-code span { + color: var(--shiki-dark) !important; + background-color: var(--shiki-dark-bg) !important; } .underline { @@ -26,7 +69,7 @@ code { font-family: "Space Grotesk", sans-serif; } -#content { +.org-article-content { padding-bottom: 10vh; } @@ -39,7 +82,7 @@ code { } .org-article-title > span { - color: #707183; + color: var(--meta-color); } #org-div-home-and-up { diff --git a/src/styles/resume.css b/src/styles/resume.css index a36fc0d..3cbf769 100644 --- a/src/styles/resume.css +++ b/src/styles/resume.css @@ -3,6 +3,47 @@ src: url(/fonts/Ubuntu-M.ttf); } +:root { + --resume-bg: white; + --resume-color: black; + --resume-link-color: #343231; + --resume-section-bg: #583759; + --resume-section-color: white; + --skills-bar-bg: white; + --skills-table-border: gray; + --skills-table-inner-border: lightgray; + --skills-table-th-color: #2E4C6D; + --experience-hover-color: #583759; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) { + --resume-bg: #161b22; + --resume-color: #e6edf3; + --resume-link-color: #8b949e; + --resume-section-bg: #3d2b5e; + --resume-section-color: #e6edf3; + --skills-bar-bg: #21262d; + --skills-table-border: #444c56; + --skills-table-inner-border: #30363d; + --skills-table-th-color: #79b8ff; + --experience-hover-color: #b083f0; + } +} + +[data-theme="dark"] { + --resume-bg: #161b22; + --resume-color: #e6edf3; + --resume-link-color: #8b949e; + --resume-section-bg: #3d2b5e; + --resume-section-color: #e6edf3; + --skills-bar-bg: #21262d; + --skills-table-border: #444c56; + --skills-table-inner-border: #30363d; + --skills-table-th-color: #79b8ff; + --experience-hover-color: #b083f0; +} + html { overflow-y: overlay; font-size: 16px; @@ -23,8 +64,8 @@ header { #resume { position: relative; text-align: left; - background-color: white; - color: black; + background-color: var(--resume-bg); + color: var(--resume-color); font-family: 'Ubuntu', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.325rem; } @@ -35,7 +76,7 @@ header { } #resume a { - color: #343231; + color: var(--resume-link-color); } #resume_sidebar { @@ -96,8 +137,8 @@ header { padding: 0; margin: 0; padding: 0.25rem; - background-color: #583759; - color: white; + background-color: var(--resume-section-bg); + color: var(--resume-section-color); } .resume_section_content { @@ -111,7 +152,7 @@ header { } .experience-item:hover { - color: #583759; + color: var(--experience-hover-color); } .experience-item ul { @@ -145,7 +186,7 @@ header { .skills_table { width: 100%; border-spacing: 0; - border: 1px solid gray; + border: 1px solid var(--skills-table-border); border-radius: 2px; margin-bottom: 2rem; } @@ -155,11 +196,11 @@ header { } .skills_table th, .skills_table tr:not(:last-child) td { - border-bottom: 1px solid lightgray; + border-bottom: 1px solid var(--skills-table-inner-border); } .skills_table tr th { - color: #2E4C6D; + color: var(--skills-table-th-color); } .skills_table td, th { @@ -183,9 +224,9 @@ header { position: relative; width: 100%; height: 1rem; - background-color: white; + background-color: var(--skills-bar-bg); border-radius: 3px; - border: 1px solid lightgray; + border: 1px solid var(--skills-table-inner-border); } .skills_section_bar_fill { @@ -222,7 +263,7 @@ header { .skills_section_label { width: 100%; margin-top: 0.25rem; - color: black; + color: var(--resume-color); font-size: 1rem; } |
