diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b2fe0b1..498c25f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -35,6 +35,7 @@ "npm-run-all": "^4.1.5", "postcss": "^8.4.38", "postcss-cli": "^11.0.0", + "postcss-prune-var": "^1.1.2", "rimraf": "^5.0.7", "rollup": "^4.18.0", "rollup-plugin-filesize": "^10.0.0", @@ -8496,6 +8497,39 @@ "postcss": "^8.4.31" } }, + "node_modules/postcss-prune-var": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-prune-var/-/postcss-prune-var-1.1.2.tgz", + "integrity": "sha512-frMnVhQ4SXAY2tfRQmqfdIa6125XtfZUvB1D+t9n63Z12zp4MV6p7TAGipa7Ici9OoQt2XrXgVXdKBQD1ubTUw==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.3" + } + }, + "node_modules/postcss-prune-var/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/postcss-prune-var/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/postcss-reduce-initial": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index c3d5b6b..a3c611e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,7 +14,7 @@ "clean": "rimraf build lang", "devel:js": "rollup -c -w", "devel:scss": "for f in scss/*.scss; do sass --embed-source-map --watch $f build/css/`basename $f .scss`.css; done;", - "build:postprocess": "postcss build/css/style.css --use autoprefixer --use cssnano --no-map -r", + "build:postprocess": "postcss build/css/style.css --use autoprefixer --use cssnano --use postcss-prune-var --no-map -r", "start": "mkdir -p build && run-p 'devel:js -s' 'devel:scss -s'" }, "dependencies": { @@ -44,6 +44,7 @@ "npm-run-all": "^4.1.5", "postcss": "^8.4.38", "postcss-cli": "^11.0.0", + "postcss-prune-var": "^1.1.2", "rimraf": "^5.0.7", "rollup": "^4.18.0", "rollup-plugin-filesize": "^10.0.0", diff --git a/frontend/scss/abstracts/_mixins.scss b/frontend/scss/abstracts/_mixins.scss new file mode 100644 index 0000000..63e72e8 --- /dev/null +++ b/frontend/scss/abstracts/_mixins.scss @@ -0,0 +1,30 @@ +@use 'sass:color'; +@use "sass:map"; + +@mixin derive-colors($colors) { + @each $name, $color in $colors { + --#{$name}: #{$color}; + } + + // background materials + --material-background: var(--color-background); + --material-background50: var(--color-background50); + --material-background70: var(--color-background70); + --material-button: var(--color-button); + --material-control: var(--color-control); + --material-menu: var(--color-menu); + --material-sidepane: var(--color-sidepane); + --material-tabbar: var(--color-tabbar); + --material-toolbar: var(--color-toolbar); + --material-mix-quinary: var(--color-quinary-on-background); + --material-mix-quarternary: var(--color-quarternary-on-background); + --material-stripe: var(--color-stripe-on-background); + + // border materials + --material-border-transparent: 1px solid transparent; + --material-border: 1px solid var(--color-border); + --material-border50: 1px solid var(--color-border50); + --material-panedivider: 1px solid var(--color-panedivider); + --material-border-quinary: 1px solid var(--fill-quinary); + --material-border-quarternary: 1px solid var(--fill-quarternary); +} \ No newline at end of file diff --git a/frontend/scss/style.scss b/frontend/scss/style.scss index 24aac86..79136f3 100644 --- a/frontend/scss/style.scss +++ b/frontend/scss/style.scss @@ -1,42 +1,24 @@ -$color: #000; +@import "abstracts/mixins"; +@import "themes/light"; +@import "themes/dark"; -$accent-color: #999; -$accent-background-color: #f0f0f0; - -$popover-color: #000; -$popover-background-color: #fff; -$popover-box-shadow-color: rgba(0, 0, 0, .15); - -$view-source-button-color: #000; - -$search-pane-button-color: $color; -$search-pane-button-border-color: $accent-color; -$search-pane-button-background-color: $accent-background-color; -$search-pane-button-hover-color: $color; -$search-pane-button-hover-border-color: #6d95e0; -$search-pane-button-hover-background-color: #bbcef1; -$search-pane-button-active-color: #fff; -$search-pane-button-active-border-color: rgb(89, 139, 236); -$search-pane-button-active-background-color: rgb(89, 139, 236); -$search-pane-button-active-hover-color: #fff; -$search-pane-button-active-hover-border-color: rgb(109, 149, 224); -$search-pane-button-active-hover-background-color: rgb(187, 206, 241); - -$search-pane-loading-indicator-color: #fff; -$search-pane-loading-indicator-background-color: #b50000; +html { + color-scheme: light dark; +} body { - color: $color; + background: var(--color-background); + color: var(--fill-primary); font-family: Georgia, "Times New Roman", Times, serif; margin: 0; padding: 0; + font-size: 16px; } h1 { font-size: 1.7em; } - h2 { font-size: 1.3em; margin: 0; @@ -49,8 +31,8 @@ h2 { .search-pane { - background: $accent-background-color; - border: 1px $accent-color solid; + background: var(--material-sidepane); + border: var(--material-panedivider); display: flex; flex-direction: row; margin: 1em 0; @@ -69,31 +51,34 @@ h2 { width: 90%; li { - background-color: $search-pane-button-background-color; - border: 1px $search-pane-button-border-color solid; - border-radius: 8px; - color: $search-pane-button-color; + background-color: var(--material-button); + box-shadow: + 0px 1px 0.75px 0px var(--fill-quinary), + 0px 0.25px 0.25px 0px var(--color-border); + ; + border: 0.5px solid var(--fill-senary); + color: var(--color-primary); cursor: default; display: inline-block; margin: 4px 7px 4px 0; padding: 3px 6px; + transition: border 0.15s ease, background-color 0.15s ease; &:hover { - background-color: $search-pane-button-hover-background-color; - border: 1px solid $search-pane-button-hover-border-color; - color: $search-pane-button-hover-color; + background-color: var(--accent-azure); + color: var(--accent-white); } &.field-active, &.format-active { - background: $search-pane-button-active-background-color; - border: 1px solid $search-pane-button-active-border-color; - color: $search-pane-button-active-color; + background: var(--accent-blue); + border-color: var(--accent-blue); + color: var(--accent-white); &:hover { - background: $search-pane-button-active-hover-background-color; - border: 1px solid $search-pane-button-active-hover-border-color; - color: $search-pane-button-active-hover-color; + background-color: var(--accent-azure); + border-color: var(--accent-blue); + color: var(--accent-white); } } } @@ -101,8 +86,8 @@ h2 { } .search-pane-loading-indicator { - background: $search-pane-loading-indicator-background-color; - color: $search-pane-loading-indicator-color; + background: var(--accent-red); + color: var(--accent-white); margin: 0; padding: .1em .2em .2em .6em; position: absolute; @@ -112,10 +97,22 @@ h2 { .search-field { - font-size: 16px; + font-size: 1em; + border: var(--material-border); + padding: 4px 6px; margin-top: 1em; max-width: 255px; width: 255px; + border-radius: 3px; + transition: border 0.15s ease, box-shadow 0.15s ease, padding 0.15s ease; + margin: 0; // Remove margin in Safari + background-clip: padding-box; // Remove inner shadow on iOS + + &:focus { + border-color: var(--accent-blue); + box-shadow: 0 0 0 2px var(--accent-blue); + outline: none; + } } .style-list { @@ -157,29 +154,21 @@ h2 { } } -.styles-loading { - min-height: 50px; - text-align: center; - - @at-root { - @keyframes loading { - to { - transform: rotate(360deg); - } - } +@keyframes loading { + to { + transform: rotate(360deg); } +} + +.styles-loading { + display: flex; + justify-content: center; + color: var(--accent-blue); - &:after { - animation: loading .75s steps(8, end) infinite; - background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHZlcnNpb249IjEuMSIgeT0iMHB4IiB4PSIwcHgiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgdmlld0JveD0iMCAwIDUwIDUwIj48cGF0aCBkPSJtMzUuODMgMy43NTljNC4zNzcgMi4yMjUgOC4wODYgNS44NiAxMC4yOSAxMC41M2wtMTAuMjEgNC42NDljLTAuODkwMi0yLjEyNy0yLjg0NC0zLjk1Ni01LjE2OC01LjExOWw1LjA5LTEwLjA2eiIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9Ii4zNTYxIiBjbGFzcz0ic3QxIi8+PGcgc3Ryb2tlPSIjZTdlN2U3IiBzdHJva2Utd2lkdGg9Ii4zNTYxIiBmaWxsPSIjZTdlN2U3Ij48cGF0aCBkPSJtNDcuNjcgMTcuNjNjMS41MzMgNC42NzMgMS41ODMgOS44NDEtMC4xNzMxIDE0LjcxbC0xMC41MS0zLjkwN2MwLjg2NTUtMi4xMjcgMC43NjY1LTQuNzk3LTAuMDQ5NDUtNy4yN2wxMC43My0zLjUzNnoiIGNsYXNzPSJzdDAiLz48cGF0aCBkPSJtNDYuMjQgMzUuODNjLTIuMjI1IDQuMzc3LTUuODYgOC4wODYtMTAuNTMgMTAuMjlsLTQuNjQ5LTEwLjE5YzIuMTI3LTAuODkwMiAzLjk1Ni0yLjg0NCA1LjExOS01LjE2OGwxMC4wNiA1LjA2OXoiIGNsYXNzPSJzdDAiLz48cGF0aCBkPSJtMzIuMzcgNDcuNjdjLTQuNjczIDEuNTMzLTkuODQxIDEuNTgzLTE0LjcxLTAuMTczMWwzLjkwNy0xMC41MWMyLjEyNyAwLjg2NTQgNC43OTcgMC43NjY1IDcuMjctMC4wNDk1bDMuNTM2IDEwLjczeiIgY2xhc3M9InN0MCIvPjxwYXRoIGQ9Im0xNC4xNyA0Ni4yNGMtNC4zNzctMi4yMi04LjA4Ni01Ljg2LTEwLjI5LTEwLjUzbDEwLjE5LTQuNjQ5YzAuODkwMiAyLjEyNyAyLjg0NCAzLjk1NiA1LjE2OCA1LjExOWwtNS4wNjkgMTAuMDZ6IiBjbGFzcz0ic3QwIi8+PHBhdGggZD0ibTIuMzI1IDMyLjM3Yy0xLjUzMy00LjY3My0xLjU4My05Ljg0MSAwLjE3MzEtMTQuNzFsMTAuNTEgMy45MDdjLTAuODY1NSAyLjEyNy0wLjc2NjUgNC43OTcgMC4wNDk0NSA3LjI3bC0xMC43MyAzLjUzNnoiIGNsYXNzPSJzdDAiLz48cGF0aCBkPSJtMy43NTkgMTQuMTdjMi4yMjYtNC4zNzcgNS44NjEtOC4wODYgMTAuNTMtMTAuMjlsNC42NDkgMTAuMTljLTIuMTI3IDAuODkwMi0zLjk1NiAyLjg0NC01LjExOSA1LjE2OGwtMTAuMDYtNS4wN3oiIGNsYXNzPSJzdDAiLz48cGF0aCBkPSJtMTcuNjMgMi4zMjVjNC42NzMtMS41MzMgOS44NDEtMS41ODMgMTQuNzEgMC4xNzMxbC0zLjkgMTAuNTFjLTIuMTI3LTAuODY1NC00Ljc5Ny0wLjc2NjUtNy4yNyAwLjA0OTVsLTMuNTQtMTAuNzR6IiBjbGFzcz0ic3QwIi8+PC9nPjwvc3ZnPgo=') 0 0 no-repeat; - content: ''; - display: inline-block; - height: 25px; - left: -62px; - position: relative; - top: .5em; - vertical-align: top; - width: 25px; + > svg { + width: 32px; + height: 32px; + animation: loading .75s linear infinite; } } @@ -189,10 +178,10 @@ h2 { left: 0; width: max-content; - background: $popover-background-color; - border: 2px $popover-color solid; - box-shadow: 1px 2px 4px 1px $popover-box-shadow-color; - color: $popover-color; + background: var(--material-background); + border: 2px var(--fill-primary) solid; + box-shadow: 1px 2px 4px 1px rgba(0, 0, 0, .15); + color: var(--fill-primary); display: none; margin-left: 40px; max-width: 700px; @@ -223,7 +212,7 @@ h2 { .style-view-source, .style-individual-link { - color: $view-source-button-color; + color: var(--color-primary); display: none; font-size: 11px; line-height: .9em; @@ -253,14 +242,7 @@ h2 { } } -/* -.inline-citation ul, -.inline-citation li { - margin: 0; - padding: 0; -} - -.inline-citation ul { - list-style: none; -} -*/ +::placeholder { + color: var(--color-placeholder); + opacity: 1; // Set opacity for Firefox +} \ No newline at end of file diff --git a/frontend/scss/themes/_dark.scss b/frontend/scss/themes/_dark.scss new file mode 100644 index 0000000..df6264f --- /dev/null +++ b/frontend/scss/themes/_dark.scss @@ -0,0 +1,62 @@ +$-colors: ( + accent-azure: #66adffd9, + accent-blue: #4072e5, + accent-blue10: #4072e54d, + accent-blue30: #4072e573, + accent-blue50: #4072e599, + accent-gold: #cc9200d9, + accent-green: #39bf68d9, + accent-orange: #ff794cd9, + accent-red: #db2c3ae5, + accent-teal: #59adc4e5, + accent-white: #fff, + accent-wood-dark: #996b6f, + accent-wood: #cc7a52e5, + accent-yellow: #faa700cc, + accent-highlight: #ffd40026, + fill-primary: #ffffffe5, + fill-secondary: #ffffff8c, + fill-tertiary: #ffffff4d, + fill-quarternary: #ffffff1f, + fill-quinary: #ffffff0f, + fill-senary: #ffffff08, + color-background: #1e1e1e, + color-background50: #1e1e1e80, + color-background70: #1e1e1eb2, + color-border: #ffffff2e, + color-border50: #ffffff17, + color-button: #404040, + color-control: #ccc, + color-menu: #28282894, + color-panedivider: #404040, + color-sidepane: #303030, + color-tabbar: #1e1e1e, + color-toolbar: #272727, + color-scrollbar: rgb(117, 117, 117), + color-scrollbar-hover: rgb(158, 158, 158), + color-scrollbar-background: transparent, + color-stripe: #ffffff0d, + tag-blue: #2ea8e5d9, + tag-gray: #aaac, + tag-green: #5fb236d9, + tag-indigo: #576dd9, + tag-magenta: #e56eeed9, + tag-orange: #f19837cc, + tag-plum: #a6507b, + tag-purple: #a28ae5e5, + tag-red: #ff6666e5, + tag-teal: #009980, + tag-yellow: #ffd400bf, + + color-placeholder: #555, +); +:root[data-color-scheme=dark] { + color-scheme: dark; + @include derive-colors($-colors); +} + +@media (prefers-color-scheme: dark) { + :root:not([data-color-scheme]) { + @include derive-colors($-colors); + } +} \ No newline at end of file diff --git a/frontend/scss/themes/_light.scss b/frontend/scss/themes/_light.scss new file mode 100644 index 0000000..3d1de70 --- /dev/null +++ b/frontend/scss/themes/_light.scss @@ -0,0 +1,68 @@ +$-colors: ( + accent-azure: #66adff, + accent-blue: #4072e5, + accent-blue10: #4072e51a, + accent-blue30: #4072e54d, + accent-blue50: #4072e580, + accent-gold: #cc9200, + accent-green: #39bf68, + accent-orange: #ff794c, + accent-red: #db2c3a, + accent-teal: #59adc4, + accent-white: #fff, + accent-wood-dark: #996b6f, + accent-wood: #cc7a52, + accent-yellow: #faa700, + accent-highlight: #ffea0080, + fill-primary: #000000d9, + fill-secondary: #00000080, + fill-tertiary: #00000040, + fill-quarternary: #0000001a, + fill-quinary: #0000000d, + fill-senary: #00000005, + color-background: #fff, + color-background50: #ffffff80, + color-background70: #ffffffb2, + color-border: #00000026, + color-border50: #00000014, + color-button: #fff, + color-control: #fff, + color-menu: #f6f6f6b8, + color-panedivider: #dadada, + color-sidepane: #f2f2f2, + color-tabbar: #f2f2f2, + color-toolbar: #f9f9f9, + color-scrollbar: rgb(194, 194, 194), + color-scrollbar-hover: rgb(125, 125, 125), + color-scrollbar-background: transparent, + color-stripe: #0000000a, + tag-blue: #2ea8e5, + tag-gray: #aaa, + tag-green: #5fb236, + tag-indigo: #576dd9, + tag-magenta: #e56eee, + tag-orange: #f19837, + tag-plum: #a6507b, + tag-purple: #a28ae5, + tag-red: #ff6666, + tag-teal: #009980, + tag-yellow: #ffd400, + + color-placeholder: #bbb, +); + +:root { + // fallback for browsers that do not support color-schemes (e.g., Safari 11) + @include derive-colors($-colors); +} + +:root[data-color-scheme=light] { + color-scheme: light; + @include derive-colors($-colors); +} + +@media (prefers-color-scheme: light) { + :root:not([data-color-scheme]) { + @include derive-colors($-colors); + } +} \ No newline at end of file diff --git a/frontend/src/component.jsx b/frontend/src/component.jsx index cc80ffe..e94ee95 100644 --- a/frontend/src/component.jsx +++ b/frontend/src/component.jsx @@ -463,7 +463,7 @@ const App = () => { preview={state.previewsCache[state.showPreviewFor] ?? { fetching: true } } /> - ) :
} + ) : } ); } @@ -508,5 +508,15 @@ const StylePreview = ({ preview, onMouseLeave }) => { ); }; +const StylesLoading = () => { + return ( +
+ + + +
+ ); +} + export default App; \ No newline at end of file