From a4f1d8472317a00509404a2987c8110c0cd7f865 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 29 Jul 2024 10:24:59 +0100 Subject: [PATCH] add night mode toggle and autoformat css --- README.md | 1 + _includes/header.html | 7 + _layouts/default.html | 2 +- _layouts/post.html | 2 +- _sass/_vars.scss | 2 +- _sass/base.scss | 411 ++++++++++++++++++++++------------- _sass/blogroll.scss | 16 +- _sass/cv.scss | 141 ++++++------ _sass/header.scss | 224 ++++++++++--------- _sass/model_viewer.scss | 154 ++++++------- _sass/nav.scss | 41 ++-- _sass/night_mode_toggle.scss | 31 +++ _sass/projects.scss | 67 ++---- assets/js/index.js | 83 ++++++- ruff.toml | 1 + 15 files changed, 692 insertions(+), 491 deletions(-) create mode 100644 _sass/night_mode_toggle.scss create mode 100644 ruff.toml diff --git a/README.md b/README.md index 441c2b6..b9fb975 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ A list of things to check once in a while to make sure I haven't broken them ina - Mobile and web layouts looks ok. - Dark mode and light mode both look ok. - OG tags render nicely, use https://www.opengraph.xyz/ +- Check the rss feed https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fthomashodson.com%2Ffeed.xml ## Todo - change the OG image used for the landing page so it's not just my face. diff --git a/_includes/header.html b/_includes/header.html index 396d04d..b9da812 100644 --- a/_includes/header.html +++ b/_includes/header.html @@ -17,6 +17,13 @@

{% include sidebar.html%} +
+
+ +
+ {{ include.extra }}
\ No newline at end of file diff --git a/_layouts/default.html b/_layouts/default.html index 637d612..eced7a2 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -1,5 +1,5 @@ - + {% include default_head_tags.html%} diff --git a/_layouts/post.html b/_layouts/post.html index b0c5deb..a9f5d2e 100644 --- a/_layouts/post.html +++ b/_layouts/post.html @@ -1,5 +1,5 @@ - + {% include default_head_tags.html%} diff --git a/_sass/_vars.scss b/_sass/_vars.scss index 47408e6..4fe0a30 100644 --- a/_sass/_vars.scss +++ b/_sass/_vars.scss @@ -1,7 +1,7 @@ $font_stack: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif; $title_font_stack: Impact, Haettenschweiler, "Franklin Gothic Bold", Charcoal, "Helvetica Inserat", "Bitstream Vera Sans Bold", "Arial Black", "sans serif", HelveticaNeue-CondensedBlack; -$horizontal_breakpoint: 700px; +$horizontal_breakpoint: 900px; $vertical_breakpoint: 500px; // For the images on the blogroll, projects and highlights pages diff --git a/_sass/base.scss b/_sass/base.scss index 74046de..b828b29 100644 --- a/_sass/base.scss +++ b/_sass/base.scss @@ -8,227 +8,334 @@ @import "projects"; //Styles for the projects page @import "cv"; // the CV page @import "blogroll"; // the summaries of the blogposts -@import "comments"; //the mastodon comments +@import "comments"; //the mastodon comments @import "model_viewer"; //Styles for the 3D model viewer @import "mastodon_timeline"; +@import "night_mode_toggle"; // The syntax highlighting css // generated with rougify style bw > code_style_bw.scss -// @import "code_style_bw"; -@import "code_style_github"; +// @import "code_style_bw"; +@import "code_style_github"; @import "d2"; - * { - box-sizing: border-box; - font-family: $font_stack; - text-rendering: geometricPrecision; + box-sizing: border-box; + font-family: $font_stack; + text-rendering: geometricPrecision; +} + +:root { + --theme-text-color: #222; + --theme-bg-color: #fcfcfc; + --theme-model-line-color: #222; + --theme-model-bg-color: #fcfcfc; + --theme-subtle-outline: oklch(90% 0 50); + --theme-highlight-color: hsl(338, 75%, 60%); + --theme-highlight-color-transparent: hsla(338, 75%, 60%, 33%); + + // constrain width and center + --body-max-width: 900px; + --body-width: min(100vw, 900px); + --body-margin: calc((100vw - var(--body-width)) / 2); + + --color-mode: "light"; + --color-dark: #141414; + --color-dark-alpha: rgba(0, 0, 0, 0.1); + --color-light: #efefef; + --color-light-alpha: rgba(255, 255, 255, 0.9); + --icon-sun: url('data:image/svg+xml,\ + \ + \ + '); + --icon-sun-filter: invert(0.75); + --icon-moon: url('data:image/svg+xml,\ + \ + \ + '); + --icon-moon-filter: invert(0); + --background: #efefef; + --text-color: #141414; + --button-icon: var(--icon-moon); + --button-icon-filter: var(--icon-moon-filter); + --button-background: var(--color-dark); + --button-color: var(--color-light); + --border-color: var(--color-dark-alpha); } html { - width: 100vw; - scroll-behavior: smooth; + width: 100vw; + scroll-behavior: smooth; } body { - --theme-text-color: #222; - --theme-bg-color: #fcfcfc; - --theme-model-line-color: #222; - --theme-model-bg-color: #fcfcfc; - --theme-subtle-outline: oklch(90% 0.0 50); - --theme-highlight-color: hsl(338, 75%, 60%); - --theme-highlight-color-transparent: hsla(338, 75%, 60%, 33%); + background: var(--theme-bg-color); + color: var(--theme-text-color); - background: var(--theme-bg-color); - color: var(--theme-text-color); - - // constrain width and center - max-width: 900px; - margin: auto; + max-width: var(--body-max-width); + margin: auto; } // Padding to keep the keep the content to the right of the header main { - container: main / inline-size; + container: main / inline-size; - max-width: 560px; - margin-left: 240px; - padding-left: 30px; - padding-right: 30px; - padding-top: 10vh; - min-height: 100vh; + --main-margin-left: 240px; + --main-padding-left: 30px; + --main-padding-right: 30px; + --main-max-width: 560px; - display: flex; - flex-direction: column; - justify-content: center; + max-width: var(--main-max-width); + margin-left: var(--main-margin-left); + padding-left: var(--main-padding-left); + padding-right: var(--main-padding-right); + padding-top: 10vh; + min-height: 100vh; - h1 { - font-size: 2em; - } + display: flex; + flex-direction: column; + justify-content: center; - // img that are direct children of p are usually img tags in markdown - p > img { - margin-top: 2em; - margin-bottom: 1em; - width: 90%; + h1 { + font-size: 2em; + } - //hack to center images in p tags - display: block; - margin-left: auto; - margin-right: auto; - } + // img that are direct children of p are usually img tags in markdown + p > img { + margin-top: 2em; + margin-bottom: 1em; + width: 90%; + + //hack to center images in p tags + display: block; + margin-left: auto; + margin-right: auto; + } } :is(h1, h2, h3, h4, .text-balance) { - text-wrap: balance; + text-wrap: balance; } -p, figcaption { - font-size: 1em; - line-height: 1.3em; - } +p, +figcaption { + font-size: 1em; + line-height: 1.3em; +} -main :is(p,h1,h2,h3,h4,h5,h6) { - margin-block-end: 0.2em; - } +main :is(p, h1, h2, h3, h4, h5, h6) { + margin-block-end: 0.2em; +} a { - text-decoration: underline; - text-underline-offset: 0.25em; - text-decoration-thickness: 0.5px; - color: var(--theme-text-color); + text-decoration: underline; + text-underline-offset: 0.25em; + text-decoration-thickness: 0.5px; + color: var(--theme-text-color); } -header a, nav a { - text-decoration: none; - color: var(--theme-text-color); +header a, +nav a { + text-decoration: none; + color: var(--theme-text-color); } div.highlight { - max-width: 100%; - overflow: auto; + max-width: 100%; + overflow: auto; } p { - margin-top: 0.7em; - margin-bottom: 0.7em; - padding-right: 0; - vertical-align: baseline; + margin-top: 0.7em; + margin-bottom: 0.7em; + padding-right: 0; + vertical-align: baseline; } figure { - container: fig / inline-size; - width: 100%; - padding-bottom: 1em; - margin-left: auto; - margin-right: auto; + container: fig / inline-size; + width: 100%; + padding-bottom: 1em; + margin-left: auto; + margin-right: auto; - figcaption { - margin-top: 1em; - text-align: center; - } + figcaption { + margin-top: 1em; + text-align: center; + } } -figure > img, figure > svg, figure > canvas { - width: 100%; - margin-bottom: 1em; - border-radius: 10px; +figure > img, +figure > svg, +figure > canvas { + width: 100%; + margin-bottom: 1em; + border-radius: 10px; } figure.centered { - display: flex; - justify-content: center; + display: flex; + justify-content: center; } section.image-grid-4x4 { - aspect-ratio: 1 / 1; - display: grid; - grid-template-columns: auto auto; - grid-template-rows: auto auto; - gap: 2px; - margin-bottom: 1em; - place-items: stretch stretch; + aspect-ratio: 1 / 1; + display: grid; + grid-template-columns: auto auto; + grid-template-rows: auto auto; + gap: 2px; + margin-bottom: 1em; + place-items: stretch stretch; - - * { - margin: 0; - padding: 0; - width: 100%; - aspect-ratio: auto; - } + * { + margin: 0; + padding: 0; + width: 100%; + aspect-ratio: auto; + } } section.note { - a {color: purple;} - p {margin: 0;} - padding: 1em; - margin-top: 1em; - margin-bottom: 1em; - background-color: var(--theme-highlight-color-transparent); - border-radius: 10px; - color: black; + a { + color: purple; + } + p { + margin: 0; + } + padding: 1em; + margin-top: 1em; + margin-bottom: 1em; + background-color: var(--theme-highlight-color-transparent); + border-radius: 10px; + color: black; } section.center { - display: flex; - justify-content: center; - margin-top: 1em; - margin-bottom: 1em; + display: flex; + justify-content: center; + margin-top: 1em; + margin-bottom: 1em; +} +div.CodeRay, +.wide-outside-parent { + // width: 100vw; + position: relative; + width: calc( + 100vw - var(--body-margin) - var(--main-margin-left) - + var(--main-padding-left) - var(--main-padding-right) + ); + pre { + white-space: pre-wrap; + } + .line-numbers { + // display: none; + margin-right: 1em; + opacity: 0.3; + a { + text-decoration: none; + } + } } // If the browser doesn't support web components, hide anything with has-wc class body.has-wc .no-wc { - display: none; + display: none; } // If the browser does support web components, hide anything with no-wc class body:not(.has-wc) .has-wc { - display: none; + display: none; } -@media - only screen and (max-width: $horizontal_breakpoint), - only screen and (max-height: $vertical_breakpoint) - { - main { - padding-top: 10px; - padding-left: 20px; - padding-right: 20px; - margin: auto; - justify-content: flex-start; - } - - article { - margin-left: 0px; } - - h1 {font-size: 1.5em !important;} - .MathJax { - font-size: 0.8em !important; - overflow-x: auto; - overflow-y: hidden; - } -} - -// For the 3D model viewer -model-viewer { - width: 100%; - height: 300px; +@media only screen and (max-width: $horizontal_breakpoint), + only screen and (max-height: $vertical_breakpoint) { + main { + --main-margin-left: 0px; + --main-padding-left: 20px; + --main-padding-right: 20px; + padding-top: 10px; + margin: auto; + justify-content: flex-start; } - - @media (prefers-color-scheme: dark) { - body { - --theme-text-color: #fcfcfc; - --theme-bg-color: #222; - --theme-subtle-outline: oklch(50% 0.0 50); - } - img { - opacity: .75; - transition: opacity .5s ease-in-out; - } - svg.invertable, img.invertable{ - opacity: 1; - filter: invert(1); - } - } \ No newline at end of file + article { + margin-left: 0px; + } + + h1 { + font-size: 1.5em !important; + } + .MathJax { + font-size: 0.8em !important; + overflow-x: auto; + overflow-y: hidden; + } + + // Make code a bit smaller so it doesn't wrap as much + div.CodeRay { + font-size: 0.8rem; + } +} + +.visually-hidden { + display: block; + height: 1px; + width: 1px; + overflow: hidden; + clip: rect(1px 1px 1px 1px); + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(1px); + white-space: nowrap; + position: absolute; +} + +// Add transitions for things that will be affected by night mode +body { + transition: background 500ms ease-in-out, color 200ms ease-in-out; +} +img { + transition: opacity 500ms ease-in-out; +} +svg.invertable, +img.invertable { + transition: filter 500ms ease-in-out; +} + +@mixin night-mode { + --background: var(--color-dark); + --text-color: var(--color-light); + --button-icon: var(--icon-sun); + --button-icon-filter: var(--icon-sun-filter); + --button-background: var(--color-light); + --button-color: var(--color-dark); + --border-color: var(--color-light-alpha); + + body { + --theme-text-color: #fcfcfc; + --theme-bg-color: #222; + --theme-subtle-outline: oklch(50% 0 50); + } + img:not(.invertable) { + opacity: 0.75; + } + svg.invertable, + img.invertable { + opacity: 1; + filter: invert(1); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --color-mode: "dark"; + } + + :root:not([data-user-color-scheme]) { + @include night-mode; + } +} + +[data-user-color-scheme="dark"] { + @include night-mode; +} diff --git a/_sass/blogroll.scss b/_sass/blogroll.scss index 803053c..1ef5e32 100644 --- a/_sass/blogroll.scss +++ b/_sass/blogroll.scss @@ -16,13 +16,22 @@ article.draft { opacity: 0.5; } +section.highlights { + margin-bottom: 2rem; + + h1 { + margin-bottom: 1rem; + } +} + a.highlights-more { margin-left: $left_pad; } -main > h2 { +h1.highlights { font-size: 1.75rem; - margin-left: $left_pad + margin-left: $left_pad; + margin-bottom: 1em; } article.blogroll { @@ -65,5 +74,8 @@ article.blogroll { font-size: 1.2em; } } + a.highlights-more { + font-size: 1.25rem; + } } \ No newline at end of file diff --git a/_sass/cv.scss b/_sass/cv.scss index cf1eb26..49befaa 100644 --- a/_sass/cv.scss +++ b/_sass/cv.scss @@ -1,123 +1,130 @@ summary.cv { - margin-bottom: 0.7em; - margin-top: 0.7em; + margin-bottom: 0.7em; + margin-top: 0.7em; - padding-left: 2.2rem; - position: relative; + padding-left: 2.2rem; + position: relative; - display: flex; - cursor: pointer; + display: flex; + cursor: pointer; } details summary.cv::-webkit-details-marker { - display:none; + display: none; } details[open] > summary:before { - transform: rotate(90deg); + transform: rotate(90deg); } //A little animation for the details opening details[open] summary ~ * { - animation: sweep .5s ease-in-out; + animation: sweep 0.5s ease-in-out; +} + +@keyframes sweep { + 0% { + opacity: 0; + transform: translateX(-10px); } - - @keyframes sweep { - 0% {opacity: 0; transform: translateX(-10px)} - 100% {opacity: 1; transform: translateX(0)} + 100% { + opacity: 1; + transform: translateX(0); } +} summary.cv:before { - content: ''; - border-width: .4rem; - border-style: solid; - border-color: transparent transparent transparent black; - position: absolute; - top: 0.2rem; - left: 1rem; - transform: rotate(0); - transform-origin: .2rem 50%; - transition: .25s transform ease; + content: ""; + border-width: 0.4rem; + border-style: solid; + border-color: transparent transparent transparent var(--theme-text-color); + position: absolute; + top: 0.2rem; + left: 1rem; + transform: rotate(0); + transform-origin: 0.2rem 50%; + transition: 0.25s transform ease; } summary li { - margin-bottom: 0em; + margin-bottom: 0em; } summary time { - width: 150px; - flex: 0 0 auto; + width: 150px; + flex: 0 0 auto; } div.details-img { - padding-right: 20px; - padding-bottom: 20px; - width: 150px; - flex: 0 0 auto; + padding-right: 20px; + padding-bottom: 20px; + width: 150px; + flex: 0 0 auto; } div.details-text p { - margin-top: 0px; - flex: 0 0 auto; + margin-top: 0px; + flex: 0 0 auto; } div.details-img img { - border-radius: 10px; - max-width: 100%; + border-radius: 10px; + max-width: 100%; } summary h3 { - font-size: 1em; - margin: 0px; - flex: 0 1 auto; + font-size: 1em; + margin: 0px; + flex: 0 1 auto; } button { - height: 2em; + height: 2em; } -div.details-container { - display: flex; - margin-left: 2.2rem; +div.details-container { + display: flex; + margin-left: 2.2rem; } .cv-title-container { - display: flex; - align-items:baseline; + display: flex; + align-items: baseline; } div.cv-title-container { - margin-bottom:1em; - margin-top:1em; + margin-bottom: 1em; + margin-top: 1em; +} +div.cv-title-container h2 { + margin: 0px; } -div.cv-title-container h2 {margin:0px;} div.cv-title-container a { - cursor: pointer; - margin-left: 3em; + cursor: pointer; + margin-left: 3em; - border-style: solid; - border-radius: 5px; - border-width: 1px; - border-color: transparent; - offset: None; + border-style: solid; + border-radius: 5px; + border-width: 1px; + border-color: transparent; + offset: None; - background-color: transparent; - font-size: 1em; + background-color: transparent; + font-size: 1em; } div.cv-title-container button:hover { - border-color:black; + border-color: black; } -@media only screen and (max-width: 900px) { - div.details-container { - margin-left:2.2rem; - flex-direction: column; - align-items: center; - } +@media only screen and (max-width: 900px) { + div.details-container { + margin-left: 2.2rem; + flex-direction: column; + align-items: center; + } - summary.cv { - flex-direction: column; - } - -} \ No newline at end of file + summary.cv { + flex-direction: column; + } +} diff --git a/_sass/header.scss b/_sass/header.scss index 4e06055..72524d6 100644 --- a/_sass/header.scss +++ b/_sass/header.scss @@ -3,141 +3,139 @@ // The header with info about me // gets displayed on the left in a wide layout and on the top in a narrow layout header { - border-right: 2px solid #eee; //make a nice dividing line - position: fixed; - width: 240px; - height: 100vh; - padding-right: 30px; - padding-left: 30px; - - flex: 0 0 240px; + border-right: 2px solid #eee; //make a nice dividing line + position: fixed; + width: 240px; + height: 100vh; + padding-right: 30px; + padding-left: 30px; + + flex: 0 0 240px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-end; + text-align: right; + top: 0px; + + //a horizontal dividing line to swap in when we switch to mobile layout + hr { + border: 0px solid #eee; + width: 100%; + margin-top: 1em; + } + + .profile-pic-name { + text-align: center; + } + + .avatar { + max-width: 175px; + border-radius: 50%; + padding: 5px; + border: 1px solid var(--theme-text-color); + } + + h1 { + color: var(--theme-highlight-color); + font-size: 2em; + } + + h1, + h2 { + font-family: $title_font_stack; + } + + a { + margin-bottom: 2px; + } + + p.professional-links { display: flex; flex-direction: column; - justify-content: center; - align-items: flex-end; - text-align: right; - top: 0px; - //a horizontal dividing line to swap in when we switch to mobile layout - hr { - border:0px solid #eee; - width: 100%; - margin-top: 1em; - } - - .profile-pic-name { - text-align: center; - } - - .avatar { - max-width: 175px; - border-radius: 50%; - padding: 5px; - border: 1px solid #f2f3f3; - } - - h1 { - color: var(--theme-highlight-color); - font-size: 2em; - } - - h1, h2 { - font-family: $title_font_stack; + svg { + height: 1em; + width: 1em; + margin-left: 0.5em; + flex: 0 0 auto; } a { - margin-bottom: 2px; - } - - p.professional-links { - display: flex; - flex-direction: column; - - svg { - height: 1em; - width: 1em; - margin-left: 0.5em; - flex: 0 0 auto; - } - - a { - display: flex; // - align-items: center; // Get the icons centered vertically - justify-content: right; //Align right - } + display: flex; // + align-items: center; // Get the icons centered vertically + justify-content: right; //Align right } + } } -@media - only screen and (max-width: $horizontal_breakpoint), - only screen and (max-height: $vertical_breakpoint) - { - header { - position: relative; - width: 100%; - border: 0px; - text-align: center; - align-items: center; - height: auto; - padding-left: 20px; - padding-right: 20px; - +@media only screen and (max-width: $horizontal_breakpoint), + only screen and (max-height: $vertical_breakpoint) { + header { + position: relative; + width: 100%; + border: 0px; + text-align: center; + align-items: center; + height: auto; + padding-left: 20px; + padding-right: 20px; + hr { - border-width:1px; + border-width: 1px; } .bio { - span { - display: inline; - } - span:after { - content: ', '; - } - span:last-of-type:after { - content: ''; - } + span { + display: inline; + } + span:after { + content: ", "; + } + span:last-of-type:after { + content: ""; + } } // To squish the text together a bit in the mobile view. p { - margin-block: 0.25em; + margin-block: 0.25em; } .avatar { - margin: auto; - } - + margin: auto; + } + p.professional-links { - flex-direction: row; - flex-wrap: wrap; - justify-content: center; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; - a { - margin-left: 1em; - margin-right: 1em; - flex-wrap: nowrap; - justify-content: center; - - // In the main view, the github/mastodon/rss icons are on the right - // for the smaller view switch the to the left - flex-direction: row-reverse; - } - svg { - // Switch the padding side having switched the order - margin-right: 0.5em; - margin-left: 0; - } - } - - } - - nav { - display: flex; - flex-direction: row; - justify-content: center; - flex-wrap: wrap; - } - nav a { + a { margin-left: 1em; + margin-right: 1em; + flex-wrap: nowrap; + justify-content: center; + + // In the main view, the github/mastodon/rss icons are on the right + // for the smaller view switch the to the left + flex-direction: row-reverse; + } + svg { + // Switch the padding side having switched the order + margin-right: 0.5em; + margin-left: 0; + } } + } + + nav { + display: flex; + flex-direction: row; + justify-content: center; + flex-wrap: wrap; + } + nav a { + margin-left: 1em; + } } diff --git a/_sass/model_viewer.scss b/_sass/model_viewer.scss index f492db8..fbc1cb1 100644 --- a/_sass/model_viewer.scss +++ b/_sass/model_viewer.scss @@ -1,84 +1,88 @@ // For fallback images inside custom outline-model-viewer elements .outline-model-poster { - width: 100%; - height: 100%; + width: 100%; + height: 100%; } outline-model-viewer { - width: 100%; - min-height: 300px; - display: flex; - justify-content: center; - align-items: center; - border: var(--theme-subtle-outline) 1px solid; - border-radius: 10px; - margin-top: 1em; - margin-bottom: 1em; + width: 100%; + min-height: 300px; + display: flex; + justify-content: center; + align-items: center; + border: var(--theme-subtle-outline) 1px solid; + border-radius: 10px; + margin-top: 1em; + margin-bottom: 1em; } .Hotspot { - background: #fff; - border-radius: 32px; - border: 0; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); - box-sizing: border-box; - cursor: pointer; - height: 15px; - padding: 8px; - position: relative; - transition: opacity 0.3s; - width: 15px; - } - - .Hotspot:not([data-visible]) { - background: transparent; - border: 4px solid #fff; - box-shadow: none; - height: 32px; - pointer-events: none; - width: 32px; - } - - .Hotspot:focus { - border: 4px solid rgb(0, 128, 200); - height: 32px; - outline: none; - width: 32px; - } - - .Hotspot > * { - opacity: 1; - transform: translateY(-50%); - } - - .HotspotAnnotation{ - background: #fff; - border-radius: 4px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); - color: rgba(0, 0, 0, 0.8); - display: block; - font-family: Futura, Helvetica Neue, sans-serif; - font-size: 12px; - font-weight: 700; - left: calc(100% + 2em); - max-width: 128px; - overflow-wrap: break-word; - padding: 0.5em 1em; - position: absolute; - top: 50%; - width: max-content; - } + background: #fff; + border-radius: 32px; + border: 0; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); + box-sizing: border-box; + cursor: pointer; + height: 15px; + padding: 8px; + position: relative; + transition: opacity 0.3s; + width: 15px; +} - .left.HotspotAnnotation { - right: calc(100% + 2em); - left: unset; - } - - .Hotspot:not([data-visible]) > * { - opacity: 0; - pointer-events: none; - transform: translateY(calc(-50% + 4px)); - transition: transform 0.3s, opacity 0.3s; - } - - \ No newline at end of file +.Hotspot:not([data-visible]) { + background: transparent; + border: 4px solid #fff; + box-shadow: none; + height: 32px; + pointer-events: none; + width: 32px; +} + +.Hotspot:focus { + border: 4px solid rgb(0, 128, 200); + height: 32px; + outline: none; + width: 32px; +} + +.Hotspot > * { + opacity: 1; + transform: translateY(-50%); +} + +.HotspotAnnotation { + background: #fff; + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); + color: rgba(0, 0, 0, 0.8); + display: block; + font-family: Futura, Helvetica Neue, sans-serif; + font-size: 12px; + font-weight: 700; + left: calc(100% + 2em); + max-width: 128px; + overflow-wrap: break-word; + padding: 0.5em 1em; + position: absolute; + top: 50%; + width: max-content; +} + +.left.HotspotAnnotation { + right: calc(100% + 2em); + left: unset; +} + +.Hotspot:not([data-visible]) > * { + opacity: 0; + pointer-events: none; + transform: translateY(calc(-50% + 4px)); + transition: transform 0.3s, opacity 0.3s; +} + +// For the 3D model viewer +model-viewer { + width: 100%; + height: 300px; +} diff --git a/_sass/nav.scss b/_sass/nav.scss index d784bfd..84cef01 100644 --- a/_sass/nav.scss +++ b/_sass/nav.scss @@ -1,31 +1,24 @@ nav { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } .current { - color: darkslategray; - } - -@media (prefers-color-scheme: dark) { - .current { - color: lightslategray; - } + color: var(--theme-highlight-color); } -@media - only screen and (max-width: $horizontal_breakpoint), - only screen and (max-height: $vertical_breakpoint) - { - nav.page-table-of-contents { - white-space: normal; - justify-content: left; - text-align: left; - ul {padding-left: 0em;} - li li { - padding-right: 0em; - padding-left: 2em; - } - +@media only screen and (max-width: $horizontal_breakpoint), + only screen and (max-height: $vertical_breakpoint) { + nav.page-table-of-contents { + white-space: normal; + justify-content: left; + text-align: left; + ul { + padding-left: 0em; } -} \ No newline at end of file + li li { + padding-right: 0em; + padding-left: 2em; + } + } +} diff --git a/_sass/night_mode_toggle.scss b/_sass/night_mode_toggle.scss new file mode 100644 index 0000000..61d41b4 --- /dev/null +++ b/_sass/night_mode_toggle.scss @@ -0,0 +1,31 @@ +.no-js .user-toggle { + display: none; +} + +.user-toggle { + padding-top: 0.5rem; +} + +.toggle-button { + width: 1.5rem; + height: 1.5rem; + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: 50%; + color: var(--theme-text-color); + background: var(--theme-background-color); + border: 1.5px solid var(--theme-text-color); + transition: background 500ms ease-in-out, color 200ms ease; +} + +.toggle-button__icon { + background: var(--button-icon); + width: 0.9rem; + height: 0.9rem; + flex-shrink: 0; + margin: 0; + transform: translateY(0px); /* Optical adjustment */ + transition: filter 200ms ease-in-out; + filter: var(--button-icon-filter); +} diff --git a/_sass/projects.scss b/_sass/projects.scss index aa31647..681f528 100644 --- a/_sass/projects.scss +++ b/_sass/projects.scss @@ -1,48 +1,27 @@ article.project { - display: flex; - justify-content: flex-start; - align-items: flex-start; - flex-wrap: nowrap; - flex-direction: row; + display: flex; + justify-content: flex-start; + align-items: flex-start; + flex-wrap: nowrap; + flex-direction: row; - h2 {margin-top: 0;} + h2 { + margin-top: 0; + } - a.photo { - width: $thumbnail_image_size; - height: $thumbnail_image_size; - margin-right: 1em; - } - - img { - max-height: $thumbnail_image_size; - width: unset; - aspect-ratio: 1 / 1; - } - figure { - padding: 0; - justify-content: center; - } + a.photo { + width: $thumbnail_image_size; + height: $thumbnail_image_size; + margin-right: 1em; + } + + img { + max-height: $thumbnail_image_size; + width: unset; + aspect-ratio: 1 / 1; + } + figure { + padding: 0; + justify-content: center; + } } - -// @media -// only screen and (max-width: $horizontal_breakpoint), -// only screen and (max-height: $vertical_breakpoint) -// { -// main { -// padding-top: 10px; -// padding-left: 20px; -// padding-right: 20px; -// margin: 0px; -// } - -// article { -// margin-left: 0px; -// } - -// h1 {font-size: 1.5em !important;} -// .MathJax { -// font-size: 0.8em !important; -// overflow-x: auto; -// overflow-y: hidden; -// } -// } \ No newline at end of file diff --git a/assets/js/index.js b/assets/js/index.js index 8ad0d30..a8a440b 100644 --- a/assets/js/index.js +++ b/assets/js/index.js @@ -1,18 +1,79 @@ function toggle_summary_by_class(element, topic) { - details = document.querySelectorAll(`details.${topic}`); + details = document.querySelectorAll(`details.${topic}`); - if(element.textContent === "Expand all") { - element.textContent = "Collapse all"; - details.forEach(e => e.open = true); - } else { - element.textContent = "Expand all" - details.forEach(e => e.open = false); - } - + if (element.textContent === "Expand all") { + element.textContent = "Collapse all"; + details.forEach((e) => (e.open = true)); + } else { + element.textContent = "Expand all"; + details.forEach((e) => (e.open = false)); + } } +// Signal that we have JS enabled +document.documentElement.classList.remove("no-js"); + // This signals to css that we have support for web components // Allows us to set elements to act as fallbacks when js/web components are disabled. if (window.customElements) { - document.querySelector('body').classList.add('has-wc'); -} \ No newline at end of file + document.querySelector("body").classList.add("has-wc"); +} + +// run the night mode toggle +const STORAGE_KEY = "user-color-scheme"; +const COLOR_MODE_KEY = "--color-mode"; + +const modeToggleButton = document.querySelector(".js-mode-toggle"); +const modeStatusElement = document.querySelector(".js-mode-status"); + +const getCSSCustomProp = (propKey) => { + let response = getComputedStyle(document.documentElement).getPropertyValue( + propKey + ); + + if (response.length) { + response = response.replace(/\"/g, "").trim(); + } + + return response; +}; + +const applySetting = (passedSetting) => { + let currentSetting = passedSetting || localStorage.getItem(STORAGE_KEY); + + if (currentSetting) { + document.documentElement.setAttribute( + "data-user-color-scheme", + currentSetting + ); + } +}; + +const toggleSetting = () => { + let currentSetting = localStorage.getItem(STORAGE_KEY); + + switch (currentSetting) { + case null: + currentSetting = + getCSSCustomProp(COLOR_MODE_KEY) === "dark" ? "light" : "dark"; + break; + case "light": + currentSetting = "dark"; + break; + case "dark": + currentSetting = "light"; + break; + } + + localStorage.setItem(STORAGE_KEY, currentSetting); + + return currentSetting; +}; + +modeToggleButton.addEventListener("click", (evt) => { + evt.preventDefault(); + + applySetting(toggleSetting()); +}); + +applySetting(); diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..aa033d0 --- /dev/null +++ b/ruff.toml @@ -0,0 +1 @@ +line-length = 60 \ No newline at end of file