From ce455b41a2a3d520a2f37c2d4c69bf6ab33a65f7 Mon Sep 17 00:00:00 2001 From: Matt Kosarek Date: Wed, 18 Mar 2026 08:17:44 -0400 Subject: feature: add a light and dark theme --- src/layouts/BaseLayout.astro | 42 ++++++++++++++++++++++ src/layouts/PostLayout.astro | 4 ++- src/styles/index.css | 84 +++++++++++++++++++++++++++++++++++++------- src/styles/post.css | 53 +++++++++++++++++++++++++--- src/styles/resume.css | 65 +++++++++++++++++++++++++++------- 5 files changed, 218 insertions(+), 30 deletions(-) (limited to 'src') 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 { +
@@ -32,9 +43,40 @@ const {
  • 🏡 Home
  • 📘 CV
  • 📝 Posts
  • +
  • + +
  • + 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;

    {title}

    RSS Feed - +
    + +
    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; } -- cgit v1.2.1