From a73914d0efc40af6c6494d0f7f5956ce06ca10cf Mon Sep 17 00:00:00 2001 From: Andras Schmelczer Date: Sun, 24 May 2026 10:58:36 +0100 Subject: [PATCH] Restyle the app interface --- assets/fonts/comfortaa-v40-latin-regular.woff | Bin 15100 -> 0 bytes .../fonts/comfortaa-v40-latin-regular.woff2 | Bin 12028 -> 0 bytes assets/fonts/open-sans-v34-latin-regular.woff | Bin 20712 -> 0 bytes src/index.scss | 281 +--------------- src/style/_app-shell.scss | 133 ++++++++ src/style/_config-pane.scss | 309 ++++++++++++++++++ src/style/_control-dock.scss | 39 +++ src/style/_garden-prompt.scss | 126 +++++++ src/style/_loading.scss | 183 +++++++++++ src/style/_panels.scss | 96 ++++++ src/style/_toolbar.scss | 4 + src/style/common.scss | 44 +-- src/style/fonts.scss | 19 +- src/style/mixins.scss | 130 +------- src/style/toolbar/_buttons.scss | 161 +++++++++ src/style/toolbar/_garden-controls.scss | 148 +++++++++ src/style/toolbar/_layout.scss | 173 ++++++++++ src/style/toolbar/_responsive.scss | 157 +++++++++ src/style/toolbar/_shared.scss | 104 ++++++ src/style/vars.scss | 27 +- 20 files changed, 1662 insertions(+), 472 deletions(-) delete mode 100644 assets/fonts/comfortaa-v40-latin-regular.woff delete mode 100644 assets/fonts/comfortaa-v40-latin-regular.woff2 delete mode 100644 assets/fonts/open-sans-v34-latin-regular.woff create mode 100644 src/style/_app-shell.scss create mode 100644 src/style/_config-pane.scss create mode 100644 src/style/_control-dock.scss create mode 100644 src/style/_garden-prompt.scss create mode 100644 src/style/_loading.scss create mode 100644 src/style/_panels.scss create mode 100644 src/style/_toolbar.scss create mode 100644 src/style/toolbar/_buttons.scss create mode 100644 src/style/toolbar/_garden-controls.scss create mode 100644 src/style/toolbar/_layout.scss create mode 100644 src/style/toolbar/_responsive.scss create mode 100644 src/style/toolbar/_shared.scss diff --git a/assets/fonts/comfortaa-v40-latin-regular.woff b/assets/fonts/comfortaa-v40-latin-regular.woff deleted file mode 100644 index c54393b0f232a808940e24118be9d4c56f29553c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15100 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

wmmAf(Ia5sSiLTs)4zmfsP_ibo1X7^{SoZPb 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 amd?$S(55001cYhm-k%A-FTxptyp(@(;K3V-x-d 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 diff --git a/src/index.scss b/src/index.scss index 8c4500a..d6d8b85 100644 --- a/src/index.scss +++ b/src/index.scss @@ -1,275 +1,8 @@ -@use 'style/mixins' as *; @use 'style/common'; - -html > body { - width: 100%; - height: 100%; - display: flex; - position: relative; - - > .canvas-container { - height: 100%; - width: 100%; - display: flex; - - > canvas { - height: 100%; - width: 100%; - touch-action: none; - cursor: - url('../assets/icons/brush.svg') 0 24, - auto; - } - - > .errors-container { - position: absolute; - top: 0; - left: 0; - margin: var(--normal-margin); - - pre { - font-size: 20px; - color: red; - } - } - - .counters { - @include blurred-background(white); - position: absolute; - border-radius: var(--border-radius); - padding: var(--small-margin); - - @include on-large-screen { - top: var(--normal-margin); - right: var(--normal-margin); - } - - @include on-small-screen { - bottom: var(--normal-margin); - right: var(--normal-margin); - } - } - } - - > aside { - @include blurred-background(#fff); - box-shadow: var(--shadow); - display: flex; - position: absolute; - overflow: hidden; - - @include on-large-screen { - top: 50%; - left: 0; - transform: translateY(-50%); - max-height: 350px; - } - - @include on-small-screen { - top: 0; - left: 50%; - transform: translateX(-50%); - flex-direction: column; - } - - transition: opacity var(--transition-time-long); - border-radius: var(--border-radius); - margin: var(--small-margin); - - > nav.buttons { - @include center-children; - justify-content: space-evenly; - - @include on-large-screen { - flex-direction: column; - } - - > button { - position: relative; - border: none; - background-color: transparent; - cursor: pointer; - - @include square(var(--icon-size)); - margin: var(--small-margin); - - &::before, - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - height: 100%; - width: 100%; - } - - &::before { - background-color: var(--accent-color); - - @include on-large-screen { - width: 0; - border-radius: 0 var(--border-radius) var(--border-radius) 0; - transition: - background-color var(--transition-time), - width var(--transition-time); - left: calc(-1 * var(--small-margin)); - height: 140%; - top: 50%; - transform: translateY(-50%); - } - - @include on-small-screen { - height: 0; - border-radius: 0 0 var(--border-radius) var(--border-radius); - transition: - background-color var(--transition-time), - height var(--transition-time); - top: calc(-1 * var(--small-margin)); - width: 140%; - left: 50%; - transform: translateX(-50%); - } - } - - &::after { - background-color: var(--accent-color); - - transition: - transform var(--transition-time), - background-color var(--transition-time); - - mask-repeat: no-repeat; - - @include square(var(--icon-size)); - } - - &.active { - &::before { - @include on-large-screen { - width: calc(100% + 2 * var(--small-margin)); - } - - @include on-small-screen { - height: calc(100% + 2 * var(--small-margin)); - } - } - - &::after { - background-color: white; - } - } - - &:hover::after { - transform: scale(1.15); - } - - &.info::after { - mask-image: url('../assets/icons/info.svg'); - } - &.maximize-full-screen::after { - mask-image: url('../assets/icons/maximize.svg'); - } - &.minimize-full-screen::after { - mask-image: url('../assets/icons/minimize.svg'); - } - &.settings::after { - mask-image: url('../assets/icons/settings.svg'); - } - &.restart::after { - mask-image: url('../assets/icons/restart.svg'); - } - } - } - - > main.pages { - overflow-x: hidden; - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: var(--main-color) transparent; - &::-webkit-scrollbar-track, - &::-webkit-scrollbar { - background-color: transparent; - width: 6px; - } - &::-webkit-scrollbar-thumb { - background-color: var(--main-color); - border-radius: var(--border-radius); - } - - &, - > * { - transition: - width var(--transition-time-long), - height var(--transition-time-long); - - @include on-large-screen { - width: max(500px, 10vw); - } - - @include on-small-screen { - height: max(500px, 70vh); - } - } - - &.hidden { - @include on-large-screen { - width: 0; - } - - @include on-small-screen { - height: 0; - } - } - - > section { - padding: var(--normal-margin); - display: flex; - flex-direction: column; - - .slider { - $track-height: 12px; - margin-bottom: var(--small-margin); - user-select: none; - - p { - display: flex; - justify-content: space-between; - } - - input[type='range'] { - width: 100%; - height: $track-height; - appearance: none; - background: transparent; - outline: none; - border-radius: 1000px; - - &::-webkit-slider-runnable-track { - appearance: none; - cursor: pointer; - border-radius: 1000px; - @include square(15px); - background: var(--accent-color); - } - - &::-webkit-slider-thumb { - appearance: none; - cursor: pointer; - border-radius: 1000px; - $size: 24px; - @include square($size); - background: white; - box-shadow: 0 0 5px 1px var(--accent-color); - - transform: translateY(-5px); - transition: transform var(--transition-time); - &:hover { - transform: translateY(-5px) scale(1.1); - } - } - } - } - } - } - } -} +@use 'style/app-shell'; +@use 'style/garden-prompt'; +@use 'style/control-dock'; +@use 'style/toolbar'; +@use 'style/config-pane'; +@use 'style/panels'; +@use 'style/loading'; diff --git a/src/style/_app-shell.scss b/src/style/_app-shell.scss new file mode 100644 index 0000000..abf8824 --- /dev/null +++ b/src/style/_app-shell.scss @@ -0,0 +1,133 @@ +html > body.is-loading .perf-stats-overlay { + display: none; +} + +$grain-noise-a: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='257' height='257' viewBox='0 0 257 257'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' seed='17' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='257' height='257' filter='url(%23n)'/%3E%3C/svg%3E"); +$grain-noise-b: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='389' height='389' viewBox='0 0 389 389'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.53' numOctaves='5' seed='41' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='389' height='389' filter='url(%23n)'/%3E%3C/svg%3E"); + +html > body { + width: 100%; + height: 100vh; + height: 100dvh; + overflow: hidden; + display: flex; + position: relative; + background: var(--garden-background, #10151f); + + > .canvas-container { + height: 100%; + width: 100%; + display: flex; + position: relative; + overflow: hidden; + + > canvas { + position: relative; + z-index: 0; + height: 100%; + width: 100%; + touch-action: none; + } + + > .garden-grain { + --garden-grain-strength: 0; + + position: absolute; + inset: 0; + z-index: 1; + pointer-events: none; + contain: strict; + + &::before, + &::after { + content: ''; + position: absolute; + inset: 0; + } + + &::before { + opacity: clamp(0, calc(var(--garden-grain-strength) * 4.25), 0.24); + background-image: $grain-noise-a; + background-size: 257px 257px; + filter: contrast(145%) brightness(0.82); + mix-blend-mode: multiply; + } + + &::after { + opacity: clamp(0, calc(var(--garden-grain-strength) * 2.5), 0.12); + background-image: $grain-noise-b; + background-position: 73px 41px; + background-size: 389px 389px; + filter: contrast(135%) brightness(1); + mix-blend-mode: screen; + transform: rotate(0.01deg); + } + + &[hidden] { + display: none; + } + } + + > .eraser-preview { + position: absolute; + top: 0; + left: 0; + z-index: 3; + width: var(--eraser-preview-size, 96px); + height: var(--eraser-preview-size, 96px); + border: 2px solid rgb(255 234 228 / 88%); + border-radius: 50%; + background: rgb(255 140 117 / 13%); + box-shadow: + 0 0 0 1px rgb(255 88 70 / 34%), + 0 0 26px rgb(255 118 92 / 24%); + opacity: 0; + pointer-events: none; + transform: translate(-50%, -50%); + transition: + opacity var(--transition-time), + width var(--transition-time), + height var(--transition-time); + mix-blend-mode: screen; + + &.visible { + opacity: 1; + } + } + + > .perf-stats-overlay { + position: absolute; + top: max(8px, env(safe-area-inset-top)); + left: max(8px, env(safe-area-inset-left)); + z-index: 6; + padding: 6px 8px; + border: 1px solid rgb(255 255 255 / 18%); + border-radius: 6px; + background: rgb(0 0 0 / 62%); + color: rgb(255 255 255 / 92%); + font: + 600 12px/1.35 ui-monospace, + SFMono-Regular, + Menlo, + Consolas, + monospace; + white-space: pre; + pointer-events: none; + user-select: none; + box-shadow: 0 8px 24px rgb(0 0 0 / 28%); + } + + > .errors-container { + position: absolute; + top: 0; + left: 0; + margin: var(--normal-margin); + z-index: 5; + + pre { + font-size: 20px; + color: red; + } + } + } +} diff --git a/src/style/_config-pane.scss b/src/style/_config-pane.scss new file mode 100644 index 0000000..ad7ae31 --- /dev/null +++ b/src/style/_config-pane.scss @@ -0,0 +1,309 @@ +@use 'mixins' as *; + +.config-pane-container { + --config-pane-available-height: calc( + 100vh - 24px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) + ); + + position: fixed; + top: max(12px, env(safe-area-inset-top, 0px)); + right: max(12px, env(safe-area-inset-right, 0px)); + display: grid; + grid-template-rows: auto minmax(0, 1fr); + gap: 4px; + z-index: 20; + width: min( + 420px, + calc(100vw - 24px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)) + ); + max-height: var(--config-pane-available-height); + pointer-events: none; + + @supports (height: 100dvh) { + --config-pane-available-height: calc( + 100dvh - 24px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) + ); + } +} + +.config-pane-container--open { + pointer-events: auto; +} + +.config-pane { + --tp-blade-value-width: min(260px, 64%); + + width: 100%; + max-height: calc(var(--config-pane-available-height) - 36px); + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior: contain; + pointer-events: auto; + scrollbar-width: thin; + touch-action: pan-y; + -webkit-overflow-scrolling: touch; + + // Tweakpane v4 internal classes — re-verify on upgrade. + // No public theming hook exists for label padding or the slider/number + // flex ratio; if a fourth override appears here, switch to a custom plugin. + .tp-lblv_l { + padding-right: 10px; + } + + .tp-sldtxtv_s { + flex: 1 1 auto; + min-width: 0; + } + + .tp-sldtxtv_t { + flex: 0 0 54px; + } +} + +.config-pane-close { + position: relative; + justify-self: end; + display: grid; + width: 28px; + height: 28px; + place-items: center; + border: 0; + border-radius: 4px; + background: transparent; + color: rgb(235 238 245 / 82%); + cursor: pointer; + font: inherit; + font-size: 0; + pointer-events: auto; + transition: + background-color var(--transition-time), + color var(--transition-time); + + &::before, + &::after { + content: ''; + position: absolute; + width: 14px; + height: 2px; + border-radius: 999px; + background: currentColor; + } + + &::before { + transform: rotate(45deg); + } + + &::after { + transform: rotate(-45deg); + } + + &:hover { + background: rgb(255 255 255 / 10%); + color: white; + } + + &:focus-visible { + outline: 2px solid white; + outline-offset: -2px; + } + + &[hidden] { + display: none; + } +} + +@mixin mobile-config-pane() { + .config-pane-container { + --config-pane-available-height: min( + 64vh, + calc( + 100vh - 112px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) + ) + ); + + top: max(8px, env(safe-area-inset-top, 0px)); + right: auto; + left: 50%; + width: min(80vw, 420px); + transform: translateX(-50%); + + @supports (height: 100dvh) { + --config-pane-available-height: min( + 64dvh, + calc( + 100dvh - + 112px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) + ) + ); + } + } + + .config-pane { + --tp-blade-value-width: min(210px, 62%); + --tp-container-unit-size: 18px; + + padding-bottom: 10px; + font-size: 11px; + + // Tweakpane v4 internal class — re-verify on upgrade. + .tp-sldtxtv_t { + flex-basis: 48px; + } + } + + .config-pane-close { + width: 32px; + height: 32px; + } +} + +@include on-mobile-input { + @include mobile-config-pane; +} + +.color-reaction-matrix-blade { + padding: 6px 8px 8px; +} + +.color-reaction-matrix { + display: grid; + grid-template-columns: 28px repeat(3, minmax(0, 1fr)); + gap: 4px; + align-items: stretch; +} + +.color-reaction-matrix__corner, +.color-reaction-matrix__header { + display: flex; + min-width: 0; + min-height: 28px; + align-items: center; + justify-content: center; + color: rgb(255 255 255 / 76%); + font-size: 11px; + line-height: 1; +} + +.color-reaction-matrix__header { + gap: 0; +} + +.color-reaction-matrix__corner { + justify-content: flex-start; + padding-left: 2px; + color: rgb(255 255 255 / 62%); +} + +.color-reaction-matrix__swatch { + flex: 0 0 auto; + width: 12px; + height: 12px; + border: 1px solid rgb(255 255 255 / 55%); + border-radius: 999px; + box-shadow: 0 0 0 1px rgb(0 0 0 / 18%); +} + +.color-reaction-matrix__cell { + min-width: 0; + display: grid; +} + +.color-reaction-matrix__button { + position: relative; + display: grid; + width: 100%; + min-width: 0; + height: 28px; + place-items: center; + border: 1px solid rgb(255 255 255 / 16%); + border-radius: 4px; + padding: 0 4px; + background: rgb(255 255 255 / 8%); + color: white; + font: inherit; + cursor: pointer; + transition: + background-color var(--transition-time), + border-color var(--transition-time), + color var(--transition-time), + transform var(--transition-time); +} + +.color-reaction-matrix__button:hover { + transform: translateY(-1px); +} + +.color-reaction-matrix__button:focus-visible { + outline: 2px solid rgb(255 255 255 / 72%); + outline-offset: 1px; +} + +.color-reaction-matrix__button[data-reaction='follow'] { + border-color: rgb(115 235 160 / 44%); + background: rgb(53 165 96 / 20%); + color: rgb(157 255 195 / 94%); +} + +.color-reaction-matrix__button[data-reaction='ignore'] { + border-color: rgb(255 255 255 / 18%); + background: rgb(255 255 255 / 7%); + color: rgb(235 238 245 / 72%); +} + +.color-reaction-matrix__button[data-reaction='avoid'] { + border-color: rgb(255 145 120 / 46%); + background: rgb(215 74 54 / 19%); + color: rgb(255 171 148 / 94%); +} + +.color-reaction-matrix__icon { + position: relative; + display: block; + width: 16px; + height: 16px; +} + +.color-reaction-matrix__icon::before, +.color-reaction-matrix__icon::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + border-radius: 999px; + background: currentColor; + transform: translate(-50%, -50%); +} + +.color-reaction-matrix__button[data-reaction='follow'] + > .color-reaction-matrix__icon::before, +.color-reaction-matrix__button[data-reaction='avoid'] + > .color-reaction-matrix__icon::before { + width: 14px; + height: 2px; +} + +.color-reaction-matrix__button[data-reaction='follow'] + > .color-reaction-matrix__icon::after { + width: 2px; + height: 14px; +} + +.color-reaction-matrix__button[data-reaction='avoid'] + > .color-reaction-matrix__icon::after { + display: none; +} + +.color-reaction-matrix__button[data-reaction='ignore'] > .color-reaction-matrix__icon { + width: 12px; + height: 12px; + border: 2px solid currentColor; + border-radius: 999px; + opacity: 0.82; +} + +.color-reaction-matrix__button[data-reaction='ignore'] + > .color-reaction-matrix__icon::before, +.color-reaction-matrix__button[data-reaction='ignore'] + > .color-reaction-matrix__icon::after { + display: none; +} diff --git a/src/style/_control-dock.scss b/src/style/_control-dock.scss new file mode 100644 index 0000000..aec5d2f --- /dev/null +++ b/src/style/_control-dock.scss @@ -0,0 +1,39 @@ +html > body > aside.control-dock { + --dock-hidden-translate-y: calc(100% + env(safe-area-inset-bottom, 0px) + 16px); + + position: absolute; + left: 0; + right: 0; + bottom: env(safe-area-inset-bottom, 0px); + z-index: 4; + width: min(calc(100vw - 1rem), 980px); + margin: 0 auto; + transform: translateY(0); + visibility: visible; + pointer-events: none; + transition: + opacity var(--transition-time-long), + transform var(--transition-time-long), + visibility 0s; + + > .toolbar-row, + > .info-page { + pointer-events: auto; + } + + &.menu-hidden { + opacity: 0; + visibility: hidden; + transform: translateY(var(--dock-hidden-translate-y)); + pointer-events: none; + transition: + opacity var(--transition-time-long), + transform var(--transition-time-long), + visibility 0s var(--transition-time-long); + + > .toolbar-row, + > .info-page { + pointer-events: none; + } + } +} diff --git a/src/style/_garden-prompt.scss b/src/style/_garden-prompt.scss new file mode 100644 index 0000000..6f7cf74 --- /dev/null +++ b/src/style/_garden-prompt.scss @@ -0,0 +1,126 @@ +@use 'mixins' as *; + +html > body > .canvas-container > .garden-prompt { + position: absolute; + left: 50%; + transform: translateX(-50%); + text-align: center; + pointer-events: none; + z-index: 2; + + &:empty { + display: none; + } + + &.draw-hint { + display: flex; + align-items: center; + top: calc(1.25rem + env(safe-area-inset-top)); + gap: 16px; + width: max-content; + min-height: 78px; + max-width: min(88vw, 460px); + padding: 12px 18px 12px 14px; + border: 1px solid rgb(255 255 255 / 16%); + border-radius: 8px; + background: rgb(10 12 16 / 50%); + box-shadow: + 0 14px 42px rgb(0 0 0 / 28%), + inset 0 0 0 1px rgb(255 255 255 / 5%); + backdrop-filter: blur(12px); + color: rgb(255 255 255 / 94%); + font-size: 20px; + font-weight: 400; + line-height: 1.2; + text-shadow: 0 1px 12px rgb(0 0 0 / 58%); + } + + .draw-hint-mark { + width: 128px; + height: 72px; + flex: 0 0 128px; + overflow: visible; + } + + .draw-hint-shadow, + .draw-hint-stroke { + fill: none; + stroke-linecap: round; + stroke-linejoin: round; + } + + .draw-hint-shadow { + stroke: rgb(0 0 0 / 42%); + stroke-width: 10px; + } + + .draw-hint-stroke { + stroke: color-mix(in srgb, var(--accent-color) 74%, white); + stroke-width: 5px; + stroke-dasharray: 154; + animation: draw-hint-stroke 2.4s ease-in-out infinite; + filter: drop-shadow( + 0 0 12px color-mix(in srgb, var(--accent-color) 60%, transparent) + ); + } + + .draw-hint-start { + fill: rgb(255 255 255 / 64%); + } + + .draw-hint-end { + fill: white; + stroke: color-mix(in srgb, var(--accent-color) 72%, transparent); + stroke-width: 5px; + transform-origin: 116px 42px; + animation: draw-hint-tap 2.4s ease-in-out infinite; + } + + @include on-small-screen { + &.draw-hint { + top: calc(0.75rem + env(safe-area-inset-top)); + gap: 10px; + min-height: 58px; + max-width: min(92vw, 340px); + padding: 9px 12px 9px 10px; + font-size: 16px; + } + + .draw-hint-mark { + width: 96px; + height: 54px; + flex-basis: 96px; + } + } +} + +@keyframes draw-hint-stroke { + 0%, + 18% { + stroke-dashoffset: 154; + } + + 58%, + 100% { + stroke-dashoffset: 0; + } +} + +@keyframes draw-hint-tap { + 0%, + 16% { + opacity: 0; + transform: scale(0.72); + } + + 36%, + 74% { + opacity: 1; + transform: scale(1); + } + + 100% { + opacity: 0.76; + transform: scale(0.88); + } +} diff --git a/src/style/_loading.scss b/src/style/_loading.scss new file mode 100644 index 0000000..925f915 --- /dev/null +++ b/src/style/_loading.scss @@ -0,0 +1,183 @@ +.loading-indicator { + --loading-gap: 22px; + + position: absolute; + top: 50%; + left: 50%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + z-index: 3; + width: min(86vw, 380px); + transform: translate(-50%, -50%); + opacity: 0; + pointer-events: none; + transition: opacity var(--transition-time-long); + contain: layout; + + > .splash { + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; + pointer-events: auto; + opacity: 1; + visibility: visible; + transition: + opacity var(--transition-time), + visibility 0s linear 0s; + + &[data-visible='false'] { + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: + opacity var(--transition-time), + visibility 0s linear var(--transition-time); + } + + > .splash-title { + margin: 0; + color: rgb(255 255 255 / 96%); + font-size: clamp(28px, 6vw, 42px); + font-weight: 700; + line-height: 1.1; + text-align: center; + letter-spacing: 0.01em; + text-shadow: + 0 2px 18px rgb(0 0 0 / 60%), + 0 0 32px rgb(255 255 255 / 10%); + } + + > .splash-description { + margin: 0; + max-width: 28ch; + color: rgb(255 255 255 / 80%); + font-size: 15px; + font-weight: 400; + line-height: 1.45; + text-align: center; + text-shadow: 0 1px 12px rgb(0 0 0 / 60%); + } + + > .start-button { + margin-top: 8px; + padding: 14px 40px; + border: 1px solid rgb(255 255 255 / 38%); + border-radius: 999px; + background: rgb(255 255 255 / 8%); + color: rgb(255 255 255 / 96%); + font-size: 16px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + cursor: pointer; + backdrop-filter: blur(6px); + box-shadow: + 0 0 24px rgb(255 255 255 / 14%), + 0 1px 6px rgb(0 0 0 / 28%); + transition: + opacity var(--transition-time), + transform var(--transition-time), + background var(--transition-time); + + &[disabled] { + opacity: 0.5; + cursor: progress; + } + + &:not([disabled]):hover, + &:not([disabled]):focus-visible { + background: rgb(255 255 255 / 16%); + transform: scale(1.04); + outline: none; + } + + &:not([disabled]):active { + transform: scale(0.98); + } + } + } + + > .loading-bar { + position: absolute; + top: calc(100% + var(--loading-gap)); + left: 0; + right: 0; + display: flex; + flex-direction: column; + gap: 18px; + align-items: center; + width: 100%; + opacity: 0; + visibility: hidden; + pointer-events: none; + transition: + opacity var(--transition-time), + visibility 0s linear var(--transition-time); + + &[data-visible='true'] { + opacity: 1; + visibility: visible; + transition: + opacity var(--transition-time), + visibility 0s linear 0s; + } + + > .loading-status { + color: rgb(255 255 255 / 88%); + font-size: 16px; + font-weight: 400; + line-height: 1.25; + text-align: center; + text-shadow: 0 1px 12px rgb(0 0 0 / 60%); + letter-spacing: 0.01em; + min-height: 1.25em; + } + + > .loading-progress { + --loading-progress: 0%; + + position: relative; + width: 100%; + height: 3px; + overflow: hidden; + border-radius: 999px; + background: rgb(255 255 255 / 14%); + box-shadow: 0 1px 6px rgb(0 0 0 / 28%); + + &::before { + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: var(--loading-progress); + border-radius: inherit; + background: linear-gradient( + 90deg, + rgb(255 255 255 / 72%), + rgb(255 255 255 / 96%) + ); + box-shadow: 0 0 12px rgb(255 255 255 / 38%); + transition: width var(--transition-time-long) ease-out; + } + } + } +} + +html > body.is-loading { + .loading-indicator { + opacity: 1; + } + + .eraser-preview { + visibility: hidden; + } + + aside.control-dock { + opacity: 0; + visibility: hidden; + } +} diff --git a/src/style/_panels.scss b/src/style/_panels.scss new file mode 100644 index 0000000..28717bb --- /dev/null +++ b/src/style/_panels.scss @@ -0,0 +1,96 @@ +@use 'mixins' as *; + +html > body > aside.control-dock > .info-page { + width: min(calc(100vw - 1rem), 560px); + max-height: min(58vh, 520px); + max-height: min(58dvh, 520px); + margin: 0 auto 10px; + overflow-x: hidden; + overflow-y: auto; + border: 1px solid rgb(255 255 255 / 78%); + border-radius: 8px; + background: + linear-gradient(180deg, rgb(255 255 255 / 97%), rgb(243 247 239 / 96%)), + rgb(255 255 255); + color: rgb(24 30 27); + box-shadow: + 0 20px 54px rgb(0 0 0 / 38%), + 0 2px 12px rgb(0 0 0 / 22%); + backdrop-filter: blur(12px); + scrollbar-width: thin; + scrollbar-color: var(--main-color) transparent; + transition: + max-height var(--transition-time-long), + opacity var(--transition-time-long), + transform var(--transition-time-long), + margin-bottom var(--transition-time-long); + + &::-webkit-scrollbar-track, + &::-webkit-scrollbar { + background-color: transparent; + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background-color: var(--main-color); + border-radius: 8px; + } + + &:focus-visible { + outline: 2px solid white; + outline-offset: 3px; + } + + > section { + display: flex; + flex-direction: column; + gap: 0.85rem; + padding: var(--normal-margin); + + h1 { + margin-bottom: 0; + color: rgb(16 24 20); + font-size: 2rem; + line-height: 1.1; + } + + p { + max-width: 54ch; + margin-bottom: 0; + color: rgb(42 48 45); + font-size: 1.1rem; + line-height: 1.65; + hyphens: auto; + } + + a { + color: rgb(0 84 120); + font-weight: 400; + + &:focus-visible { + outline: 2px solid currentColor; + outline-offset: 3px; + } + } + } + + &.hidden { + max-height: 0; + margin-bottom: 0; + border-color: transparent; + opacity: 0; + pointer-events: none; + box-shadow: none; + transform: translateY(8px); + visibility: hidden; + } + + @include on-small-screen { + max-height: min(54vh, 500px); + max-height: min(54dvh, 500px); + + > section { + padding: var(--small-margin); + } + } +} diff --git a/src/style/_toolbar.scss b/src/style/_toolbar.scss new file mode 100644 index 0000000..ef7ca8c --- /dev/null +++ b/src/style/_toolbar.scss @@ -0,0 +1,4 @@ +@use 'toolbar/layout'; +@use 'toolbar/buttons'; +@use 'toolbar/garden-controls'; +@use 'toolbar/responsive'; diff --git a/src/style/common.scss b/src/style/common.scss index 8954439..23c82aa 100644 --- a/src/style/common.scss +++ b/src/style/common.scss @@ -1,6 +1,5 @@ @use 'vars'; @use 'fonts'; -@use 'mixins' as *; *, *::before, @@ -9,41 +8,34 @@ padding: 0; box-sizing: border-box; - @media (prefers-reduced-motion) { + @media (prefers-reduced-motion: reduce) { transition: none !important; animation: none !important; } } -h1, -h2, -h3, -h4, -h5, -h6 { - font-family: 'Comfortaa', sans-serif; - margin-bottom: var(--small-margin); -} - -p { - font-family: 'Open Sans', sans-serif; -} - html { height: 100%; + touch-action: manipulation; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; } -.large-button { - border: none; - background-color: var(--accent-color); - cursor: pointer; - border-radius: var(--border-radius); - padding: calc(var(--small-margin) / 2) var(--small-margin); - margin: var(--small-margin) auto; - align-self: flex-end; - @include main-font(); - color: white; +body { + font-family: 'Open Sans', sans-serif; + touch-action: manipulation; +} + +.visually-hidden { + position: absolute !important; + width: 1px !important; + height: 1px !important; + margin: -1px !important; + padding: 0 !important; + overflow: hidden !important; + clip: rect(0 0 0 0) !important; + clip-path: inset(50%) !important; + white-space: nowrap !important; + border: 0 !important; } diff --git a/src/style/fonts.scss b/src/style/fonts.scss index a00d604..a4f4b3c 100644 --- a/src/style/fonts.scss +++ b/src/style/fonts.scss @@ -1,25 +1,8 @@ -/* comfortaa-regular - latin */ -@font-face { - font-family: 'Comfortaa'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: - local(''), - url('../../assets/fonts/comfortaa-v40-latin-regular.woff2') format('woff2'), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url('../../assets/fonts/comfortaa-v40-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - /* open-sans-regular - latin */ @font-face { font-family: 'Open Sans'; font-style: normal; font-weight: 400; font-display: swap; - src: - local(''), - url('../../assets/fonts/open-sans-v34-latin-regular.woff2') format('woff2'), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url('../../assets/fonts/open-sans-v34-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ + src: url('../../assets/fonts/open-sans-v34-latin-regular.woff2') format('woff2'); } diff --git a/src/style/mixins.scss b/src/style/mixins.scss index 4ed95f5..9197605 100644 --- a/src/style/mixins.scss +++ b/src/style/mixins.scss @@ -1,6 +1,3 @@ -@use 'sass:math'; -@use 'sass:color'; - $breakpoint-width: 600px !default; @mixin on-small-screen() { @@ -9,131 +6,8 @@ $breakpoint-width: 600px !default; } } -@mixin on-large-screen() { - @media (min-width: $breakpoint-width) { +@mixin on-mobile-input() { + @media (max-width: ($breakpoint-width - 1px)), (hover: none) and (pointer: coarse) { @content; } } - -@mixin title-fragment-link() { - position: relative; - - &:before { - content: '#'; - position: absolute; - left: -0.5ch; - top: 50%; - opacity: 0; - transform: translateX(-100%) translateY(-50%); - transition: opacity var(--transition-time); - } - - &:hover:before { - opacity: 0.5; - } -} - -@mixin center-children() { - display: flex; - align-items: center; - justify-content: center; -} - -@mixin absolute-center() { - position: absolute; - left: 50%; - top: 50%; - transform: translateX(-50%) translateY(-50%); -} - -@mixin blurred-background($color: transparent) { - background-color: color.adjust($color, $alpha: -0.66); - backdrop-filter: blur(var(--blur-radius)); -} - -@mixin square($size) { - width: $size; - height: $size; -} - -@mixin title-font() { - font: - 400 3rem 'Comfortaa', - sans-serif; - color: var(--normal-text-color); - line-height: 1; - - @include on-small-screen { - font-size: 3rem; - line-height: 1.1; - } -} - -@mixin sub-title-font() { - font: - 400 1.75rem 'Comfortaa', - sans-serif; - color: var(--normal-text-color); - hyphens: auto; -} - -@mixin main-font() { - font: - 400 1.1rem 'Open Sans', - sans-serif; - color: var(--normal-text-color); - line-height: 1.8; - hyphens: auto; -} - -@mixin special-text-font() { - font: - 400 1rem 'Open Sans', - sans-serif; - color: var(--special-text-color); - hyphens: auto; - font-style: italic; -} - -@mixin link { - $border-shift: 10px; - $line-width: 2px; - - @include special-text-font(); - cursor: pointer; - position: relative; - display: inline-block; - overflow: hidden; - - padding: 0 3px $line-width 0; - - &:before, - &:after { - content: ''; - display: block; - position: absolute; - bottom: 0; - } - - &:before { - width: calc(100% + #{$border-shift}); - border-bottom: $line-width dashed var(--accent-color); - transition: transform var(--transition-time); - } - - &:after { - width: 100%; - height: $line-width; - background: linear-gradient( - 90deg, - var(--card-color) 0, - transparent 4px, - transparent calc(100% - 4px), - var(--card-color) 100% - ); - } - - &:hover:before { - transform: translateX(-$border-shift); - } -} diff --git a/src/style/toolbar/_buttons.scss b/src/style/toolbar/_buttons.scss new file mode 100644 index 0000000..198ca47 --- /dev/null +++ b/src/style/toolbar/_buttons.scss @@ -0,0 +1,161 @@ +@use 'shared' as *; + +.buttons { + grid-area: buttons; + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: center; + justify-self: center; + gap: 4px; + width: fit-content; + max-width: 100%; + min-width: 0; + + > button, + > .audio-control > button { + position: relative; + width: 44px; + height: 44px; + flex: 1 1 44px; + max-width: 54px; + min-width: 0; + @include toolbar-control-surface(transparent, rgb(255 255 255 / 9%)); + + &::after { + content: ''; + position: absolute; + inset: 0; + z-index: 1; + width: 20px; + height: 20px; + margin: auto; + background-color: rgb(245 250 244 / 76%); + mask-position: center; + mask-repeat: no-repeat; + mask-size: contain; + transition: + background-color var(--transition-time), + transform var(--transition-time); + } + + &:hover::after { + transform: scale(1.08); + } + + &.active { + border-color: color-mix(in srgb, var(--accent-color) 55%, white 15%); + background: color-mix(in srgb, var(--accent-color) 30%, transparent); + } + + &.active::after { + background-color: white; + } + + @each $class, $icon in $toolbar-icons { + &.#{$class}::after { + mask-image: url('../../../assets/icons/#{$icon}.svg'); + } + } + + &.full-screen-toggle.active::after { + mask-image: url('../../../assets/icons/minimize.svg'); + } + + &.sound.muted::before { + content: ''; + position: absolute; + inset: 0; + z-index: 2; + width: 2px; + height: 28px; + margin: auto; + border-radius: 999px; + background: white; + transform: rotate(-45deg); + transform-origin: center; + } + + &.sound.muted::after { + background-color: rgb(255 255 255 / 46%); + } + } + + > .audio-control { + display: flex; + align-items: center; + width: 132px; + height: 44px; + flex: 2 1 132px; + max-width: 150px; + min-width: 0; + padding-right: 10px; + @include toolbar-control-surface(rgb(255 255 255 / 4%), rgb(255 255 255 / 7%)); + + > button { + flex: 0 0 42px; + min-width: 42px; + border-color: transparent; + + &:focus-visible { + outline-offset: -4px; + } + } + + > .volume-control { + --range-progress: var(--volume-progress, 42%); + --range-track-height: 4px; + --range-fill: color-mix(in srgb, var(--accent-color) 62%, white 8%); + --range-empty: rgb(255 255 255 / 18%); + --range-track-shadow: + inset 0 1px 1px rgb(0 0 0 / 24%), 0 1px 0 rgb(255 255 255 / 8%); + --range-thumb-width: 12px; + --range-thumb-height: 12px; + --range-thumb-border: 2px solid rgb(13 18 24); + --range-thumb-radius: 50%; + --range-thumb-background: rgb(245 250 244); + --range-thumb-shadow: 0 0 0 1px rgb(255 255 255 / 46%), 0 3px 8px rgb(0 0 0 / 28%); + --range-thumb-hover-shadow: + 0 0 0 1px rgb(255 255 255 / 56%), + 0 0 0 5px color-mix(in srgb, var(--accent-color) 25%, transparent), + 0 4px 10px rgb(0 0 0 / 34%); + --range-thumb-hover-transform: scale(1.08); + --range-focus-outline-offset: -4px; + + position: relative; + display: grid; + align-items: center; + height: 44px; + flex: 1 1 auto; + min-width: 0; + padding-left: 3px; + cursor: ew-resize; + opacity: 0.96; + transition: opacity var(--transition-time); + + &.muted { + opacity: 0.56; + } + } + + > .volume-control input[type='range'] { + @include toolbar-range-input(); + } + } + + > .export-status { + flex: 0 1 140px; + min-height: 20px; + max-width: 140px; + overflow: hidden; + color: rgb(255 255 255 / 82%); + font-size: 13px; + line-height: 1.2; + text-overflow: ellipsis; + white-space: nowrap; + + &:empty { + display: none; + } + } +} diff --git a/src/style/toolbar/_garden-controls.scss b/src/style/toolbar/_garden-controls.scss new file mode 100644 index 0000000..4dca516 --- /dev/null +++ b/src/style/toolbar/_garden-controls.scss @@ -0,0 +1,148 @@ +@use 'shared' as *; + +.garden-controls { + grid-area: swatches; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + min-width: 0; + padding: 0 4px; + + > .swatches { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + min-height: 58px; + padding: 6px 10px; + + > .color-swatch { + position: relative; + width: 44px; + height: 44px; + border: 2px solid rgb(255 255 255 / 54%); + border-radius: 50%; + box-shadow: + inset 0 0 0 1px rgb(0 0 0 / 16%), + 0 3px 10px rgb(0 0 0 / 22%); + + &:hover { + transform: translateY(-2px); + } + + &.active { + outline: 2px solid rgb(255 255 255 / 96%); + outline-offset: 3px; + box-shadow: + inset 0 0 0 1px rgb(0 0 0 / 14%), + 0 0 0 7px color-mix(in srgb, var(--accent-color) 52%, transparent), + 0 7px 18px rgb(0 0 0 / 26%); + } + } + + > .eraser-size-control, + > .mirror-segment-control { + --control-thumb-hover-transform: scale(1.03); + --control-thumb-radius: 50%; + --control-thumb-transform: none; + --range-progress: var(--control-progress); + --range-track-height: 7px; + --range-fill: rgb(var(--control-rgb) / 72%); + --range-empty: rgb(255 255 255 / 24%); + --range-track-shadow: inset 0 1px 2px rgb(0 0 0 / 24%); + --range-thumb-width: var(--control-thumb-width); + --range-thumb-height: var(--control-thumb-height); + --range-thumb-border: 2px solid rgb(255 255 255 / 92%); + --range-thumb-radius: var(--control-thumb-radius); + --range-thumb-background: var(--control-thumb-background); + --range-thumb-shadow: + inset 0 1px 2px rgb(255 255 255 / 22%), 0 4px 12px rgb(0 0 0 / 30%); + --range-thumb-hover-shadow: + inset 0 1px 2px rgb(255 255 255 / 22%), 0 0 0 4px rgb(var(--control-rgb) / 22%), + 0 5px 14px rgb(0 0 0 / 34%); + --range-thumb-hover-transform: var(--control-thumb-hover-transform); + --range-thumb-transform: var(--control-thumb-transform); + --range-thumb-transition: + box-shadow var(--transition-time), height var(--transition-time), + margin-top var(--transition-time), transform var(--transition-time), + width var(--transition-time); + + position: relative; + display: grid; + align-items: center; + width: 184px; + height: 46px; + flex: 0 0 184px; + padding: 0 12px; + overflow: hidden; + border: 1px solid rgb(255 255 255 / 14%); + border-radius: 8px; + background: linear-gradient(180deg, rgb(255 255 255 / 9%), rgb(255 255 255 / 4%)); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 6%), + 0 3px 10px rgb(0 0 0 / 18%); + cursor: ew-resize; + transition: + border-color var(--transition-time), + background-color var(--transition-time), + box-shadow var(--transition-time), + transform var(--transition-time); + + &:hover { + border-color: rgb(255 255 255 / 24%); + transform: translateY(-2px); + } + + &.active { + border-color: rgb(var(--control-rgb) / 72%); + background-color: rgb(var(--control-rgb) / 11%); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 10%), + 0 0 0 5px rgb(var(--control-rgb) / 28%), + 0 6px 15px rgb(0 0 0 / 22%); + } + + input[type='range'] { + @include toolbar-range-input(); + } + } + + > .eraser-size-control { + --control-progress: var(--eraser-progress, 33%); + --control-rgb: 255 140 117; + --control-thumb-background: + linear-gradient( + 110deg, + transparent 0 12%, + rgb(255 255 255 / 44%) 13% 20%, + transparent 21% 100% + ), + linear-gradient( + 90deg, + #ff8fa3 0 52%, + rgb(54 46 51 / 78%) 53% 56%, + #f5eee5 57% 100% + ); + --control-thumb-height: calc(21px * var(--eraser-control-scale, 1)); + --control-thumb-hover-transform: rotate(-10deg) scale(1.03); + --control-thumb-radius: calc(6px * var(--eraser-control-scale, 1)); + --control-thumb-transform: rotate(-10deg); + --control-thumb-width: calc(34px * var(--eraser-control-scale, 1)); + } + + > .mirror-segment-control { + --control-progress: var(--mirror-progress, 0%); + --control-rgb: 148 233 203; + --control-thumb-background: + radial-gradient(circle, white 0 3px, rgb(9 20 18 / 78%) 3.5px 8px), + repeating-conic-gradient( + from -90deg, + rgb(218 255 241) 0 8deg, + rgb(8 22 19 / 94%) 8deg var(--mirror-angle, 360deg) + ); + --control-thumb-height: 44px; + --control-thumb-width: 44px; + } + } +} diff --git a/src/style/toolbar/_layout.scss b/src/style/toolbar/_layout.scss new file mode 100644 index 0000000..f2c8930 --- /dev/null +++ b/src/style/toolbar/_layout.scss @@ -0,0 +1,173 @@ +@use 'shared' as *; + +.toolbar-row { + --toolbar-background-opacity: 0%; + --toolbar-background-strength: 0; + --toolbar-divider-space: clamp(6px, 1.8vw, 14px); + --toolbar-top-max-width: 594px; + --vibe-button-hit-size: 64px; + + display: grid; + grid-template-areas: + 'previous controls next' + 'previous divider next' + 'previous buttons next'; + grid-template-columns: + var(--vibe-button-hit-size) + minmax(0, var(--toolbar-top-max-width)) + var(--vibe-button-hit-size); + align-items: stretch; + justify-content: center; + width: fit-content; + max-width: 100%; + margin: 0 auto; + padding-inline: clamp(8px, 1.4vw, 14px); + column-gap: 0; + row-gap: 0; + border-radius: 12px; + color: rgb(245 250 244 / 92%); + background-color: rgb(5 8 13 / var(--toolbar-background-opacity)); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / calc(var(--toolbar-background-strength) * 16%)), + inset 0 1px 0 rgb(255 255 255 / calc(var(--toolbar-background-strength) * 7%)), + 0 14px 34px rgb(0 0 0 / calc(var(--toolbar-background-strength) * 28%)); + backdrop-filter: blur(calc(var(--toolbar-background-strength) * 18px)) + brightness(calc(1 - var(--toolbar-background-strength) * 0.38)) + saturate(calc(1 - var(--toolbar-background-strength) * 0.18)); + font-size: 13px; + font-weight: 400; + line-height: 1; + transition: + backdrop-filter var(--transition-time-long), + background-color var(--transition-time-long), + box-shadow var(--transition-time-long); + + &::after { + content: ''; + grid-area: divider; + align-self: center; + justify-self: center; + width: min(100%, var(--toolbar-top-max-width)); + height: 1px; + margin-block: var(--toolbar-divider-space); + background: rgb(255 255 255 / 12%); + } + + button { + min-width: 44px; + min-height: 44px; + border: 0; + font: inherit; + cursor: pointer; + @include toolbar-button-transition(); + + &:disabled { + cursor: progress; + opacity: 0.58; + } + + &:focus-visible { + outline: 2px solid white; + outline-offset: 2px; + } + } + + > .toolbar-shell { + grid-area: controls; + display: grid; + grid-template-areas: 'swatches'; + grid-template-columns: minmax(0, 1fr); + align-items: center; + justify-content: center; + justify-self: center; + width: min(100%, var(--toolbar-top-max-width)); + min-width: 0; + padding: 8px 9px; + } + + > .vibe-button { + --vibe-button-surface-inset-block: 10px; + --vibe-button-surface-inset-inline: 8px; + --vibe-chevron-size: 22px; + --vibe-chevron-stroke: 4px; + + position: relative; + isolation: isolate; + display: grid; + place-items: center; + width: var(--vibe-button-hit-size); + height: auto; + min-height: 72px; + flex: 0 0 auto; + padding: 0; + border-radius: 0; + background: transparent; + color: rgb(255 255 255 / 88%); + font-size: 0; + line-height: 1; + + &::after { + content: ''; + position: absolute; + z-index: 0; + inset: var(--vibe-button-surface-inset-block) + var(--vibe-button-surface-inset-inline); + border-radius: 8px; + background: rgb(255 255 255 / calc(9% + var(--toolbar-background-strength) * 10%)); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 18%), + 0 8px 18px rgb(0 0 0 / calc(var(--toolbar-background-strength) * 22%)); + transition: + background var(--transition-time), + box-shadow var(--transition-time), + opacity var(--transition-time); + } + + &::before { + content: ''; + position: absolute; + z-index: 1; + top: 50%; + left: 50%; + width: var(--vibe-chevron-size); + height: var(--vibe-chevron-size); + border-color: currentColor; + border-style: solid; + border-width: 0 0 var(--vibe-chevron-stroke) var(--vibe-chevron-stroke); + filter: drop-shadow(0 1px 3px rgb(0 0 0 / 70%)); + transform: translate(-35%, -50%) rotate(45deg); + } + + &.next-vibe::before { + border-width: var(--vibe-chevron-stroke) var(--vibe-chevron-stroke) 0 0; + transform: translate(-65%, -50%) rotate(45deg); + } + + &:hover { + color: white; + } + + &:hover::after { + background: color-mix(in srgb, var(--accent-color) 34%, rgb(255 255 255 / 18%)); + box-shadow: + inset 0 0 0 1px rgb(255 255 255 / 28%), + 0 10px 22px rgb(0 0 0 / calc(var(--toolbar-background-strength) * 30%)); + } + + &.previous-vibe:hover { + transform: translateX(-2px); + } + + &.next-vibe:hover { + transform: translateX(2px); + } + } + + > .previous-vibe { + grid-area: previous; + } + + > .next-vibe { + grid-area: next; + } +} diff --git a/src/style/toolbar/_responsive.scss b/src/style/toolbar/_responsive.scss new file mode 100644 index 0000000..2aeba6c --- /dev/null +++ b/src/style/toolbar/_responsive.scss @@ -0,0 +1,157 @@ +@use '../mixins' as *; + +.toolbar-row { + @include on-small-screen { + --toolbar-divider-space: 4px; + --toolbar-top-max-width: 329px; + --vibe-button-hit-size: 44px; + + grid-template-areas: + 'previous controls next' + '. divider .' + 'buttons buttons buttons'; + width: 100%; + padding-inline: 4px; + column-gap: 0; + row-gap: 0; + + > .vibe-button { + --vibe-button-surface-inset-block: 5px; + --vibe-button-surface-inset-inline: 3px; + --vibe-chevron-size: 17px; + --vibe-chevron-stroke: 3px; + + width: var(--vibe-button-hit-size); + min-height: 44px; + } + + > .toolbar-shell { + padding: 4px; + } + + > nav.buttons { + justify-self: stretch; + justify-content: space-between; + gap: clamp(1px, 0.55vw, 2px); + width: auto; + max-width: none; + margin-inline: -4px; + + > button { + width: auto; + height: 38px; + flex: 1 1 clamp(28px, 8vw, 38px); + max-width: 38px; + min-height: 38px; + + &::after { + width: 17px; + height: 17px; + } + } + + > .audio-control { + width: auto; + height: 38px; + flex: 2 1 clamp(58px, 18vw, 118px); + max-width: 118px; + padding-right: clamp(4px, 1.8vw, 9px); + + > button { + width: auto; + flex: 1 1 clamp(28px, 8vw, 38px); + min-width: 0; + } + + > .volume-control { + height: 38px; + } + } + + > .export-status { + flex-basis: 0; + max-width: 0; + text-align: center; + } + } + + > .toolbar-shell > .garden-controls { + padding: 2px 4px; + + > .swatches { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + justify-items: center; + justify-content: stretch; + width: 100%; + min-width: 0; + min-height: 48px; + flex: 1 1 100%; + padding: 3px 5px; + column-gap: 6px; + row-gap: 6px; + + > .color-swatch { + width: 38px; + height: 38px; + min-width: 38px; + min-height: 38px; + + grid-column: span 2; + } + + > .eraser-size-control, + > .mirror-segment-control { + justify-self: stretch; + width: 100%; + min-width: 0; + height: 38px; + padding: 0 7px; + } + + > .eraser-size-control { + grid-column: 1 / span 3; + } + + > .mirror-segment-control { + --control-thumb-height: 34px; + --control-thumb-width: 34px; + + grid-column: 4 / span 3; + } + } + } + } +} + +@media (prefers-reduced-motion: reduce) { + .toolbar-row { + > .vibe-button.previous-vibe:hover, + > .vibe-button.next-vibe:hover, + > .toolbar-shell > .garden-controls > .swatches > .color-swatch:hover, + > .toolbar-shell > .garden-controls > .swatches > .eraser-size-control:hover, + > .toolbar-shell > .garden-controls > .swatches > .mirror-segment-control:hover { + transform: none; + } + + > nav.buttons > button:hover::after, + > nav.buttons > .audio-control > button:hover::after { + transform: none; + } + + > nav.buttons > .audio-control > .volume-control input[type='range'] { + &::-webkit-slider-thumb:hover { + transform: none; + } + } + + > .toolbar-shell > .garden-controls > .swatches { + > .eraser-size-control input[type='range'], + > .mirror-segment-control input[type='range'] { + &::-webkit-slider-thumb:hover { + transform: var(--range-thumb-transform, none); + } + } + } + } +} diff --git a/src/style/toolbar/_shared.scss b/src/style/toolbar/_shared.scss new file mode 100644 index 0000000..ed477f2 --- /dev/null +++ b/src/style/toolbar/_shared.scss @@ -0,0 +1,104 @@ +$toolbar-icons: ( + info: 'info', + full-screen-toggle: 'maximize', + settings: 'settings', + sound: 'sound', + export-4k: 'download', + restart: 'restart', +); + +@mixin toolbar-button-transition() { + transition: + background-color var(--transition-time), + border-color var(--transition-time), + color var(--transition-time), + box-shadow var(--transition-time), + opacity var(--transition-time), + transform var(--transition-time); +} + +@mixin toolbar-control-surface($background, $hover-background) { + border: 1px solid transparent; + border-radius: 8px; + background: $background; + transition: + border-color var(--transition-time), + background-color var(--transition-time), + box-shadow var(--transition-time), + opacity var(--transition-time); + + &:hover { + border-color: rgb(255 255 255 / 10%); + background: $hover-background; + } +} + +@mixin toolbar-range-track() { + height: var(--range-track-height); + border: var(--range-track-border, 0); + border-radius: 999px; + background: linear-gradient( + 90deg, + var(--range-fill) 0 var(--range-progress), + var(--range-empty) var(--range-progress) 100% + ); + box-shadow: var(--range-track-shadow); + cursor: ew-resize; +} + +@mixin toolbar-range-thumb() { + width: var(--range-thumb-width); + height: var(--range-thumb-height); + border: var(--range-thumb-border); + border-radius: var(--range-thumb-radius); + background: var(--range-thumb-background); + box-shadow: var(--range-thumb-shadow); + cursor: ew-resize; + transform: var(--range-thumb-transform, none); +} + +@mixin toolbar-range-input() { + position: relative; + z-index: 1; + width: 100%; + height: 100%; + appearance: none; + background: transparent; + cursor: ew-resize; + outline: none; + touch-action: pan-y; + + &:focus-visible { + border-radius: 8px; + outline: 2px solid white; + outline-offset: var(--range-focus-outline-offset, 2px); + } + + &::-webkit-slider-runnable-track { + @include toolbar-range-track(); + } + + &::-webkit-slider-thumb { + @include toolbar-range-thumb(); + margin-top: calc((var(--range-track-height) - var(--range-thumb-height)) / 2); + appearance: none; + transition: var( + --range-thumb-transition, + box-shadow var(--transition-time), + transform var(--transition-time) + ); + } + + &::-webkit-slider-thumb:hover { + box-shadow: var(--range-thumb-hover-shadow, var(--range-thumb-shadow)); + transform: var(--range-thumb-hover-transform, var(--range-thumb-transform, none)); + } + + &::-moz-range-track { + @include toolbar-range-track(); + } + + &::-moz-range-thumb { + @include toolbar-range-thumb(); + } +} diff --git a/src/style/vars.scss b/src/style/vars.scss index aa832ca..319d82e 100644 --- a/src/style/vars.scss +++ b/src/style/vars.scss @@ -1,33 +1,8 @@ -@use 'mixins' as *; - :root { --transition-time: 200ms; --transition-time-long: 350ms; - --line-width: 4px; - --line-height: 1.125rem; - --accent-color: rgb(6.39851188659668, 70.28645324707031, 102.23043060302734); - --very-light-text-color: #ffffff; + --accent-color: rgb(255 93 162); --main-color: #aaa; - --normal-text-color: #31343f; - --blurred-card-color: transparent; - --blur-radius: 12px; - --special-text-color: var(--accent-color); - --border-radius: 0.6rem; - - --large-margin: 4.6rem; --normal-margin: 2rem; --small-margin: 1rem; - --shadow: 0 0 5px 2px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.2); - --icon-size: 2.5rem; - --large-icon-size: 3.75rem; - --body-width: min(80%, 60rem); -} - -@include on-small-screen { - :root { - --body-width: 90%; - --large-margin: 2.8rem; - --normal-margin: 2rem; - --icon-size: 2rem; - } }