diff --git a/public/assets/app.css b/public/assets/app.css index 3042dfa..b0d66d6 100644 --- a/public/assets/app.css +++ b/public/assets/app.css @@ -289,76 +289,47 @@ button, input, select { .rack-grid { position: relative; border-radius: 28px; - border: 1px solid rgba(105, 108, 115, 0.22); + border: 1px solid rgba(105, 108, 115, 0.12); background: - linear-gradient(180deg, rgba(255, 255, 255, 0.84), rgba(228, 229, 232, 0.86)), - linear-gradient(90deg, rgba(144, 148, 156, 0.06), rgba(144, 148, 156, 0)); - padding: 28px 40px 28px 74px; + radial-gradient(circle at top left, rgba(255, 255, 255, 0.07), transparent 20%), + linear-gradient(180deg, #26272b, #202126); + padding: 16px; overflow: hidden; box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.65), - inset 0 -18px 24px rgba(134, 137, 145, 0.12), - 0 24px 40px rgba(92, 84, 73, 0.12); -} - -.rack-grid { - outline: 18px solid var(--rack-frame-dark); - outline-offset: -18px; -} - -.rack-grid::before, -.rack-grid::after { - content: ""; - position: absolute; - top: 20px; - bottom: 20px; - width: 16px; - border-radius: 6px; - background: - radial-gradient(circle at center 8px, rgba(116, 120, 128, 0.48) 0 2px, transparent 2.5px) center top / 100% 18px repeat-y, - linear-gradient(180deg, var(--rack-frame-light), var(--rack-rail)); - box-shadow: - inset 0 0 0 1px rgba(255, 255, 255, 0.45), - inset 0 -10px 10px rgba(79, 82, 90, 0.16); -} - -.rack-grid::before { - left: 26px; -} - -.rack-grid::after { - right: 26px; + inset 0 1px 0 rgba(255, 255, 255, 0.08), + 0 20px 40px rgba(20, 18, 16, 0.18); } .rack-grid__bay { position: relative; - width: var(--rack-inner-width); + width: min(100%, 1180px); margin: 0 auto; - padding: 18px 0 14px; - background: - linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 13%, transparent 87%, rgba(0, 0, 0, 0.48)), - linear-gradient(135deg, rgba(255, 255, 255, 0.05), transparent 30%); - border-radius: 8px; + aspect-ratio: 3 / 2; + background-image: + linear-gradient(180deg, color-mix(in srgb, var(--rack-frame) 38%, transparent), color-mix(in srgb, var(--rack-frame) 38%, transparent)), + url("images/rack-template.png"); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + border-radius: 18px; box-shadow: - inset 0 0 0 2px rgba(0, 0, 0, 0.35), - inset 0 18px 32px rgba(0, 0, 0, 0.3), - inset 0 -18px 32px rgba(0, 0, 0, 0.24); + 0 18px 34px rgba(7, 8, 10, 0.32), + inset 0 0 0 1px rgba(255, 255, 255, 0.04); + isolation: isolate; } .rack-grid__guides { position: relative; width: 100%; - background: linear-gradient(180deg, rgba(20, 22, 28, 0.92), rgba(7, 8, 11, 0.98)); - border-left: 4px solid rgba(0, 0, 0, 0.4); - border-right: 4px solid rgba(0, 0, 0, 0.4); + height: 100%; + background: transparent; } .rack-slot { position: relative; - height: var(--rack-unit-height); - border-top: 1px solid rgba(126, 131, 140, 0.14); - background: - linear-gradient(180deg, rgba(255, 255, 255, 0.52), rgba(221, 224, 230, 0.42)); + height: calc(100% / var(--rack-total-u)); + border-top: 0; + background: transparent; } .rack-slot:first-child { @@ -372,50 +343,51 @@ button, input, select { .rack-slot__label { position: absolute; - left: -52px; - top: 8px; - font-size: 0.76rem; - color: rgba(76, 78, 84, 0.82); + left: 5.7%; + top: 39%; + font-size: 0.78rem; + color: rgba(239, 241, 245, 0.92); + text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65); } .rack-slot__label--right { left: auto; - right: -42px; + right: 5.7%; } .rack-items-layer { position: absolute; - inset: 18px 0 14px; - width: var(--rack-inner-width); + inset: 13.9% 17.4% 16.8% 17.4%; + z-index: 2; } .rack-insertion-layer { position: absolute; - inset: 18px 0 14px; - width: var(--rack-inner-width); - pointer-events: none; + inset: 13.9% 17.4% 16.8% 17.4%; + pointer-events: auto; + z-index: 3; } .rack-grid__header-badge { position: absolute; - top: 16px; - z-index: 4; + top: 1.7%; + z-index: 6; padding: 14px 18px; - border-radius: 14px; + border-radius: 16px; background: rgba(17, 19, 24, 0.84); color: #f6f7f9; - font-size: 1rem; + font-size: 1.05rem; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12), 0 10px 20px rgba(20, 22, 28, 0.18); } .rack-grid__header-badge--left { - left: 16px; + left: 1.8%; } .rack-grid__header-badge--right { - right: 16px; + right: 1.8%; } .rack-insert-zone { @@ -427,6 +399,7 @@ button, input, select { background: transparent; pointer-events: auto; cursor: pointer; + z-index: 3; } .rack-insert-zone.is-disabled { @@ -435,7 +408,7 @@ button, input, select { .rack-insert-zone__ear { width: 28px; - height: calc(100% - 2px); + height: calc(100% - 4px); border-radius: 10px; background: rgba(83, 156, 243, 0.26); border: 1px solid rgba(116, 184, 255, 0.5); @@ -477,6 +450,7 @@ button, input, select { background: linear-gradient(180deg, rgba(35, 92, 154, 0.34), rgba(23, 52, 84, 0.42)); box-shadow: inset 0 0 0 1px rgba(120, 182, 247, 0.24); font-size: 1rem; + transition: background 120ms ease, box-shadow 120ms ease, transform 120ms ease; } .rack-insert-zone__icon { @@ -489,6 +463,13 @@ button, input, select { background-color: rgba(72, 151, 228, 0.34); } +.rack-insert-zone:hover .rack-insert-zone__body { + transform: scaleY(1.02); + box-shadow: + inset 0 0 0 1px rgba(120, 182, 247, 0.34), + 0 0 0 1px rgba(120, 182, 247, 0.18); +} + .rack-insert-zone.is-disabled .rack-insert-zone__body, .rack-insert-zone.is-disabled .rack-insert-zone__ear { opacity: 0.28; @@ -500,12 +481,12 @@ button, input, select { padding: 0; user-select: none; overflow: hidden; - border-radius: 10px; - border: 1px solid rgba(122, 127, 137, 0.35); - background: linear-gradient(180deg, #fcfcfd, #e1e5eb); + border-radius: 8px; + border: 1px solid rgba(34, 38, 44, 0.55); + background: linear-gradient(180deg, rgba(237, 241, 246, 0.96), rgba(205, 213, 222, 0.96)); box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.76), - 0 10px 18px rgba(80, 84, 93, 0.18); + inset 0 1px 0 rgba(255, 255, 255, 0.9), + 0 10px 18px rgba(5, 6, 7, 0.28); touch-action: none; cursor: grab; } @@ -548,16 +529,32 @@ button, input, select { color: #17191c; } -.rack-item__actions { - display: flex; - flex-wrap: wrap; - gap: 8px; +.rack-item__drag-hint { + align-self: start; + padding: 5px 8px; + border-radius: 999px; + background: rgba(19, 23, 28, 0.78); + color: rgba(245, 247, 250, 0.95); + font-size: 0.72rem; + letter-spacing: 0.04em; } -.rack-item__actions button { - padding: 8px 10px; - font-size: 0.84rem; - background: rgba(181, 93, 45, 0.92); +.rack-item__remove { + position: absolute; + top: 8px; + right: 8px; + width: 28px; + height: 28px; + display: inline-flex; + align-items: center; + justify-content: center; + border: 0; + border-radius: 999px; + background: rgba(16, 18, 23, 0.78); + color: #fff; + font-size: 1rem; + line-height: 1; + cursor: pointer; } .subpanel { diff --git a/public/assets/app.js b/public/assets/app.js index 1ccf487..fb0f6e8 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -226,6 +226,7 @@ function renderRack() { } ui.rackGrid.style.setProperty("--rack-unit-height", `${RACK_UNIT_PX}px`); + ui.rackGrid.style.setProperty("--rack-total-u", String(rack.totalU)); applyRackColorTheme(ui.rackGrid, state.rackColor); const slots = []; @@ -238,26 +239,25 @@ function renderRack() { `); } - const insertionZones = renderInsertionZones(rack); - ui.rackGrid.innerHTML = `