adasd
All checks were successful
Deploy / deploy (push) Successful in 17s

This commit is contained in:
2026-05-17 01:07:33 +02:00
parent 70e82cae7b
commit 16c19cd6ff
3 changed files with 183 additions and 161 deletions

View File

@@ -119,9 +119,8 @@ button, input, select {
.workspace { .workspace {
display: grid; display: grid;
grid-template-columns: minmax(320px, 420px) minmax(420px, 1fr) minmax(320px, 390px); grid-template-columns: 1fr;
gap: 24px; gap: 24px;
align-items: start;
} }
.panel { .panel {
@@ -140,12 +139,33 @@ button, input, select {
color: var(--muted); color: var(--muted);
} }
.panel--controls, .panel--dashboard {
.panel--sidebar {
display: grid; display: grid;
gap: 18px; gap: 18px;
} }
.dashboard-grid {
display: grid;
grid-template-columns: minmax(320px, 1.15fr) minmax(320px, 1fr);
gap: 18px;
}
.dashboard-block {
display: grid;
gap: 16px;
}
.dashboard-controls {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 14px;
align-items: end;
}
.dashboard-block--library {
padding-top: 8px;
}
.field { .field {
display: grid; display: grid;
gap: 8px; gap: 8px;
@@ -184,6 +204,11 @@ button, input, select {
padding-right: 4px; padding-right: 4px;
} }
.library--wide {
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
max-height: 420px;
}
.component-card, .component-card,
.rack-item, .rack-item,
.subpanel, .subpanel,
@@ -263,20 +288,14 @@ button, input, select {
.rack-stage { .rack-stage {
display: grid; display: grid;
gap: 18px; gap: 0;
} }
.rack-summary,
.stat-grid { .stat-grid {
display: grid; display: grid;
gap: 12px; gap: 12px;
} }
.rack-summary {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.summary-card,
.stat-card { .stat-card {
padding: 16px; padding: 16px;
border-radius: var(--radius-md); border-radius: var(--radius-md);
@@ -284,7 +303,6 @@ button, input, select {
border: 1px solid rgba(75, 57, 37, 0.12); border: 1px solid rgba(75, 57, 37, 0.12);
} }
.summary-card strong,
.stat-card strong { .stat-card strong {
display: block; display: block;
margin-top: 6px; margin-top: 6px;
@@ -297,7 +315,7 @@ button, input, select {
border: 1px solid rgba(105, 108, 115, 0.14); border: 1px solid rgba(105, 108, 115, 0.14);
background: background:
linear-gradient(180deg, rgba(255, 255, 255, 0.78), rgba(239, 232, 214, 0.88)); linear-gradient(180deg, rgba(255, 255, 255, 0.78), rgba(239, 232, 214, 0.88));
padding: 16px; padding: 6px;
overflow: hidden; overflow: hidden;
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.7),
@@ -306,9 +324,9 @@ button, input, select {
.rack-shell { .rack-shell {
position: relative; position: relative;
width: min(100%, 1180px); width: min(100%, 1380px);
margin: 0 auto; margin: 0 auto;
aspect-ratio: 3 / 2; aspect-ratio: 3.1 / 2;
border-radius: 28px; border-radius: 28px;
background: background:
linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(0, 0, 0, 0.16)), linear-gradient(180deg, rgba(255, 255, 255, 0.04), rgba(0, 0, 0, 0.16)),
@@ -330,34 +348,34 @@ button, input, select {
.rack-shell__frame--top, .rack-shell__frame--top,
.rack-shell__frame--bottom { .rack-shell__frame--bottom {
left: 9%; left: 5.1%;
right: 9%; right: 5.1%;
height: 8%; height: 4.8%;
border-radius: 14px; border-radius: 12px;
} }
.rack-shell__frame--top { .rack-shell__frame--top {
top: 6%; top: 3.6%;
} }
.rack-shell__frame--bottom { .rack-shell__frame--bottom {
bottom: 6%; bottom: 3.6%;
} }
.rack-shell__frame--left, .rack-shell__frame--left,
.rack-shell__frame--right { .rack-shell__frame--right {
top: 8%; top: 4.7%;
bottom: 8%; bottom: 4.7%;
width: 6.8%; width: 3.2%;
border-radius: 24px; border-radius: 18px;
} }
.rack-shell__frame--left { .rack-shell__frame--left {
left: 0.5%; left: 0.6%;
} }
.rack-shell__frame--right { .rack-shell__frame--right {
right: 0.5%; right: 0.6%;
} }
.rack-shell__screw { .rack-shell__screw {
@@ -395,17 +413,17 @@ button, input, select {
height: 58%; height: 58%;
} }
.rack-shell__screw--tl { top: 7.4%; left: 10.6%; } .rack-shell__screw--tl { top: 4.2%; left: 5.8%; }
.rack-shell__screw--tr { top: 7.4%; right: 10.6%; } .rack-shell__screw--tr { top: 4.2%; right: 5.8%; }
.rack-shell__screw--bl { bottom: 7.4%; left: 10.6%; } .rack-shell__screw--bl { bottom: 4.2%; left: 5.8%; }
.rack-shell__screw--br { bottom: 7.4%; right: 10.6%; } .rack-shell__screw--br { bottom: 4.2%; right: 5.8%; }
.rack-core { .rack-core {
position: absolute; position: absolute;
inset: 15% 12.8% 14% 12.8%; inset: 8.7% 6.2% 8.3% 6.2%;
display: grid; display: grid;
grid-template-columns: 10% 1fr 10%; grid-template-columns: 5.5% 1fr 5.5%;
gap: 0; gap: 0.8%;
z-index: 2; z-index: 2;
} }
@@ -442,11 +460,11 @@ button, input, select {
} }
.rack-rail__label--left { .rack-rail__label--left {
left: -2.1rem; left: -1.65rem;
} }
.rack-rail__label--right { .rack-rail__label--right {
right: -1.6rem; right: -1.35rem;
} }
.rack-rail__tick { .rack-rail__tick {
@@ -494,6 +512,7 @@ button, input, select {
.rack-bay { .rack-bay {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
border-radius: 4px;
background: background:
radial-gradient(circle at center, rgba(96, 99, 108, 0.22), transparent 48%), radial-gradient(circle at center, rgba(96, 99, 108, 0.22), transparent 48%),
linear-gradient(180deg, #181a1f, #2a2d34 36%, #22252c 68%, #17191d 100%); linear-gradient(180deg, #181a1f, #2a2d34 36%, #22252c 68%, #17191d 100%);
@@ -562,24 +581,24 @@ button, input, select {
.rack-grid__header-badge { .rack-grid__header-badge {
position: absolute; position: absolute;
top: 1.7%; top: 0.9%;
z-index: 6; z-index: 6;
padding: 14px 18px; padding: 10px 14px;
border-radius: 16px; border-radius: 16px;
background: rgba(17, 19, 24, 0.84); background: rgba(17, 19, 24, 0.84);
color: #f6f7f9; color: #f6f7f9;
font-size: 1.05rem; font-size: 0.98rem;
box-shadow: box-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.12), inset 0 0 0 1px rgba(255, 255, 255, 0.12),
0 10px 20px rgba(20, 22, 28, 0.18); 0 10px 20px rgba(20, 22, 28, 0.18);
} }
.rack-grid__header-badge--left { .rack-grid__header-badge--left {
left: 1.8%; left: 0.9%;
} }
.rack-grid__header-badge--right { .rack-grid__header-badge--right {
right: 1.8%; right: 0.9%;
} }
.rack-items-layer { .rack-items-layer {
@@ -693,12 +712,14 @@ button, input, select {
padding: 0; padding: 0;
user-select: none; user-select: none;
overflow: hidden; overflow: hidden;
border-radius: 8px; border-radius: 14px;
border: 1px solid rgba(32, 36, 42, 0.8); border: 1px solid rgba(30, 34, 40, 0.84);
background: linear-gradient(180deg, rgba(235, 239, 244, 0.98), rgba(191, 200, 211, 0.98)); background:
linear-gradient(180deg, rgba(248, 250, 252, 0.98), rgba(209, 215, 224, 0.98) 58%, rgba(187, 194, 204, 0.98));
box-shadow: box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.94), inset 0 1px 0 rgba(255, 255, 255, 0.96),
0 8px 14px rgba(5, 6, 7, 0.24); inset 0 -2px 0 rgba(0, 0, 0, 0.14),
0 12px 18px rgba(5, 6, 7, 0.28);
touch-action: none; touch-action: none;
cursor: grab; cursor: grab;
} }
@@ -721,15 +742,16 @@ button, input, select {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
padding: 6px 10px 6px 10px; padding: 8px 12px 8px 12px;
background: background:
linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0) 42%), linear-gradient(180deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0) 28%),
linear-gradient(90deg, rgba(255, 255, 255, 0.38), rgba(255, 255, 255, 0.06) 34%, rgba(255, 255, 255, 0.18)); linear-gradient(90deg, rgba(255, 255, 255, 0.26), rgba(255, 255, 255, 0.06) 32%, rgba(255, 255, 255, 0.16));
} }
.rack-item__face { .rack-item__face {
position: absolute; position: absolute;
inset: 0; inset: 0;
filter: drop-shadow(0 10px 10px rgba(0, 0, 0, 0.18));
} }
.rack-item__meta, .rack-item__meta,
@@ -745,7 +767,7 @@ button, input, select {
} }
.rack-item__drag-hint { .rack-item__drag-hint {
align-self: start; align-self: end;
padding: 5px 8px; padding: 5px 8px;
border-radius: 999px; border-radius: 999px;
background: rgba(19, 23, 28, 0.78); background: rgba(19, 23, 28, 0.78);
@@ -791,7 +813,7 @@ button, input, select {
} }
.stat-grid { .stat-grid {
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
} }
.field-row { .field-row {
@@ -1114,7 +1136,8 @@ button, input, select {
} }
@media (max-width: 1280px) { @media (max-width: 1280px) {
.workspace { .dashboard-grid,
.dashboard-controls {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
@@ -1128,15 +1151,14 @@ button, input, select {
padding: 18px; padding: 18px;
} }
.rack-summary,
.stat-grid, .stat-grid,
.field-row { .field-row,
.dashboard-controls {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.rack-grid { .rack-grid {
padding-left: 62px; padding: 8px;
padding-right: 26px;
} }
.rack-shell, .rack-shell,

View File

@@ -30,7 +30,6 @@ function cacheDom() {
ui.componentFilter = document.getElementById("component-filter"); ui.componentFilter = document.getElementById("component-filter");
ui.pluginInput = document.getElementById("plugin-input"); ui.pluginInput = document.getElementById("plugin-input");
ui.componentLibrary = document.getElementById("component-library"); ui.componentLibrary = document.getElementById("component-library");
ui.rackSummary = document.getElementById("rack-summary");
ui.rackGrid = document.getElementById("rack-grid"); ui.rackGrid = document.getElementById("rack-grid");
ui.projectStats = document.getElementById("project-stats"); ui.projectStats = document.getElementById("project-stats");
ui.bomOutput = document.getElementById("bom-output"); ui.bomOutput = document.getElementById("bom-output");
@@ -51,7 +50,7 @@ function bindEvents() {
ui.projectName.addEventListener("input", () => { ui.projectName.addEventListener("input", () => {
state.projectName = ui.projectName.value.trim() || "Neues Rack-Projekt"; state.projectName = ui.projectName.value.trim() || "Neues Rack-Projekt";
renderSummary(); renderStats();
}); });
ui.rackColor.addEventListener("input", () => { ui.rackColor.addEventListener("input", () => {
state.rackColor = ui.rackColor.value; state.rackColor = ui.rackColor.value;
@@ -89,7 +88,6 @@ async function loadBootstrap() {
} }
function renderAll() { function renderAll() {
renderSummary();
renderLibrary(); renderLibrary();
renderSelectionInfo(); renderSelectionInfo();
renderRack(); renderRack();
@@ -112,26 +110,7 @@ function renderTemplateOptions() {
} }
function renderSummary() { function renderSummary() {
const rack = getCurrentRackTemplate(); renderStats();
if (!rack) {
ui.rackSummary.innerHTML = "";
return;
}
ui.rackSummary.innerHTML = `
<div class="summary-card">
<span>Projekt</span>
<strong>${escapeHtml(state.projectName)}</strong>
</div>
<div class="summary-card">
<span>Rack-Standard</span>
<strong>${rack.rackStandard === "19_inch" ? "19 inch" : "10 inch"}</strong>
</div>
<div class="summary-card">
<span>Kapazitaet</span>
<strong>${rack.totalU}U / ${rack.usableDepthMm} mm</strong>
</div>
`;
} }
function renderLibrary() { function renderLibrary() {
@@ -384,6 +363,18 @@ function renderStats() {
}, 0); }, 0);
ui.projectStats.innerHTML = ` ui.projectStats.innerHTML = `
<div class="stat-card">
<span>Projekt</span>
<strong>${escapeHtml(state.projectName)}</strong>
</div>
<div class="stat-card">
<span>Rack</span>
<strong>${rack.rackStandard === "19_inch" ? '19"' : '10"'} · ${rack.totalU}U</strong>
</div>
<div class="stat-card">
<span>Tiefe</span>
<strong>${rack.usableDepthMm} mm</strong>
</div>
<div class="stat-card"> <div class="stat-card">
<span>Belegte U</span> <span>Belegte U</span>
<strong>${usedU} / ${rack.totalU}</strong> <strong>${usedU} / ${rack.totalU}</strong>

View File

@@ -42,12 +42,15 @@ $apiBase = $publicBase === '' ? '' : $publicBase;
</header> </header>
<main class="workspace"> <main class="workspace">
<section class="panel panel--controls"> <section class="panel panel--dashboard">
<div class="dashboard-grid">
<section class="dashboard-block dashboard-block--controls">
<div class="panel__heading"> <div class="panel__heading">
<h2>Projekt</h2> <h2>Projekt</h2>
<p>Rack-Vorlage, Bibliothek und Plugin-Import.</p> <p>Rack-Vorlage, Bibliothek und Plugin-Import.</p>
</div> </div>
<div class="dashboard-controls">
<label class="field"> <label class="field">
<span>Rack-Vorlage</span> <span>Rack-Vorlage</span>
<select id="rack-template-select"></select> <select id="rack-template-select"></select>
@@ -58,44 +61,29 @@ $apiBase = $publicBase === '' ? '' : $publicBase;
<input id="project-name" type="text" value="Neues Rack-Projekt"> <input id="project-name" type="text" value="Neues Rack-Projekt">
</label> </label>
<div class="field-row">
<label class="field"> <label class="field">
<span>Rack-Farbe</span> <span>Rack-Farbe</span>
<input id="rack-color" type="color" value="#50545c"> <input id="rack-color" type="color" value="#50545c">
</label> </label>
<label class="field">
<span>Komponenten filtern</span>
<input id="component-filter" type="search" placeholder="z. B. Switch, UPS, Patch Panel">
</label>
<label class="field">
<span>Plugin-Pack laden</span>
<input id="plugin-input" type="file" accept=".json,application/json">
</label>
<div class="field field--status"> <div class="field field--status">
<span>Einsteckmodus</span> <span>Einsteckmodus</span>
<div id="selected-component-info" class="selection-info">Kein Element ausgewaehlt</div> <div id="selected-component-info" class="selection-info">Kein Element ausgewaehlt</div>
</div> </div>
</div> </div>
<div class="library-toolbar">
<label class="field">
<span>Komponenten filtern</span>
<input id="component-filter" type="search" placeholder="z. B. Switch, UPS, Patch Panel">
</label>
<label class="field">
<span>Plugin-Pack laden</span>
<input id="plugin-input" type="file" accept=".json,application/json">
</label>
</div>
<div class="library" id="component-library"></div>
</section> </section>
<section class="panel panel--editor"> <section class="dashboard-block dashboard-block--stats">
<div class="panel__heading">
<h2>Rack-Editor</h2>
<p>Komponenten koennen per Drag-and-Drop verschoben werden. Jede Position referenziert eine U-Einheit.</p>
</div>
<div class="rack-stage">
<div class="rack-summary" id="rack-summary"></div>
<div class="rack-grid" id="rack-grid" aria-live="polite"></div>
</div>
</section>
<aside class="panel panel--sidebar">
<div class="panel__heading"> <div class="panel__heading">
<h2>Auswertung</h2> <h2>Auswertung</h2>
<p>Stueckliste, Platzreserve und Kabelschaetzung.</p> <p>Stueckliste, Platzreserve und Kabelschaetzung.</p>
@@ -138,7 +126,28 @@ $apiBase = $publicBase === '' ? '' : $publicBase;
</div> </div>
<ul class="notes" id="validation-output"></ul> <ul class="notes" id="validation-output"></ul>
</section> </section>
</aside> </section>
</div>
<section class="dashboard-block dashboard-block--library">
<div class="panel__heading">
<h2>Bibliothek</h2>
<p>Module per Drag-and-Drop direkt aus der Liste ins Rack ziehen.</p>
</div>
<div class="library library--wide" id="component-library"></div>
</section>
</section>
<section class="panel panel--editor">
<div class="panel__heading">
<h2>Rack-Editor</h2>
<p>Komponenten koennen per Drag-and-Drop verschoben werden. Jede Position referenziert eine U-Einheit.</p>
</div>
<div class="rack-stage">
<div class="rack-grid" id="rack-grid" aria-live="polite"></div>
</div>
</section>
</main> </main>
</div> </div>