Files
Webklar-Kundenbereich/public/dashboard.html
Claude 07ebcc7e62 feat(portal): Live-Vorschaufenster pro Projektkarte im Kundenbereich
Statt nur Name + Link zeigt jede Projektkarte jetzt ein kleines,
skaliertes Live-Fenster der echten Webseite (iframe der previewUrl,
responsiv per ResizeObserver auf 1280px-Basisbreite herunterskaliert).
Klick aufs Fenster oeffnet die Seite im neuen Tab. Nicht-fertige
Projekte zeigen einen Platzhalter statt iframe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 12:42:35 +00:00

176 lines
8.7 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kundenbereich Webklar</title>
<link rel="stylesheet" href="/login.css">
<style>
.viewas-banner {
display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
padding: 10px 16px; margin-bottom: 16px; border-radius: 12px;
background: rgba(251,191,36,0.12); border: 1px solid rgba(251,191,36,0.45);
}
/* Tabs (Muster aus Admin, violett) */
.portal-tabs { display: flex; gap: 8px; margin: 14px 0 22px; flex-wrap: wrap; }
.portal-tab {
background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.14);
color: inherit; padding: 9px 18px; border-radius: 999px; cursor: pointer; font: inherit;
display: inline-flex; align-items: center; gap: 8px;
}
.portal-tab.active { background: rgba(157,61,254,0.22); border-color: rgba(157,61,254,0.65); }
.portal-section { display: none; }
.portal-section.active { display: block; }
.portal-section-title { margin: 0 0 14px; font-size: 20px; }
.badge-pill {
display: inline-flex; min-width: 20px; height: 20px; padding: 0 6px;
align-items: center; justify-content: center; border-radius: 999px;
background: #9d3dfe; color: #fff; font-size: 12px; font-weight: 700;
}
.simple-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.simple-table th, .simple-table td { text-align: left; padding: 8px 10px; border-bottom: 1px solid rgba(255,255,255,0.08); }
.simple-table th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; opacity: 0.65; }
.simple-table tr:last-child td { border-bottom: none; }
.btn-link { color: #7dd3fc; text-decoration: none; }
.btn-link:hover { text-decoration: underline; }
.pill { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 12px; border: 1px solid transparent; white-space: nowrap; }
.pill-ok { background: rgba(74,222,128,0.15); border-color: rgba(74,222,128,0.4); }
.pill-warn { background: rgba(157,61,254,0.18); border-color: rgba(157,61,254,0.5); }
.pill-red { background: rgba(248,113,113,0.15); border-color: rgba(248,113,113,0.45); }
.pill-muted { background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.16); opacity: 0.85; }
.pill-git { background: rgba(251,146,60,0.16); border-color: rgba(251,146,60,0.5); }
.activity-item { padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,0.08); }
.activity-item:last-child { border-bottom: none; }
.activity-status {
display: inline-block; margin-left: 6px; padding: 1px 9px; border-radius: 999px; font-size: 12px;
background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.16);
}
.activity-ws { font-size: 13px; opacity: 0.85; margin: 4px 0 4px 14px; white-space: pre-wrap; }
/* Projekt-Details */
.project-details-toggle { margin-top: 10px; }
.project-details { margin-top: 14px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 12px; }
.project-details h3 { margin: 12px 0 8px; font-size: 15px; }
.commit-item { padding: 6px 0; border-bottom: 1px solid rgba(255,255,255,0.06); font-size: 14px; }
.commit-item:last-child { border-bottom: none; }
.commit-meta { font-size: 12px; opacity: 0.6; }
.commit-body { font-size: 13px; opacity: 0.8; white-space: pre-wrap; margin: 2px 0 0 8px; }
/* Projekt-Vorschaufenster */
.preview-frame {
position: relative; display: block; width: 100%; aspect-ratio: 16 / 10;
overflow: hidden; border-radius: 12px; border: 1px solid rgba(255,255,255,0.14);
background: rgba(255,255,255,0.04); margin-bottom: 1rem; text-decoration: none;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.preview-frame:hover { border-color: rgba(157,61,254,0.7); box-shadow: 0 0 0 1px rgba(157,61,254,0.35); }
.preview-frame__view {
position: absolute; top: 0; left: 0; width: 1280px; height: 800px; border: 0;
transform-origin: 0 0; pointer-events: none; background: #fff;
}
.preview-frame__hint {
position: absolute; left: 0; right: 0; bottom: 0; padding: 10px 14px;
font-size: 13px; font-weight: 600; color: #fff;
background: linear-gradient(to top, rgba(0,0,0,0.6), rgba(0,0,0,0));
opacity: 0; transition: opacity 0.2s ease; pointer-events: none;
}
.preview-frame:hover .preview-frame__hint { opacity: 1; }
.preview-frame--empty {
display: flex; align-items: center; justify-content: center;
color: rgba(255,255,255,0.5); font-size: 14px; aspect-ratio: 16 / 10;
}
.preview-open { margin: 0.75rem 0 0; }
/* Chat */
.chat-box { display: flex; flex-direction: column; height: 480px; }
.chat-messages { flex: 1; overflow-y: auto; padding: 6px 4px; display: flex; flex-direction: column; gap: 10px; }
.chat-bubble { max-width: 78%; padding: 10px 14px; border-radius: 16px; font-size: 14px; white-space: pre-wrap; word-break: break-word; }
.chat-bubble .chat-meta { display: block; font-size: 11px; opacity: 0.6; margin-top: 4px; }
.chat-bubble.mine { align-self: flex-end; background: rgba(157,61,254,0.3); border: 1px solid rgba(157,61,254,0.5); border-bottom-right-radius: 4px; }
.chat-bubble.theirs { align-self: flex-start; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.14); border-bottom-left-radius: 4px; }
.chat-input-row { display: flex; gap: 10px; margin-top: 12px; align-items: flex-end; }
.chat-input-row textarea {
flex: 1; resize: none; min-height: 46px; max-height: 130px; padding: 12px 14px;
border-radius: 14px; border: 1px solid rgba(255,255,255,0.18);
background: rgba(255,255,255,0.06); color: inherit; font: inherit;
}
.chat-send {
background: #9d3dfe; border: none; color: #fff; font: inherit; font-weight: 600;
padding: 12px 20px; border-radius: 14px; cursor: pointer;
}
.chat-send:disabled { opacity: 0.5; cursor: default; }
.chat-hint { font-size: 12px; opacity: 0.55; margin-top: 6px; }
</style>
</head>
<body class="portal-page dashboard-page">
<div class="dot-background" aria-hidden="true">
<div class="dot-pattern"></div>
<div class="dot-fade"></div>
</div>
<header class="portal-header">
<a class="portal-logo" href="/dashboard.html">Webklar</a>
<div class="portal-header-actions">
<span class="portal-meta" id="customer-meta"></span>
<button type="button" class="portal-btn-outline" id="logout-btn">Abmelden</button>
</div>
</header>
<main class="portal-main dashboard-content-reveal">
<div id="viewas-banner" class="viewas-banner hidden"></div>
<h1 class="portal-title">Kundenbereich</h1>
<p id="load-error" class="error hidden"></p>
<div class="portal-tabs">
<button class="portal-tab active" data-tab="projects">Projekte</button>
<button class="portal-tab" data-tab="activity">Was wurde gemacht</button>
<button class="portal-tab" data-tab="invoices">Rechnungen</button>
<button class="portal-tab" data-tab="chat">Chat <span id="chat-badge" class="badge-pill hidden"></span></button>
</div>
<!-- Projekte -->
<section class="portal-section active" id="tab-projects">
<p id="loading" class="muted portal-status">Projekte werden geladen…</p>
<ul id="projects" class="projects hidden"></ul>
<p id="empty" class="portal-card hidden portal-status">Noch keine Website-Projekte zugewiesen.</p>
</section>
<!-- Was wurde gemacht -->
<section class="portal-section" id="tab-activity">
<h2 class="portal-section-title">Was wurde gemacht</h2>
<div class="portal-card" id="activity-body"><p class="muted">Lade…</p></div>
</section>
<!-- Rechnungen -->
<section class="portal-section" id="tab-invoices">
<h2 class="portal-section-title">Meine Rechnungen</h2>
<div class="portal-card" id="invoices-body"><p class="muted">Lade…</p></div>
</section>
<!-- Chat -->
<section class="portal-section" id="tab-chat">
<h2 class="portal-section-title">Chat mit dem Webklar-Team</h2>
<div class="portal-card chat-box">
<div class="chat-messages" id="chat-messages"></div>
<div class="chat-input-row">
<textarea id="chat-input" maxlength="2000" placeholder="Nachricht an das Webklar-Team…"></textarea>
<button type="button" class="chat-send" id="chat-send">Senden</button>
</div>
<p class="chat-hint">Enter = Senden, Shift+Enter = Zeilenumbruch. Wir antworten in der Regel innerhalb eines Werktags.</p>
</div>
</section>
</main>
<script src="/app.js"></script>
<script>
initDashboardPage();
</script>
</body>
</html>