diff --git a/.gitignore b/.gitignore index 5b366bb78eb..179470c16af 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ docker-compose.override.yml *~ src/schema.rs.orig +.DS_Store diff --git a/app/app.js b/app/app.js index e45e8400e94..7bc0534665f 100644 --- a/app/app.js +++ b/app/app.js @@ -5,6 +5,9 @@ import Resolver from 'ember-resolver'; import config from './config/environment'; import * as Sentry from './sentry'; +import { theme } from './utils/theme'; + +theme.loadSettingTheme(); if (typeof FastBoot === 'undefined') { // eslint-disable-next-line unicorn/prefer-add-event-listener diff --git a/app/components/crate-downloads-list.module.css b/app/components/crate-downloads-list.module.css index 1a3c849b094..c1c9e7b406a 100644 --- a/app/components/crate-downloads-list.module.css +++ b/app/components/crate-downloads-list.module.css @@ -8,8 +8,8 @@ } .link { - color: #525252; - background-color: #edebdd; + color: var(--download-list-link); + background-color: var(--main-bg-dark); font-size: 90%; padding: 20px 10px; display: flex; diff --git a/app/components/crate-row.module.css b/app/components/crate-row.module.css index b5d7ad5a1a8..8fcd5130541 100644 --- a/app/components/crate-row.module.css +++ b/app/components/crate-row.module.css @@ -1,10 +1,9 @@ .crate-row { - --shadow: 0 1px 3px hsla(51, 90%, 42%, .35); - display: flex; flex-wrap: wrap; padding: 15px 25px; - background-color: white; + background-color: var(--item-background); + color: var(--item); border-radius: 5px; box-shadow: var(--shadow); transition: all 300ms; diff --git a/app/components/dependency-list/row.module.css b/app/components/dependency-list/row.module.css index ef9f7dda703..3174c830650 100644 --- a/app/components/dependency-list/row.module.css +++ b/app/components/dependency-list/row.module.css @@ -4,20 +4,19 @@ --range-color: var(--grey900); --crate-color: var(--grey700); --placeholder-opacity: 0.35; - --shadow: 0 1px 3px hsla(51, 90%, 42%, .35); - + display: flex; align-items: center; position: relative; font-size: 18px; padding: 15px 25px; - background-color: white; + background-color: var(--item-background); border-radius: 5px; box-shadow: var(--shadow); transition: all 300ms; &:hover, &.focused { - background-color: var(--hover-bg-color); + background-color: var(--item-hover); transition: all 0ms; } diff --git a/app/components/dropdown/menu-item.module.css b/app/components/dropdown/menu-item.module.css index 05d2baacd38..3eaac6a968e 100644 --- a/app/components/dropdown/menu-item.module.css +++ b/app/components/dropdown/menu-item.module.css @@ -1,15 +1,16 @@ .item { - > a, button { + > a, span, button { font-size: 90%; width: 100%; display: inline-flex; text-align: start; padding: 8px 10px; text-decoration: none; + cursor: pointer; color: var(--main-color) !important; &:hover { - background: #5e5e5e; + background: var(--menu-hover); color: white !important; } } diff --git a/app/components/dropdown/menu.module.css b/app/components/dropdown/menu.module.css index 35a0655e48b..a7c159200e1 100644 --- a/app/components/dropdown/menu.module.css +++ b/app/components/dropdown/menu.module.css @@ -2,7 +2,7 @@ margin: 0; text-align: left; padding: 0; - background: white; + background: var(--item-background); border: 1px solid var(--gray-border); list-style: none; overflow: hidden; diff --git a/app/components/email-input.module.css b/app/components/email-input.module.css index 75f30210d17..fb1fe6f27ab 100644 --- a/app/components/email-input.module.css +++ b/app/components/email-input.module.css @@ -6,7 +6,7 @@ .row { width: 100%; - border: 1px solid #d5d3cb; + border: 1px solid var(--gray-border); border-bottom-width: 0; padding: 10px 20px; display: flex; diff --git a/app/components/front-page-list/item.module.css b/app/components/front-page-list/item.module.css index 396e7b2aae5..7f6b278aa0c 100644 --- a/app/components/front-page-list/item.module.css +++ b/app/components/front-page-list/item.module.css @@ -1,5 +1,4 @@ .link { - --shadow: 0 2px 3px hsla(51, 50%, 44%, .35); display: flex; align-items: center; @@ -7,11 +6,11 @@ height: 60px; margin: 8px 0; padding: 0 15px; - background-color: white; - color: #525252; + background-color: var(--item-background); + color: var(--item); text-decoration: none; border-radius: 5px; - box-shadow: var(--shadow); + box-shadow: var(--shadow2); transition: background-color 300ms; &:focus-visible { @@ -20,14 +19,14 @@ } &:hover, &:focus-visible { - color: #525252; - background-color: hsl(58deg 72% 97%); + color: var(--download-list-link); + background-color: var(--item-hover); transition: background-color 0ms; } &:active { transform: translateY(2px); - --shadow: inset 0 0 0 1px hsla(51, 50%, 44%, .15); + box-shadow: inset 0 0 0 1px hsla(51, 50%, 44%, .15);; } } diff --git a/app/components/front-page-list/item/placeholder.module.css b/app/components/front-page-list/item/placeholder.module.css index 7be83a33b3c..8402216b57c 100644 --- a/app/components/front-page-list/item/placeholder.module.css +++ b/app/components/front-page-list/item/placeholder.module.css @@ -1,5 +1,4 @@ .link { - --shadow: 0 2px 3px hsla(51, 50%, 44%, .35); --placeholder-bg: hsla(59, 19%, 50%, 1.0); --placeholder-bg2: hsla(59, 19%, 50%, 0.7); @@ -9,10 +8,10 @@ height: 60px; margin: 8px 0; padding: 0 15px; - background-color: white; - color: #525252; + background-color: var(--item-background); + color: var(--download-list-link); border-radius: 5px; - box-shadow: var(--shadow); + box-shadow: var(--shadow2); cursor: wait; } diff --git a/app/components/header.hbs b/app/components/header.hbs index c515c3c00c5..e60c448f032 100644 --- a/app/components/header.hbs +++ b/app/components/header.hbs @@ -32,6 +32,17 @@ Browse All Crates | + + + Theme + + + Sync with system + Light theme + Dark theme + + + | Docs diff --git a/app/components/header.js b/app/components/header.js index ec3ed3cf82d..2dc10d5a55f 100644 --- a/app/components/header.js +++ b/app/components/header.js @@ -2,6 +2,8 @@ import { action } from '@ember/object'; import { inject as service } from '@ember/service'; import Component from '@glimmer/component'; +import { theme } from '../utils/theme'; + export default class Header extends Component { @service header; @service router; @@ -20,4 +22,16 @@ export default class Header extends Component { }, }); } + + @action useSystemTheme() { + theme.useSystemTheme(); + } + + @action useLightTheme() { + theme.useLightTheme(); + } + + @action useDarkTheme() { + theme.useDarkTheme(); + } } diff --git a/app/components/owned-crate-row.module.css b/app/components/owned-crate-row.module.css index 2468be7745c..fb0ec36855d 100644 --- a/app/components/owned-crate-row.module.css +++ b/app/components/owned-crate-row.module.css @@ -2,7 +2,7 @@ display: flex; align-items: center; background-color: #fff; - border: 1px solid #d5d3cb; + border: 1px solid var(--gray-border); padding: 20px 30px; font-weight: bold; cursor: pointer; @@ -24,12 +24,12 @@ width: 36px; height: 36px; margin-left: 10px; - border: 2px solid #d5d3cb; + border: 2px solid var(--gray-border); border-radius: 50%; .checked & { - background-color: #cfc487; - border-color: #cfc487; + background-color: var(--owned-crate-checked); + border-color: var(--owned-crate-checked); } } diff --git a/app/components/rendered-html.module.css b/app/components/rendered-html.module.css index ae18157e9b8..bad93ad0463 100644 --- a/app/components/rendered-html.module.css +++ b/app/components/rendered-html.module.css @@ -20,8 +20,9 @@ p { code { - background-color: #fff; - padding: 0 2px; + background-color: var(--code); + padding: 0 4px; + border-radius: 2px; } } @@ -35,7 +36,7 @@ overflow-x: auto; th, td { - border: 1px solid #dfe2e5; + border: 1px solid var(--rendered-html-table); padding: 6px 13px; } } diff --git a/app/components/rev-dep-row.module.css b/app/components/rev-dep-row.module.css index 3f078e8f048..aa81780488c 100644 --- a/app/components/rev-dep-row.module.css +++ b/app/components/rev-dep-row.module.css @@ -2,18 +2,17 @@ --hover-bg-color: hsl(217, 37%, 98%); --crate-color: var(--grey700); --placeholder-opacity: 0.35; - --shadow: 0 1px 3px hsla(51, 90%, 42%, .35); - + position: relative; font-size: 18px; padding: 15px 25px; - background-color: white; + background-color: var(--item-background); border-radius: 5px; box-shadow: var(--shadow); transition: all 300ms; &:hover, &.focused { - background-color: var(--hover-bg-color); + background-color: var(--item-hover); transition: all 0ms; } diff --git a/app/components/settings/api-tokens.module.css b/app/components/settings/api-tokens.module.css index bf90fa265ab..945f3e06b25 100644 --- a/app/components/settings/api-tokens.module.css +++ b/app/components/settings/api-tokens.module.css @@ -21,7 +21,7 @@ .row { width: 100%; - border: 1px solid #d5d3cb; + border: 1px solid var(--gray-border); border-bottom-width: 0; padding: 10px 20px; display: flex; diff --git a/app/components/version-list/row.module.css b/app/components/version-list/row.module.css index 5fb3a546f5b..f83fd3aa6fd 100644 --- a/app/components/version-list/row.module.css +++ b/app/components/version-list/row.module.css @@ -2,20 +2,19 @@ --bg-color: var(--grey200); --hover-bg-color: hsl(217, 37%, 98%); --fg-color: var(--grey700); - --shadow: 0 1px 3px hsla(51, 90%, 42%, .35); display: flex; align-items: center; position: relative; font-size: 18px; padding: 15px 25px; - background-color: white; + background-color: var(--item-background); border-radius: 5px; - box-shadow: var(--shadow); + box-shadow: var(--shadow2); transition: all 300ms; &:hover, &.focused { - background-color: var(--hover-bg-color); + background-color: var(--item-hover); transition: all 0ms; } diff --git a/app/index.html b/app/index.html index 81dac870e59..434d9a79891 100644 --- a/app/index.html +++ b/app/index.html @@ -1,5 +1,5 @@ - + diff --git a/app/styles/application.module.css b/app/styles/application.module.css index 7749c1fa02f..c9922314df9 100644 --- a/app/styles/application.module.css +++ b/app/styles/application.module.css @@ -1,29 +1,25 @@ +@import url(./theme.module.css); + :root { --violet800: hsl(252, 44%, 24%); --grey900: hsl(200, 15%, 19%); --grey700: hsl(200, 11%, 43%); --grey600: hsl(200, 13%, 60%); --grey200: hsl(200, 17%, 96%); - --green800: hsl(115, 31%, 31%); --yellow500: hsl(44, 100%, 60%); - --header-bg-color: var(--green800); - --footer-bg-color: var(--green800); - --font-sans: "Fira Sans", sans-serif; --font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - - --main-color: #383838; --main-color-light: #858585; - --main-bg: #f9f7ec; - --main-bg-dark: #edebdd; - --gray-border: #d5d3cb; - --link-color: rgb(0, 172, 91); - --link-hover-color: #007940; - --separator-color: #284725; + --download-list-link: #525252; + --owned-crate-checked: #cfc487; + --rendered-html-table: #dfe2e5; --placeholder-bg: hsl(212, 7%, 57%); --placeholder-bg2: hsl(213, 16%, 75%); + --separator-color: #284725; + --link-hover-color: #007940; + --link-color: rgb(0, 172, 91); } :global(.new-design) { diff --git a/app/styles/crate/version.module.css b/app/styles/crate/version.module.css index 89c83b3279a..5ccf5291f8e 100644 --- a/app/styles/crate/version.module.css +++ b/app/styles/crate/version.module.css @@ -6,13 +6,11 @@ } .docs { - --shadow: 0 2px 3px hsla(51, 50%, 44%, .35); - margin-bottom: 25px; padding: 25px; - background-color: white; + background-color: var(--item-background); border-radius: 5px; - box-shadow: var(--shadow); + box-shadow: var(--shadow2); @media only screen and (max-width: 550px) { margin-left: -15px; @@ -104,6 +102,9 @@ font-size: 160%; font-weight: bold; margin-bottom: 4px; + circle { + fill: #fff; + } } .num__align { diff --git a/app/styles/crates.module.css b/app/styles/crates.module.css index 01044bfff87..f53d7666def 100644 --- a/app/styles/crates.module.css +++ b/app/styles/crates.module.css @@ -4,7 +4,7 @@ justify-content: space-between; padding: 20px; border-radius: 5px; - background-color: white; + background-color: var(--item-background); margin-bottom: 40px; a { diff --git a/app/styles/dashboard.module.css b/app/styles/dashboard.module.css index 52e8fcfb3c6..1b671d043f1 100644 --- a/app/styles/dashboard.module.css +++ b/app/styles/dashboard.module.css @@ -81,7 +81,7 @@ } .feed { - background: white; + background: var(--item-background); padding: 0 20px 20px; } diff --git a/app/styles/me/pending-invites.module.css b/app/styles/me/pending-invites.module.css index 19813a7a861..94e6a743ff8 100644 --- a/app/styles/me/pending-invites.module.css +++ b/app/styles/me/pending-invites.module.css @@ -5,7 +5,7 @@ .row { margin: 0; padding: 20px; - border-bottom: 2px solid #d5d3cb; + border-bottom: 2px solid var(--gray-border); &:last-of-type { border: none; diff --git a/app/styles/shared/typography.module.css b/app/styles/shared/typography.module.css index 60abd926a84..8e96fbab87d 100644 --- a/app/styles/shared/typography.module.css +++ b/app/styles/shared/typography.module.css @@ -13,6 +13,6 @@ font-weight: normal; &:hover { - color: #6b6b6b; + color: var(--color4); } } diff --git a/app/styles/theme.module.css b/app/styles/theme.module.css new file mode 100644 index 00000000000..48dcb7964ab --- /dev/null +++ b/app/styles/theme.module.css @@ -0,0 +1,65 @@ +@media (prefers-color-scheme: light) { + [data-color-mode=auto][data-light-theme*=light] { + --shadow: 0 1px 3px hsla(51, 90%, 42%, .35); + --shadow2: 0 2px 3px hsla(51, 50%, 44%, .35); + --header-bg-color: hsl(115, 31%, 31%); + --footer-bg-color: hsl(115, 31%, 31%); + --main-color: #383838; + --main-bg: #f9f7ec; + --main-bg-dark: #edebdd; + --gray-border: #d5d3cb; + --menu-hover: #5e5e5e; + --item: #525252; + --item-background: #fff; + --item-hover: #fdfcf2; + --code: #fff; + } +} +@media (prefers-color-scheme: dark) { + [data-color-mode=auto][data-dark-theme*=dark] { + --shadow: 0 0 6px rgba(0,0,0,.4); + --shadow2: 0 2px 3px rgba(0,0,0,.3); + --header-bg-color: #24292e; + --footer-bg-color: #24292e; + --main-color: #c9d1d9; + --main-bg: #0d1117; + --main-bg-dark: #161c22; + --gray-border: #444444; + --menu-hover: #2a3138; + --item: #f9f7ec; + --item-background: #161c22; + --item-hover: #2a3138; + --code: #f0f6fc26; + } +} +[data-color-mode=light] { + --shadow: 0 1px 3px hsla(51, 90%, 42%, .35); + --shadow2: 0 2px 3px hsla(51, 50%, 44%, .35); + --header-bg-color: hsl(115, 31%, 31%); + --footer-bg-color: hsl(115, 31%, 31%); + --main-color: #383838; + --main-bg: #f9f7ec; + --main-bg-dark: #edebdd; + --gray-border: #d5d3cb; + --menu-hover: #5e5e5e; + --item: #525252; + --item-background: #fff; + --item-hover: #fdfcf2; + --code: #fff; +} + +[data-color-mode=dark] { + --shadow: 0 0 6px rgba(0,0,0,.4); + --shadow2: 0 2px 3px rgba(0,0,0,.3); + --header-bg-color: #24292e; + --footer-bg-color: #24292e; + --main-color: #c9d1d9; + --main-bg: #0d1117; + --main-bg-dark: #161c22; + --gray-border: #444444; + --menu-hover: #2a3138; + --item: #f9f7ec; + --item-background: #161c22; + --item-hover: #2a3138; + --code: #f0f6fc26; +} diff --git a/app/utils/theme.js b/app/utils/theme.js new file mode 100644 index 00000000000..11f12a0beea --- /dev/null +++ b/app/utils/theme.js @@ -0,0 +1,34 @@ +import { getItem, setItem } from './local-storage'; + +const THEME_KEY = 'tmeme'; + +export const theme = { + loadSettingTheme() { + switch (getItem(THEME_KEY)) { + case 'light': { + this.useLightTheme(); + break; + } + case 'dark': { + this.useDarkTheme(); + break; + } + default: { + this.useSystemTheme(); + break; + } + } + }, + useSystemTheme() { + document.querySelector('html').dataset.colorMode = 'auto'; + setItem(THEME_KEY, 'auto'); + }, + useLightTheme() { + document.querySelector('html').dataset.colorMode = 'light'; + setItem(THEME_KEY, 'light'); + }, + useDarkTheme() { + document.querySelector('html').dataset.colorMode = 'dark'; + setItem(THEME_KEY, 'dark'); + }, +}; diff --git a/public/assets/download.svg b/public/assets/download.svg index a754591d5ea..9feaac2fc24 100644 --- a/public/assets/download.svg +++ b/public/assets/download.svg @@ -1,6 +1,6 @@ - + diff --git a/tests/index.html b/tests/index.html index 7366af85f72..5196b4e3e9c 100644 --- a/tests/index.html +++ b/tests/index.html @@ -1,5 +1,5 @@ - +