Compare commits
10 Commits
f3f24cebba
...
2ce58a3fc4
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ce58a3fc4 | |||
| 21276eba8a | |||
| 1901176010 | |||
| 86781c18f7 | |||
| e5d841caf9 | |||
| 7e9148f774 | |||
| b6124fb3a5 | |||
| 5618c8e85c | |||
| 467461b747 | |||
| 16b60cb47a |
@@ -1,21 +1,24 @@
|
|||||||
<?php
|
<?php
|
||||||
$app = app();
|
$app = app();
|
||||||
$app->assets()->addStyle('/assets/app.css', 'early');
|
$app->assets()->addStyle('/assets/css/app.css', 'early');
|
||||||
$app->assets()->addScript('/assets/app.js', 'footer', true);
|
$app->assets()->addScript('/assets/js/app.js', 'footer', true);
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<section class="mm-shell">
|
<section class="mm-shell">
|
||||||
<header class="mm-header">
|
<header class="mm-header">
|
||||||
<div>
|
<div class="mm-brand">
|
||||||
<p class="mm-kicker">Materialmatrix</p>
|
<img class="mm-logo" src="/assets/bilder/logo.png" alt="Logo">
|
||||||
<h1 class="mm-title"><?= htmlspecialchars(t('common.title'), ENT_QUOTES) ?></h1>
|
<div>
|
||||||
<p class="mm-subtitle">Schnell prüfen, welche Filamente auf welchen Druckern laufen.</p>
|
<p class="mm-kicker">Materialmatrix</p>
|
||||||
|
<h1 class="mm-title"><?= htmlspecialchars(t('common.title'), ENT_QUOTES) ?></h1>
|
||||||
|
<p class="mm-subtitle">Schnell prüfen, welche Filamente auf welchen Druckern laufen.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mm-status" id="status">Bereit</div>
|
<div class="mm-status" id="status">Bereit</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="mm-card">
|
<div class="mm-card">
|
||||||
<aside class="mm-sidebar">
|
<aside class="mm-sidebar mm-sidebar--top">
|
||||||
<div class="mm-panel">
|
<div class="mm-panel">
|
||||||
<h2>Drucker auswählen</h2>
|
<h2>Drucker auswählen</h2>
|
||||||
<label for="printerSelect">Einzelansicht</label>
|
<label for="printerSelect">Einzelansicht</label>
|
||||||
@@ -43,19 +46,17 @@ $app->assets()->addScript('/assets/app.js', 'footer', true);
|
|||||||
<tr id="tableHead">
|
<tr id="tableHead">
|
||||||
<th>Material</th>
|
<th>Material</th>
|
||||||
<th>Eigenschaften</th>
|
<th>Eigenschaften</th>
|
||||||
<th>Tg °C</th>
|
|
||||||
<th>Düse</th>
|
|
||||||
<th>Platte</th>
|
|
||||||
<th>Zusatz</th>
|
|
||||||
<th>Anwendung</th>
|
<th>Anwendung</th>
|
||||||
<th>Kinder</th>
|
<th>Kinder <span aria-hidden="true">👶</span></th>
|
||||||
<th>Emission</th>
|
<th>Emission <span aria-hidden="true">🌫️</span></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="matBody"></tbody>
|
<tbody id="matBody"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="mmTooltip" class="mm-tooltip" role="tooltip" aria-hidden="true"></div>
|
||||||
|
|
||||||
<div id="errorBox" class="mm-error" hidden></div>
|
<div id="errorBox" class="mm-error" hidden></div>
|
||||||
|
|
||||||
<section class="mm-disclaimer">
|
<section class="mm-disclaimer">
|
||||||
|
|||||||
BIN
public/assets/bilder/404.jpg
Normal file
BIN
public/assets/bilder/404.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
BIN
public/assets/bilder/logo.png
Normal file
BIN
public/assets/bilder/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
BIN
public/assets/bilder/logo_wuerfel.png
Normal file
BIN
public/assets/bilder/logo_wuerfel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
public/assets/bilder/orig/404.png
Normal file
BIN
public/assets/bilder/orig/404.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/assets/bilder/orig/logo.xcf
Normal file
BIN
public/assets/bilder/orig/logo.xcf
Normal file
Binary file not shown.
@@ -28,9 +28,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mm-shell {
|
.mm-shell {
|
||||||
max-width: 1200px;
|
max-width: 2000px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 3rem 2rem 4rem;
|
padding: 2rem 1rem 4rem;
|
||||||
animation: fadeUp 0.6s ease both;
|
animation: fadeUp 0.6s ease both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +42,23 @@
|
|||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mm-brand {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-logo {
|
||||||
|
height: 140px;
|
||||||
|
width: auto;
|
||||||
|
max-width: 320px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mm-kicker {
|
.mm-kicker {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
letter-spacing: 0.2em;
|
letter-spacing: 0.2em;
|
||||||
@@ -71,8 +88,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.mm-card {
|
.mm-card {
|
||||||
display: grid;
|
display: flex;
|
||||||
grid-template-columns: 280px 1fr;
|
flex-direction: column;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
background: var(--card);
|
background: var(--card);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
@@ -85,8 +102,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
border-right: 1px dashed var(--line);
|
border-bottom: 1px dashed var(--line);
|
||||||
padding-right: 1.5rem;
|
padding-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mm-panel h2 {
|
.mm-panel h2 {
|
||||||
@@ -161,6 +178,83 @@
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.mm-info-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.35rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: #fff7ed;
|
||||||
|
color: #9a3412;
|
||||||
|
padding: 0.15rem 0.5rem;
|
||||||
|
margin-top: 0.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-tooltip {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 50;
|
||||||
|
max-width: 280px;
|
||||||
|
background: #101018;
|
||||||
|
color: #f4f4f7;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 0.6rem 0.75rem;
|
||||||
|
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.25);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(6px);
|
||||||
|
transition: opacity 0.12s ease, transform 0.12s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-tooltip.is-visible {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-details-row {
|
||||||
|
background: #fffaf3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-details {
|
||||||
|
padding: 0.9rem 1rem;
|
||||||
|
border-left: 3px solid var(--accent);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||||
|
gap: 0.6rem 1rem;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--muted);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-details strong {
|
||||||
|
color: var(--ink);
|
||||||
|
display: block;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-row-toggle {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-details-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.6rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 999px;
|
||||||
|
padding: 0.2rem 0.6rem;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
color: var(--muted);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.mm-table tbody tr:nth-child(even) {
|
.mm-table tbody tr:nth-child(even) {
|
||||||
background: #fcfcff;
|
background: #fcfcff;
|
||||||
}
|
}
|
||||||
@@ -218,13 +312,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 980px) {
|
@media (max-width: 980px) {
|
||||||
.mm-card {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
.mm-sidebar {
|
.mm-sidebar {
|
||||||
border-right: none;
|
|
||||||
border-bottom: 1px dashed var(--line);
|
|
||||||
padding-right: 0;
|
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,4 +320,5 @@
|
|||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
.mm-shell { padding: 2rem 1.25rem 3rem; }
|
.mm-shell { padding: 2rem 1.25rem 3rem; }
|
||||||
.mm-header { flex-direction: column; align-items: flex-start; }
|
.mm-header { flex-direction: column; align-items: flex-start; }
|
||||||
|
.mm-brand { flex-direction: column; align-items: flex-start; }
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
const tableHead = document.getElementById('tableHead');
|
const tableHead = document.getElementById('tableHead');
|
||||||
const statusEl = document.getElementById('status');
|
const statusEl = document.getElementById('status');
|
||||||
const errorBox = document.getElementById('errorBox');
|
const errorBox = document.getElementById('errorBox');
|
||||||
|
const tooltipEl = document.getElementById('mmTooltip');
|
||||||
|
|
||||||
if (!printerSelect || !printerCompare || !matBody || !tableHead) {
|
if (!printerSelect || !printerCompare || !matBody || !tableHead) {
|
||||||
return;
|
return;
|
||||||
@@ -107,13 +108,9 @@
|
|||||||
const baseHead = [
|
const baseHead = [
|
||||||
'Material',
|
'Material',
|
||||||
'Eigenschaften',
|
'Eigenschaften',
|
||||||
'Tg °C',
|
|
||||||
'Düse',
|
|
||||||
'Platte',
|
|
||||||
'Zusatz',
|
|
||||||
'Anwendung',
|
'Anwendung',
|
||||||
'Kinder',
|
'Kinder <span aria-hidden="true">👶</span>',
|
||||||
'Emission'
|
'Emission <span aria-hidden="true">🌫️</span>'
|
||||||
].map(label => `<th>${label}</th>`).join('');
|
].map(label => `<th>${label}</th>`).join('');
|
||||||
|
|
||||||
let printerCols = '';
|
let printerCols = '';
|
||||||
@@ -139,19 +136,31 @@
|
|||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
tr.className = idx % 2 === 0 ? '' : 'is-alt';
|
tr.className = idx % 2 === 0 ? '' : 'is-alt';
|
||||||
|
|
||||||
const kid = m.kid_safety === 'safe' ? 'grün' : (m.kid_safety === 'limited' ? 'gelb' : 'rot');
|
const kid = m.kid_safety === 'safe'
|
||||||
const em = m.emission === 'low' ? 'niedrig' : (m.emission === 'medium' ? 'mittel' : 'hoch');
|
? { icon: '🌿', text: 'sicher' }
|
||||||
|
: (m.kid_safety === 'limited' ? { icon: '🟡', text: 'eingeschränkt' } : { icon: '🔴', text: 'nicht geeignet' });
|
||||||
|
const em = m.emission === 'low'
|
||||||
|
? { icon: '✅', text: 'niedrig' }
|
||||||
|
: (m.emission === 'medium' ? { icon: '⚠️', text: 'mittel' } : { icon: '⛔', text: 'hoch' });
|
||||||
|
|
||||||
let html = '';
|
let html = '';
|
||||||
html += `<td><strong>${escapeHtml(m.code)}</strong><div class="mm-sub">${escapeHtml(m.short_desc || '')}</div></td>`;
|
const detailPayload = {
|
||||||
|
tg: m.tg_celsius ?? '–',
|
||||||
|
nozzle: m.nozzle_req ?? '–',
|
||||||
|
plate: m.plate_req ?? '–',
|
||||||
|
extra: m.extra_req ?? '–',
|
||||||
|
emission: m.emission ?? '–'
|
||||||
|
};
|
||||||
|
const detailAttr = escapeHtml(JSON.stringify(detailPayload));
|
||||||
|
html += `<td class="mm-row-toggle" data-details="${detailAttr}">` +
|
||||||
|
`<strong>${escapeHtml(m.code)}</strong>` +
|
||||||
|
`<div class="mm-sub">${escapeHtml(m.short_desc || '')}</div>` +
|
||||||
|
`<button type="button" class="mm-info-btn" data-tooltip="Mehr Infos anzeigen">Mehr Info</button>` +
|
||||||
|
`</td>`;
|
||||||
html += `<td>${escapeHtml(m.properties || '')}</td>`;
|
html += `<td>${escapeHtml(m.properties || '')}</td>`;
|
||||||
html += `<td>${escapeHtml(m.tg_celsius || '–')}</td>`;
|
|
||||||
html += `<td>${escapeHtml(m.nozzle_req || '')}</td>`;
|
|
||||||
html += `<td>${escapeHtml(m.plate_req || '')}</td>`;
|
|
||||||
html += `<td>${escapeHtml(m.extra_req || '')}</td>`;
|
|
||||||
html += `<td>${escapeHtml(m.application || '')}</td>`;
|
html += `<td>${escapeHtml(m.application || '')}</td>`;
|
||||||
html += `<td>${escapeHtml(kid)}</td>`;
|
html += `<td title="${escapeHtml(kid.text)}">${kid.icon}</td>`;
|
||||||
html += `<td>${escapeHtml(em)}</td>`;
|
html += `<td title="${escapeHtml(em.text)}">${em.icon}</td>`;
|
||||||
|
|
||||||
datasets.forEach(ds => {
|
datasets.forEach(ds => {
|
||||||
const printerId = ds && ds.printer ? ds.printer.id : '';
|
const printerId = ds && ds.printer ? ds.printer.id : '';
|
||||||
@@ -181,6 +190,101 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setTooltip(content, x, y) {
|
||||||
|
if (!tooltipEl) return;
|
||||||
|
tooltipEl.textContent = content;
|
||||||
|
const padding = 12;
|
||||||
|
const maxX = window.innerWidth - tooltipEl.offsetWidth - padding;
|
||||||
|
const maxY = window.innerHeight - tooltipEl.offsetHeight - padding;
|
||||||
|
const left = Math.min(x + 14, maxX);
|
||||||
|
const top = Math.min(y + 14, maxY);
|
||||||
|
tooltipEl.style.left = Math.max(left, padding) + 'px';
|
||||||
|
tooltipEl.style.top = Math.max(top, padding) + 'px';
|
||||||
|
tooltipEl.classList.add('is-visible');
|
||||||
|
tooltipEl.setAttribute('aria-hidden', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideTooltip() {
|
||||||
|
if (!tooltipEl) return;
|
||||||
|
tooltipEl.classList.remove('is-visible');
|
||||||
|
tooltipEl.setAttribute('aria-hidden', 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDetailsHtml(details) {
|
||||||
|
return `
|
||||||
|
<button type="button" class="mm-details-close">Schließen</button>
|
||||||
|
<div><strong>Tg °C</strong>${escapeHtml(details.tg)}</div>
|
||||||
|
<div><strong>Düse</strong>${escapeHtml(details.nozzle)}</div>
|
||||||
|
<div><strong>Platte</strong>${escapeHtml(details.plate)}</div>
|
||||||
|
<div><strong>Zusatz</strong>${escapeHtml(details.extra)}</div>
|
||||||
|
<div><strong>Emission</strong>${escapeHtml(details.emission)}</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeActiveDetails() {
|
||||||
|
const open = matBody.querySelector('tr.mm-details-row');
|
||||||
|
if (open) {
|
||||||
|
open.remove();
|
||||||
|
}
|
||||||
|
const active = matBody.querySelector('tr.is-active');
|
||||||
|
if (active) {
|
||||||
|
active.classList.remove('is-active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matBody.addEventListener('mouseover', (e) => {
|
||||||
|
const cell = e.target.closest('[data-details]');
|
||||||
|
if (!cell) return;
|
||||||
|
let details;
|
||||||
|
try {
|
||||||
|
details = JSON.parse(cell.dataset.details || '{}');
|
||||||
|
} catch {
|
||||||
|
details = {};
|
||||||
|
}
|
||||||
|
const hoverText = `Tg °C: ${details.tg ?? '–'} | Düse: ${details.nozzle ?? '–'} | Platte: ${details.plate ?? '–'} | Zusatz: ${details.extra ?? '–'} | Emission: ${details.emission ?? '–'}`;
|
||||||
|
setTooltip(hoverText, e.clientX, e.clientY);
|
||||||
|
});
|
||||||
|
|
||||||
|
matBody.addEventListener('mousemove', (e) => {
|
||||||
|
if (!tooltipEl || tooltipEl.getAttribute('aria-hidden') === 'true') return;
|
||||||
|
setTooltip(tooltipEl.textContent, e.clientX, e.clientY);
|
||||||
|
});
|
||||||
|
|
||||||
|
matBody.addEventListener('mouseout', (e) => {
|
||||||
|
if (e.target.closest('[data-details]')) {
|
||||||
|
hideTooltip();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
matBody.addEventListener('click', (e) => {
|
||||||
|
if (e.target.closest('.mm-details-close')) {
|
||||||
|
closeActiveDetails();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cell = e.target.closest('[data-details]');
|
||||||
|
if (!cell) return;
|
||||||
|
|
||||||
|
const row = cell.closest('tr');
|
||||||
|
const isActive = row.classList.contains('is-active');
|
||||||
|
closeActiveDetails();
|
||||||
|
if (isActive) return;
|
||||||
|
|
||||||
|
let details;
|
||||||
|
try {
|
||||||
|
details = JSON.parse(cell.dataset.details || '{}');
|
||||||
|
} catch {
|
||||||
|
details = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const colCount = row.children.length;
|
||||||
|
const detailRow = document.createElement('tr');
|
||||||
|
detailRow.className = 'mm-details-row';
|
||||||
|
detailRow.innerHTML = `<td colspan="${colCount}"><div class="mm-details">${buildDetailsHtml(details)}</div></td>`;
|
||||||
|
row.classList.add('is-active');
|
||||||
|
row.parentNode.insertBefore(detailRow, row.nextSibling);
|
||||||
|
});
|
||||||
|
|
||||||
printerSelect.addEventListener('change', e => {
|
printerSelect.addEventListener('change', e => {
|
||||||
const id = e.target.value;
|
const id = e.target.value;
|
||||||
if (id) {
|
if (id) {
|
||||||
@@ -59,8 +59,9 @@ if ($uriPath === '' || $uriPath === 'index' || $uriPath === 'index.php') {
|
|||||||
$skipLayout = false;
|
$skipLayout = false;
|
||||||
$targetReal = realpath($target);
|
$targetReal = realpath($target);
|
||||||
|
|
||||||
// Beispiel: alles unter /page/raw/* ohne Layout
|
// Beispiel: alles unter /page/retool/* ohne Layout
|
||||||
if ($targetReal && str_starts_with($targetReal, realpath(__DIR__ . '/page/retool'))) {
|
$retoolBase = realpath(__DIR__ . '/page/retool');
|
||||||
|
if ($targetReal && $retoolBase && str_starts_with($targetReal, $retoolBase)) {
|
||||||
$skipLayout = true;
|
$skipLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user