This commit is contained in:
Andras Schmelczer 2026-05-21 07:43:10 +01:00
commit 6bc125be1c
104 changed files with 3084 additions and 2410 deletions

View file

@ -1,709 +1,4 @@
@use 'mixins' as *;
@mixin toolbar-track() {
height: 7px;
border-radius: 999px;
background: linear-gradient(
90deg,
rgb(var(--control-rgb) / 72%) 0 var(--control-progress),
rgb(255 255 255 / 24%) var(--control-progress) 100%
);
box-shadow: inset 0 1px 2px rgb(0 0 0 / 24%);
cursor: ew-resize;
}
@mixin toolbar-thumb() {
width: var(--thumb-width);
height: var(--thumb-height);
border: 2px solid rgb(255 255 255 / 92%);
border-radius: var(--thumb-radius);
background: var(--thumb-background);
box-shadow:
inset 0 1px 2px rgb(255 255 255 / 22%),
0 4px 12px rgb(0 0 0 / 30%);
cursor: ew-resize;
transform: var(--thumb-transform);
}
$toolbar-icons: (
info: 'info',
maximize-full-screen: 'maximize',
minimize-full-screen: 'minimize',
settings: 'settings',
sound: 'sound',
export-4k: 'download',
restart: 'restart',
);
html > body > aside.control-dock > .toolbar-row {
--toolbar-background-opacity: 0%;
--toolbar-background-strength: 0;
--toolbar-divider-space: clamp(6px, 1.8vw, 14px);
--toolbar-top-max-width: 594px;
display: grid;
grid-template-areas:
'previous controls next'
'previous divider next'
'previous buttons next';
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: stretch;
justify-content: center;
width: 100%;
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;
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);
&: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 {
position: relative;
display: grid;
place-items: center;
width: 52px;
height: auto;
min-height: 66px;
flex: 0 0 auto;
padding: 0;
border-radius: 0;
background: transparent;
color: rgb(255 255 255 / 70%);
font-size: 0;
line-height: 1;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 18px;
height: 18px;
border-color: currentColor;
border-style: solid;
border-width: 0 0 3px 3px;
transform: translate(-35%, -50%) rotate(45deg);
}
&.next-vibe::before {
border-width: 3px 3px 0 0;
transform: translate(-65%, -50%) rotate(45deg);
}
&:hover {
color: color-mix(in srgb, var(--accent-color) 70%, white);
}
&.previous-vibe:hover {
transform: translateX(-2px);
}
&.next-vibe:hover {
transform: translateX(2px);
}
}
> .previous-vibe {
grid-area: previous;
}
> .next-vibe {
grid-area: next;
}
> nav.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;
border: 1px solid transparent;
border-radius: 8px;
background: transparent;
&::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 {
border-color: rgb(255 255 255 / 10%);
background: rgb(255 255 255 / 9%);
}
&: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');
}
}
&.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;
border: 1px solid transparent;
border-radius: 8px;
background: rgb(255 255 255 / 4%);
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: rgb(255 255 255 / 7%);
}
> button {
flex: 0 0 42px;
min-width: 42px;
border-color: transparent;
&:focus-visible {
outline-offset: -4px;
}
}
> .volume-control {
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'] {
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: -4px;
}
&::-webkit-slider-runnable-track {
height: 4px;
border-radius: 999px;
background: linear-gradient(
90deg,
color-mix(in srgb, var(--accent-color) 62%, white 8%) 0
var(--volume-progress, 42%),
rgb(255 255 255 / 18%) var(--volume-progress, 42%) 100%
);
box-shadow:
inset 0 1px 1px rgb(0 0 0 / 24%),
0 1px 0 rgb(255 255 255 / 8%);
cursor: ew-resize;
}
&::-webkit-slider-thumb {
width: 12px;
height: 12px;
border: 2px solid rgb(13 18 24);
border-radius: 50%;
background: rgb(245 250 244);
box-shadow:
0 0 0 1px rgb(255 255 255 / 46%),
0 3px 8px rgb(0 0 0 / 28%);
margin-top: -4px;
appearance: none;
transition:
box-shadow var(--transition-time),
transform var(--transition-time);
}
&::-webkit-slider-thumb:hover {
box-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%);
transform: scale(1.08);
}
&::-moz-range-track {
height: 4px;
border: 0;
border-radius: 999px;
background: linear-gradient(
90deg,
color-mix(in srgb, var(--accent-color) 62%, white 8%) 0
var(--volume-progress, 42%),
rgb(255 255 255 / 18%) var(--volume-progress, 42%) 100%
);
box-shadow:
inset 0 1px 1px rgb(0 0 0 / 24%),
0 1px 0 rgb(255 255 255 / 8%);
}
&::-moz-range-thumb {
width: 12px;
height: 12px;
border: 2px solid rgb(13 18 24);
border-radius: 50%;
background: rgb(245 250 244);
box-shadow:
0 0 0 1px rgb(255 255 255 / 46%),
0 3px 8px rgb(0 0 0 / 28%);
cursor: ew-resize;
}
}
}
> .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;
}
}
}
> .toolbar-shell > .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 {
--thumb-hover-transform: scale(1.03);
--thumb-radius: 50%;
--thumb-transform: none;
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'] {
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: 2px;
}
&::-webkit-slider-runnable-track {
@include toolbar-track();
}
&::-webkit-slider-thumb {
@include toolbar-thumb();
margin-top: calc((7px - var(--thumb-height)) / 2);
appearance: none;
transition:
box-shadow var(--transition-time),
height var(--transition-time),
margin-top var(--transition-time),
transform var(--transition-time),
width var(--transition-time);
}
&::-webkit-slider-thumb:hover {
box-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%);
transform: var(--thumb-hover-transform);
}
&::-moz-range-track {
@include toolbar-track();
}
&::-moz-range-thumb {
@include toolbar-thumb();
}
}
}
> .eraser-size-control {
--control-progress: var(--eraser-progress, 33%);
--control-rgb: 255 140 117;
--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%
);
--thumb-height: calc(21px * var(--eraser-control-scale, 1));
--thumb-hover-transform: rotate(-10deg) scale(1.03);
--thumb-radius: calc(6px * var(--eraser-control-scale, 1));
--thumb-transform: rotate(-10deg);
--thumb-width: calc(34px * var(--eraser-control-scale, 1));
}
> .mirror-segment-control {
--control-progress: var(--mirror-progress, 0%);
--control-rgb: 148 233 203;
--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)
);
--thumb-height: 44px;
--thumb-width: 44px;
}
}
}
@include on-small-screen {
--toolbar-divider-space: 4px;
--toolbar-top-max-width: 329px;
grid-template-areas:
'previous controls next'
'. divider .'
'buttons buttons buttons';
width: 100%;
padding-inline: 4px;
column-gap: 0;
row-gap: 0;
> .vibe-button {
width: 36px;
min-height: 44px;
&::before {
width: 14px;
height: 14px;
}
}
> .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 {
--thumb-height: 34px;
--thumb-width: 34px;
grid-column: 4 / span 3;
}
}
}
}
}
}
@use 'toolbar/layout';
@use 'toolbar/buttons';
@use 'toolbar/garden-controls';
@use 'toolbar/responsive';