From b2dcff9cb671e8844999e5a57afc3d0b8d780ae8 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Fri, 15 May 2026 23:08:24 +0200 Subject: [PATCH] yssadasd --- public/assets/app.css | 245 +++++++++++++++++++++++++++++++++++++++--- public/assets/app.js | 110 ++++++++++++++++--- 2 files changed, 329 insertions(+), 26 deletions(-) diff --git a/public/assets/app.css b/public/assets/app.css index 86dccd5..78b0856 100644 --- a/public/assets/app.css +++ b/public/assets/app.css @@ -194,6 +194,12 @@ button, input, select { gap: 10px; } +.component-card__preview { + padding: 10px; + border-radius: 14px; + background: linear-gradient(180deg, rgba(44, 47, 53, 0.08), rgba(18, 19, 23, 0.02)); +} + .component-card__header { display: flex; justify-content: space-between; @@ -276,12 +282,16 @@ button, input, select { .rack-grid { position: relative; border-radius: 28px; - border: 2px solid rgba(77, 50, 21, 0.4); + border: 2px solid rgba(42, 34, 24, 0.55); background: - linear-gradient(90deg, rgba(98, 71, 45, 0.18), rgba(255, 255, 255, 0) 14%, rgba(255, 255, 255, 0) 86%, rgba(98, 71, 45, 0.18)), - linear-gradient(180deg, rgba(255, 255, 255, 0.42), rgba(218, 197, 174, 0.36)); + linear-gradient(90deg, rgba(9, 11, 15, 0.88), rgba(20, 25, 31, 0.15) 14%, rgba(20, 25, 31, 0.15) 86%, rgba(9, 11, 15, 0.88)), + linear-gradient(180deg, #6e737b 0%, #3a3f48 12%, #15181d 22%, #0f1217 100%); padding: 24px 38px 24px 74px; overflow: hidden; + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.18), + inset 0 0 0 2px rgba(255, 255, 255, 0.04), + 0 24px 40px rgba(9, 11, 15, 0.22); } .rack-grid::before, @@ -290,9 +300,14 @@ button, input, select { position: absolute; top: 18px; bottom: 18px; - width: 12px; - border-radius: 999px; - background: rgba(92, 65, 37, 0.42); + width: 16px; + border-radius: 6px; + background: + radial-gradient(circle at center 8px, rgba(205, 214, 229, 0.75) 0 2px, transparent 2.5px) center top / 100% 18px repeat-y, + linear-gradient(180deg, #404550, #1a1d23); + box-shadow: + inset 0 0 0 1px rgba(255, 255, 255, 0.08), + inset 0 0 12px rgba(0, 0, 0, 0.4); } .rack-grid::before { @@ -306,7 +321,9 @@ button, input, select { .rack-slot { position: relative; height: var(--rack-unit-height); - border-top: 1px dashed rgba(89, 60, 31, 0.25); + border-top: 1px solid rgba(202, 212, 222, 0.06); + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(0, 0, 0, 0.06)); } .rack-slot:first-child { @@ -314,7 +331,8 @@ button, input, select { } .rack-slot.is-drop-target { - background: rgba(181, 93, 45, 0.11); + background: + linear-gradient(180deg, rgba(236, 129, 69, 0.16), rgba(236, 129, 69, 0.08)); } .rack-slot__label { @@ -322,7 +340,7 @@ button, input, select { left: -52px; top: 8px; font-size: 0.76rem; - color: var(--muted); + color: rgba(219, 225, 235, 0.84); } .rack-items-layer { @@ -334,11 +352,15 @@ button, input, select { position: absolute; left: 0; right: 0; - padding: 12px 12px 12px 14px; - display: grid; - gap: 8px; - border-left: 8px solid var(--accent); + padding: 0; user-select: none; + overflow: hidden; + border-radius: 10px; + border: 1px solid rgba(255, 255, 255, 0.08); + background: linear-gradient(180deg, #272c34, #11151b); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.08), + inset 0 -12px 18px rgba(0, 0, 0, 0.28); } .rack-item[data-standard="10_inch"] { @@ -356,13 +378,32 @@ button, input, select { align-items: start; } +.rack-item__overlay { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 8px 10px 8px 12px; + background: linear-gradient(90deg, rgba(11, 13, 16, 0.72), rgba(11, 13, 16, 0.08) 45%, rgba(11, 13, 16, 0.56)); +} + +.rack-item__face { + position: absolute; + inset: 0; +} + .rack-item__meta, .list-output, .notes { - color: var(--muted); + color: rgba(222, 227, 235, 0.76); font-size: 0.9rem; } +.rack-item__header strong { + color: #f3f5f8; +} + .rack-item__actions { display: flex; flex-wrap: wrap; @@ -372,6 +413,7 @@ button, input, select { .rack-item__actions button { padding: 8px 10px; font-size: 0.84rem; + background: rgba(181, 93, 45, 0.9); } .subpanel { @@ -438,6 +480,181 @@ button, input, select { border-radius: var(--radius-md); } +.device-face { + position: relative; + width: 100%; + height: 100%; + padding: 8px 12px; + overflow: hidden; +} + +.device-face--library { + min-height: 72px; + border-radius: 10px; +} + +.device-face--rack { + min-height: 100%; +} + +.device-face--switch, +.device-face--patch-panel, +.device-face--pdu, +.device-face--blank, +.device-face--generic { + background: linear-gradient(180deg, #4d535d 0%, #262c34 18%, #12161d 100%); +} + +.device-face--ups { + background: linear-gradient(180deg, #636973 0%, #2a3038 16%, #0f1319 100%); +} + +.device-face--shelf { + background: linear-gradient(180deg, #3e444c 0%, #171b21 100%); +} + +.device-silkscreen { + position: absolute; + left: 12px; + bottom: 8px; + font-size: 0.7rem; + letter-spacing: 0.12em; + text-transform: uppercase; + color: rgba(222, 227, 235, 0.58); +} + +.device-leds { + display: flex; + gap: 5px; + position: absolute; + top: 10px; + right: 12px; +} + +.device-leds span { + width: 7px; + height: 7px; + border-radius: 50%; + background: radial-gradient(circle at 35% 35%, #b8ff8e, #367f26 72%); + box-shadow: 0 0 8px rgba(114, 255, 86, 0.4); +} + +.device-ports, +.device-keystones, +.device-sockets { + display: grid; + gap: 4px; +} + +.device-ports { + position: absolute; + left: 16px; + right: 54px; + top: 18px; + grid-template-columns: repeat(12, minmax(0, 1fr)); +} + +.device-ports span, +.device-keystones span { + height: 11px; + border-radius: 2px; + background: linear-gradient(180deg, #181d23, #050709); + border: 1px solid rgba(183, 191, 207, 0.12); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06); +} + +.device-ports--8 { + grid-template-columns: repeat(8, minmax(0, 1fr)); +} + +.device-ports--12 { + grid-template-columns: repeat(12, minmax(0, 1fr)); +} + +.device-keystones { + position: absolute; + left: 16px; + right: 16px; + top: 18px; + grid-template-columns: repeat(12, minmax(0, 1fr)); +} + +.device-face--patch-panel .device-keystones span { + height: 13px; + background: linear-gradient(180deg, #0b0d10, #1b2128); +} + +.device-face--patch-panel .device-keystones span:nth-child(odd) { + border-color: rgba(239, 147, 78, 0.24); +} + +.device-uplink { + position: absolute; + top: 16px; + right: 16px; + width: 22px; + height: 16px; + border-radius: 4px; + border: 1px solid rgba(188, 197, 214, 0.15); + background: linear-gradient(180deg, #11161c, #050709); +} + +.device-sockets { + position: absolute; + top: 14px; + left: 16px; + right: 44px; + grid-template-columns: repeat(8, minmax(0, 1fr)); + align-items: center; +} + +.device-sockets span { + width: 15px; + height: 15px; + border-radius: 50%; + background: + radial-gradient(circle at center, transparent 0 3px, #0f1216 3px 5px, transparent 5px), + linear-gradient(180deg, #aeb8c6, #57606e); + border: 1px solid rgba(229, 233, 240, 0.18); +} + +.device-display { + position: absolute; + left: 16px; + top: 14px; + width: 68px; + height: 30px; + border-radius: 8px; + background: + linear-gradient(180deg, rgba(46, 180, 156, 0.9), rgba(18, 97, 90, 0.92)), + linear-gradient(180deg, #0f151c, #080b0f); + box-shadow: + inset 0 0 0 1px rgba(255, 255, 255, 0.12), + 0 0 16px rgba(46, 180, 156, 0.22); +} + +.device-vents { + position: absolute; + top: 16px; + right: 18px; + width: 96px; + height: 22px; + background: + repeating-linear-gradient(90deg, rgba(222, 227, 235, 0.16) 0 3px, transparent 3px 7px); + opacity: 0.8; +} + +.device-shelf-top { + position: absolute; + left: 18px; + right: 18px; + top: 14px; + height: 18px; + border-radius: 4px 4px 12px 12px; + background: linear-gradient(180deg, #69707a, #262b33); + box-shadow: 0 5px 12px rgba(0, 0, 0, 0.28); +} + @media (max-width: 1280px) { .workspace { grid-template-columns: 1fr; diff --git a/public/assets/app.js b/public/assets/app.js index a809760..c4b0a52 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -139,7 +139,10 @@ function renderLibrary() { ui.componentLibrary.innerHTML = filtered .map( (component) => ` -
+
+
+ ${renderComponentFace(component, "library")} +
${escapeHtml(component.name)} @@ -235,23 +238,28 @@ function renderRack() { const top = (rack.totalU - (item.startU + component.heightU) + 1) * 38; const height = component.heightU * 38 - 2; const element = document.createElement("article"); - element.className = "rack-item"; + element.className = `rack-item rack-item--${component.category.replace(/_/g, "-")}`; element.dataset.standard = component.rackStandard; element.draggable = true; element.style.top = `${top}px`; element.style.height = `${height}px`; element.innerHTML = ` -
-
- ${escapeHtml(component.name)} -
${component.heightU}U · ${component.depthMm} mm · ${formatCurrency(component.priceNet, component.currency)}
-
- ${item.startU}U +
+ ${renderComponentFace(component, "rack")}
-
- - - +
+
+
+ ${escapeHtml(component.name)} +
${component.heightU}U · ${component.depthMm} mm · ${formatCurrency(component.priceNet, component.currency)}
+
+ ${item.startU}U +
+
+ + + +
`; @@ -634,6 +642,84 @@ function formatCurrency(value, currency) { }).format(value); } +function renderComponentFace(component, mode) { + const ports = renderPortStrip(component); + const leds = '
'; + const label = `
${escapeHtml(component.manufacturer || component.category)}
`; + const modeClass = mode === "rack" ? "device-face--rack" : "device-face--library"; + + switch (component.category) { + case "switch": + return ` +
+ ${label} + ${leds} + ${ports} + +
+ `; + case "patch_panel": + return ` +
+ ${label} + ${renderPatchPanel(component)} +
+ `; + case "pdu": + return ` +
+ ${label} +
${renderSocketStrip(component)}
+ ${leds} +
+ `; + case "ups": + return ` +
+
+
+ ${label} +
+ `; + case "shelf": + return ` +
+
+ ${label} +
+ `; + case "blank_panel": + return ` +
+ ${label} +
+ `; + default: + return ` +
+ ${label} +
+ `; + } +} + +function renderPortStrip(component) { + const totalPorts = component.name.includes("24") ? 24 : component.name.includes("12") ? 12 : 8; + const ports = Array.from({ length: totalPorts }, (_, index) => ``).join(""); + return `
${ports}
`; +} + +function renderPatchPanel(component) { + const totalPorts = component.name.includes("24") ? 24 : 12; + const ports = Array.from({ length: totalPorts }, (_, index) => ``).join(""); + return `
${ports}
`; +} + +function renderSocketStrip(component) { + const totalSockets = component.name.includes("8") ? 8 : 6; + return Array.from({ length: totalSockets }, () => "").join(""); +} + function escapeHtml(value) { return String(value) .replaceAll("&", "&")