diff --git a/code/libraries/array/cpp/resources/libcpp.so b/code/libraries/array/cpp/resources/libcpp.so new file mode 100755 index 00000000..9d6d9616 Binary files /dev/null and b/code/libraries/array/cpp/resources/libcpp.so differ diff --git a/code/services-application/search-service/resources/static/search/main.js b/code/services-application/search-service/resources/static/search/main.js index 618533b7..a6bd3157 100644 --- a/code/services-application/search-service/resources/static/search/main.js +++ b/code/services-application/search-service/resources/static/search/main.js @@ -1,6 +1,6 @@ -// This sets the data-has-js attribute on the body tag to true, so we can style the page with the assumption that +// This sets the data-has-js attribute on the html tag to true, so we can style the page with the assumption that // the browser supports JS. This is a progressive enhancement, so the page will still work without JS. -document.getElementsByTagName('body')[0].setAttribute('data-has-js', 'true'); +document.documentElement.setAttribute('data-has-js', 'true'); // To prevent the filter menu from being opened when the user hits enter on the search box, we need to add a keydown // handler to the search box that stops the event from propagating. Janky hack, but it works. diff --git a/code/services-application/search-service/resources/static/search/serp.scss b/code/services-application/search-service/resources/static/search/serp.scss index b2ca3a19..3e25e780 100644 --- a/code/services-application/search-service/resources/static/search/serp.scss +++ b/code/services-application/search-service/resources/static/search/serp.scss @@ -1,4 +1,6 @@ :root { + color-scheme: light; + --clr-bg-page: hsl(60, 42%, 95%); // $nicotine-light --clr-bg-ui: hsl(0, 0%, 100%); @@ -26,29 +28,41 @@ --font-family-heading: serif; // $heading-fonts } + +@mixin dark-theme-mixin { + color-scheme: dark; + + --clr-bg-page: hsl(0, 0%, 6%); + + --clr-bg-ui: hsl(0, 0%, 18%); + --clr-text-ui: #ddd; + + --clr-bg-theme: hsl(0, 0%, 2%); + --clr-text-theme: var(--clr-text-ui); + + --clr-bg-highlight: hsl(0, 0%, 11%); + --clr-text-highlight: #fff; + + --clr-bg-accent: hsl(200, 32%, 28%); + --clr-border-accent: hsl(200, 8%, 12%); + + --clr-border: hsl(0, 0%, 30%); + + --clr-shadow: #000; + + --clr-link: #8a8aff; + --clr-link-visited: #ffadff; + --clr-heading-link-visited: var(--clr-link-visited); +} + +:root[data-theme='dark'] { + @include dark-theme-mixin; +} + +// Makes theme match the user's OS preference when JS is disabled @media (prefers-color-scheme: dark) { - :root { - --clr-bg-page: hsl(0, 0%, 6%); - - --clr-bg-ui: hsl(0, 0%, 18%); - --clr-text-ui: #ddd; - - --clr-bg-theme: hsl(0, 0%, 2%); - --clr-text-theme: var(--clr-text-ui); - - --clr-bg-highlight: hsl(0, 0%, 11%); - --clr-text-highlight: #fff; - - --clr-bg-accent: hsl(200, 32%, 28%); - --clr-border-accent: hsl(200, 8%, 12%); - - --clr-border: hsl(0, 0%, 30%); - - --clr-shadow: #000; - - --clr-link: #8a8aff; - --clr-link-visited: #ffadff; - --clr-heading-link-visited: var(--clr-link-visited); + :root:not([data-has-js="true"]) { + @include dark-theme-mixin; } } @@ -56,10 +70,6 @@ box-sizing: border-box; } -html { - color-scheme: light dark; -} - a { color: var(--clr-link); } @@ -199,6 +209,9 @@ header { color: var(--clr-text-ui); box-shadow: 0 0 0.5ch var(--clr-shadow); margin-bottom: 1ch; + display: flex; + align-items: center; + justify-content: space-between; nav { a { @@ -228,6 +241,15 @@ header { } } +#theme { + padding: .5ch; + display: none; + + [data-has-js='true'] & { + display: block; + } +} + #complaint { @extend .dialog; max-width: 60ch; @@ -333,10 +355,8 @@ section.cards { line-height: 1.6; } - @media (prefers-color-scheme: dark) { - & { - border: 1px solid var(--clr-border); - } + [data-theme='dark'] & { + border: 1px solid var(--clr-border); } } } @@ -525,6 +545,8 @@ footer { font-family: var(--font-family-heading); font-weight: normal; text-align: center; + display: flex; + justify-content: space-between; } #suggestions-anchor { @@ -717,7 +739,7 @@ footer { } @media (max-device-width: 624px) { - body[data-has-js="true"] { // This property is set via js so we can selectively enable these changes only if JS is enabled; + [data-has-js="true"] body { // This property is set via js so we can selectively enable these changes only if JS is enabled; // This is desirable since mobile navigation is JS-driven. If JS is disabled, having a squished // GUI is better than having no working UI. margin: 0 !important; @@ -733,6 +755,8 @@ footer { #mcfeast { display: inline; float: right; + width: 2rem; + font-size: 1rem; } #menu-close { diff --git a/code/services-application/search-service/resources/static/search/theme.js b/code/services-application/search-service/resources/static/search/theme.js new file mode 100644 index 00000000..73fdcd26 --- /dev/null +++ b/code/services-application/search-service/resources/static/search/theme.js @@ -0,0 +1,57 @@ +function getTheme() { + const theme = window.localStorage.getItem('theme'); + + // if a valid theme is set in localStorage, return it + if (theme === 'dark' || theme === 'light') { + return { value: theme, system: false }; + } + + // if matchMedia is supported and OS theme is dark + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + return { value: 'dark', system: true }; + } + + return { value: 'light', system: true }; +} + +function setTheme(value) { + if (value === 'dark' || value === 'light') { + window.localStorage.setItem('theme', value); + } else { + window.localStorage.removeItem('theme'); + } + + const theme = getTheme(); + + document.documentElement.setAttribute('data-theme', theme.value); +} + +function initializeTheme() { + const themeSelect = document.getElementById('theme-select'); + + const theme = getTheme(); + + document.documentElement.setAttribute('data-theme', theme.value); + + // system is selected by default in the themeSwitcher so ignore it here + if (!theme.system) { + themeSelect.value = theme.value; + } + + themeSelect.addEventListener('change', e => { + setTheme(e.target.value); + }); + + const mql = window.matchMedia('(prefers-color-scheme: dark)'); + + // if someone changes their theme at the OS level we need to update + // their theme immediately if they're using their OS theme + mql.addEventListener('change', e => { + if (themeSelect.value !== 'system') return; + + if (e.matches) setTheme('dark'); + else setTheme('light'); + }); +} + +initializeTheme(); \ No newline at end of file diff --git a/code/services-application/search-service/resources/templates/search/parts/search-header.hdb b/code/services-application/search-service/resources/templates/search/parts/search-header.hdb index c9ad0dab..805ea8a9 100644 --- a/code/services-application/search-service/resources/templates/search/parts/search-header.hdb +++ b/code/services-application/search-service/resources/templates/search/parts/search-header.hdb @@ -7,4 +7,15 @@ Donate Random +
+ + +
+ + + \ No newline at end of file