Kundenbereich: „Wartung“ heißt jetzt „Verträge“, auch am Desktop in der Navigation
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
36b54f6dab
commit
0129ac48e7
3 files changed
+62
-62
No files matched your search
+27
-29
@@ -816,7 +816,7 @@ function renderAboSideOffer(card, data, { ended }) {
|
||||
: '<strong>50 €</strong><span>pro Monat</span>'}</p>
|
||||
${offer?.validUntil ? `<p class="kb-offer-until">Angebot gültig bis <strong>${fmtDateShort(offer.validUntil)}</strong></p>` : ''}
|
||||
<ul class="kb-checks">${ABO_SIDE_FEATURES.map((f) => `<li>${escapeHtml(f)}</li>`).join('')}</ul>
|
||||
<button type="button" class="kb-btn-primary kb-btn-block" data-view="abo"${data.available ? '' : ' disabled'}>Abo abschließen</button>
|
||||
<button type="button" class="kb-btn-primary kb-btn-block" data-view="stunden"${data.available ? '' : ' disabled'}>Abo abschließen</button>
|
||||
<p class="kb-fine">${data.available
|
||||
? '12 Monate Mindestlaufzeit. Gemäß § 19 UStG ohne Umsatzsteuer.'
|
||||
: 'Die Online-Bestellung wird gerade eingerichtet – schreiben Sie uns gern im Chat.'}</p>`
|
||||
@@ -837,7 +837,7 @@ function renderAboSideActive(card, data) {
|
||||
card.innerHTML = `
|
||||
<p class="kb-label">Ihre Wartung</p>
|
||||
${status}
|
||||
<button type="button" class="kb-hours" data-view="abo" title="Stundenkonto und Verlauf ansehen" aria-label="${fmtHours(l.balanceMinutes)} Arbeitszeit verfügbar – Stundenkonto und Verlauf ansehen">
|
||||
<button type="button" class="kb-hours" data-view="stunden" title="Stundenkonto und Verlauf ansehen" aria-label="${fmtHours(l.balanceMinutes)} Arbeitszeit verfügbar – Stundenkonto und Verlauf ansehen">
|
||||
<strong>${fmtHours(l.balanceMinutes)}</strong><span>Arbeitszeit verfügbar</span><em aria-hidden="true">›</em>
|
||||
</button>
|
||||
<p class="kb-sub">${dateLine}</p>
|
||||
@@ -971,7 +971,7 @@ function renderAboAccountView(view, data) {
|
||||
<h1>Wartungs-Abo</h1>
|
||||
<p>Ihr Stundenkontingent, der Verlauf und Ihr Vertrag.</p>
|
||||
</header>
|
||||
${sub.paymentProblem ? '<div class="abo-alert">Die letzte Abbuchung ist fehlgeschlagen. Bitte aktualisieren Sie Ihre Zahlungsart über „Zahlungsart aktualisieren“ <span class="kb-desk-only">in der Seitenleiste</span><span class="kb-app-only">unter <a href="#wartung" data-view="wartung">Wartung</a></span>, damit Ihre Website online bleibt.</div>' : ''}
|
||||
${sub.paymentProblem ? '<div class="abo-alert">Die letzte Abbuchung ist fehlgeschlagen. Bitte aktualisieren Sie Ihre Zahlungsart über „Zahlungsart aktualisieren“ <span class="kb-desk-only">in der Seitenleiste</span><span class="kb-app-only">unter <a href="#vertraege" data-view="vertraege">Verträge</a></span>, damit Ihre Website online bleibt.</div>' : ''}
|
||||
${sub.serviceStartsAt ? `<div class="abo-alert">Wie gewählt beginnen wir nach Ablauf der Widerrufsfrist am ${fmtDateShort(sub.serviceStartsAt)}. Dann wird auch zum ersten Mal abgebucht, und Ihre erste Stunde steht bereit.</div>` : ''}
|
||||
<div class="kb-stats">
|
||||
<div class="kb-stat"><strong>${fmtHours(l.balanceMinutes)}</strong><span>verfügbare Zeit</span></div>
|
||||
@@ -998,7 +998,7 @@ const aboState = { data: null }
|
||||
|
||||
async function loadAboCard({ afterCheckout = false } = {}) {
|
||||
const card = document.getElementById('abo-card')
|
||||
const view = document.getElementById('view-abo')
|
||||
const view = document.getElementById('view-stunden')
|
||||
if (!card || !view) return
|
||||
try {
|
||||
let data = await api('/api/abo')
|
||||
@@ -1020,6 +1020,8 @@ async function loadAboCard({ afterCheckout = false } = {}) {
|
||||
card.classList.remove('hidden')
|
||||
document.getElementById('invoices-abo-note')?.classList.toggle('hidden', !data.subscription)
|
||||
document.getElementById('kb-sheet-abo')?.classList.toggle('hidden', !data.subscription)
|
||||
// Vertragsbedingungen im Konto-Menue: die Fassung, die fuer das Abo des Kunden gilt
|
||||
document.getElementById('kb-sheet-terms')?.setAttribute('href', data.subscription?.termsUrl || '/abo-bedingungen.html')
|
||||
loadTakeoverCard({ abo: data })
|
||||
document.dispatchEvent(new CustomEvent('kb:abo', { detail: data }))
|
||||
} catch (err) {
|
||||
@@ -1242,7 +1244,7 @@ async function loadTakeoverCard({ abo, notice = '' } = {}) {
|
||||
const requests = data.requests || []
|
||||
updateTakeoverBadge(requests)
|
||||
if (!active && !requests.length) {
|
||||
card.innerHTML = '<div class="kb-panel"><p class="abo-note" style="margin:0">Die Übernahmegutschrift können Sie beantragen, sobald Ihr Abo läuft. <a href="#abo" data-view="abo">Zum Abo</a></p></div>'
|
||||
card.innerHTML = '<div class="kb-panel"><p class="abo-note" style="margin:0">Die Übernahmegutschrift können Sie beantragen, sobald Ihr Abo läuft. <a href="#vertraege" data-view="vertraege">Zum Abo</a></p></div>'
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1392,16 +1394,18 @@ function initPasswordView() {
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------- Navigation --- */
|
||||
// Ansichten im Inhaltsbereich; Hash fuer Direktlinks (z. B. aus Mails: #abo, #gutschrift).
|
||||
// "wartung" gibt es nur in der App-Ansicht (Tab), am Desktop zeigt sie das Wartungs-Abo.
|
||||
// Ansichten im Inhaltsbereich; Hash fuer Direktlinks (z. B. aus Mails: #vertraege, #gutschrift).
|
||||
// Die alten Hashes #wartung und #abo fuehren zu #vertraege (HASH_ALIASES).
|
||||
// "projekt" (Projektdetails als eigene Seite) gibt es ebenfalls nur in der App-Ansicht.
|
||||
// "passwort" oeffnet das Konto-Menue (Profilbild).
|
||||
const VIEW_HASHES = { projects: '', activity: 'fortschritt', invoices: 'rechnungen', chat: 'chat', wartung: 'wartung', abo: 'abo', takeover: 'gutschrift', projekt: 'projekt', passwort: 'passwort' }
|
||||
const VIEW_HASHES = { projects: '', activity: 'fortschritt', invoices: 'rechnungen', chat: 'chat', vertraege: 'vertraege', stunden: 'stunden', 'bestellen-hosting': 'bestellen-hosting', 'bestellen-wartung': 'bestellen-wartung', wechsel: 'wechsel', takeover: 'gutschrift', projekt: 'projekt', passwort: 'passwort' }
|
||||
const HASH_ALIASES = { wartung: 'vertraege', abo: 'vertraege' }
|
||||
const viewLoaders = { activity: loadCustomerActivity, chat: initChat }
|
||||
const loadedViews = new Set()
|
||||
|
||||
function viewFromHash() {
|
||||
const hash = window.location.hash.replace(/^#/, '')
|
||||
if (HASH_ALIASES[hash]) return HASH_ALIASES[hash]
|
||||
return Object.keys(VIEW_HASHES).find((v) => VIEW_HASHES[v] && VIEW_HASHES[v] === hash) || ''
|
||||
}
|
||||
|
||||
@@ -1506,7 +1510,8 @@ async function initDashboardPage() {
|
||||
loadCustomerInvoices()
|
||||
|
||||
const initialView = viewFromHash()
|
||||
if (initialView) showView(initialView, { updateHash: false })
|
||||
// Alte Hashes (#wartung, #abo) gleich auf den neuen (#vertraege) umschreiben
|
||||
if (initialView) showView(initialView, { updateHash: Boolean(HASH_ALIASES[window.location.hash.replace(/^#/, '')]) })
|
||||
|
||||
const [{ projects }, { features }] = await Promise.all([
|
||||
api('/api/projects'),
|
||||
@@ -1551,8 +1556,8 @@ const appLayout = window.matchMedia('(max-width: 880px), (pointer: coarse) and (
|
||||
const coarsePointer = window.matchMedia('(pointer: coarse)')
|
||||
// Unterseite -> Tab, zu dem sie gehoert (und Text neben dem Zurueck-Pfeil).
|
||||
// "passwort" setzt onAppViewShown: die Ansicht, aus der das Konto-Menue geoeffnet wurde.
|
||||
const APP_PARENT = { abo: 'wartung', takeover: 'wartung', projekt: 'projects' }
|
||||
const APP_PARENT_LABEL = { wartung: 'Wartung', projects: 'Projekte', activity: 'Fortschritt', invoices: 'Rechnungen', chat: 'Chat' }
|
||||
const APP_PARENT = { stunden: 'vertraege', 'bestellen-hosting': 'vertraege', 'bestellen-wartung': 'vertraege', wechsel: 'vertraege', takeover: 'vertraege', projekt: 'projects' }
|
||||
const APP_PARENT_LABEL = { vertraege: 'Verträge', projects: 'Projekte', activity: 'Fortschritt', invoices: 'Rechnungen', chat: 'Chat' }
|
||||
const appShell = { view: 'projects', scroll: {}, fromHistory: false, sideCards: [], installPrompt: null }
|
||||
const TEXT_INPUT = 'textarea, input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=date]):not([type=button]):not([type=submit]):not([type=range]):not([type=color])'
|
||||
|
||||
@@ -1573,7 +1578,7 @@ function isIosDevice() {
|
||||
return /iphone|ipad|ipod/i.test(navigator.userAgent) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
|
||||
}
|
||||
|
||||
// Karten der Seitenleiste: App-Ansicht -> Ansprechpartner ins Konto-Sheet, Abo-Karte in den Tab "Wartung"
|
||||
// Karten der Seitenleiste: App-Ansicht -> Ansprechpartner ins Konto-Sheet, Abo-Karte in den Tab "Verträge"
|
||||
function placeSideCards() {
|
||||
for (const { el, slot, anchor } of appShell.sideCards) {
|
||||
if (isAppLayout()) {
|
||||
@@ -1613,11 +1618,6 @@ function updateAppBar() {
|
||||
}
|
||||
|
||||
function onAppViewShown(name) {
|
||||
// Den Tab "Wartung" gibt es nur in der App-Ansicht; am Desktop direkt das Wartungs-Abo zeigen
|
||||
if (name === 'wartung' && !isAppLayout()) {
|
||||
showView('abo', { updateHash: !appShell.fromHistory })
|
||||
return
|
||||
}
|
||||
// Projektdetails als Seite nur in der App-Ansicht und nur mit gewaehltem Projekt (nicht per Direktlink)
|
||||
if (name === 'projekt' && (!isAppLayout() || !projectPage.project)) {
|
||||
showView('projects', { updateHash: !appShell.fromHistory })
|
||||
@@ -1642,7 +1642,7 @@ function onAppViewShown(name) {
|
||||
})
|
||||
|
||||
if (isAppLayout()) {
|
||||
// Unterseite mit eigenem Verlaufseintrag: "Zurück" (auch die Android-Geste) führt zum Tab darüber (Wartung bzw. Projekte)
|
||||
// Unterseite mit eigenem Verlaufseintrag: "Zurück" (auch die Android-Geste) führt zum Tab darüber (Verträge bzw. Projekte)
|
||||
if (nav === 'push' && !appShell.fromHistory) {
|
||||
window.history.replaceState(null, '', VIEW_HASHES[parent] ? `#${VIEW_HASHES[parent]}` : window.location.pathname)
|
||||
window.history.pushState({ kbSub: name }, '', `#${VIEW_HASHES[name]}`)
|
||||
@@ -1670,10 +1670,10 @@ function revealChatComposer() {
|
||||
if (Number.isFinite(delta) && Math.abs(delta) > 1) window.scrollBy(0, delta)
|
||||
}
|
||||
|
||||
/* Wartungs-Tab: Hinweis bei fehlgeschlagener Zahlung oder offener Rückfrage zur Gutschrift */
|
||||
function updateWartungBadge() {
|
||||
/* Tab "Verträge": Hinweis bei fehlgeschlagener Zahlung oder offener Rückfrage zur Gutschrift */
|
||||
function updateVertraegeBadge() {
|
||||
const card = document.getElementById('abo-card')
|
||||
const badge = document.getElementById('kb-tab-wartung-badge')
|
||||
const badge = document.getElementById('kb-tab-vertraege-badge')
|
||||
if (!card || !badge) return
|
||||
const paymentProblem = Boolean(card.querySelector('.kb-side-alert'))
|
||||
const questions = Number(card.querySelector('#takeover-badge:not(.hidden)')?.textContent || 0)
|
||||
@@ -1832,17 +1832,16 @@ function initAppShell() {
|
||||
|
||||
document.addEventListener('kb:view', (ev) => onAppViewShown(ev.detail.name))
|
||||
document.addEventListener('kb:abo', (ev) => {
|
||||
document.getElementById('kb-tab-wartung')?.classList.toggle('hidden', !ev.detail)
|
||||
const slot = document.getElementById('kb-abo-slot')
|
||||
slot?.querySelector(':scope > .kb-empty')?.remove()
|
||||
if (!ev.detail) slot?.insertAdjacentHTML('afterbegin', '<p class="kb-empty">Die Wartung konnte gerade nicht geladen werden. Bitte später noch einmal versuchen.</p>')
|
||||
updateWartungBadge()
|
||||
if (!ev.detail) slot?.insertAdjacentHTML('afterbegin', '<p class="kb-empty">Ihre Verträge konnten gerade nicht geladen werden. Bitte später noch einmal versuchen.</p>')
|
||||
updateVertraegeBadge()
|
||||
updateAppBar()
|
||||
})
|
||||
const aboCard = document.getElementById('abo-card')
|
||||
if (aboCard) new MutationObserver(updateWartungBadge).observe(aboCard, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] })
|
||||
if (aboCard) new MutationObserver(updateVertraegeBadge).observe(aboCard, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] })
|
||||
|
||||
// Zurueck: ueber den Verlauf, falls die Unterseite ihn angelegt hat, sonst direkt zur Wartung
|
||||
// Zurueck: ueber den Verlauf, falls die Unterseite ihn angelegt hat, sonst direkt zu den Verträgen
|
||||
document.getElementById('kb-back')?.addEventListener('click', () => {
|
||||
if (window.history.state?.kbSub) window.history.back()
|
||||
else showView(APP_PARENT[appShell.view] || 'projects')
|
||||
@@ -1946,7 +1945,6 @@ function initAppShell() {
|
||||
|
||||
onMediaChange(appLayout, () => {
|
||||
placeSideCards()
|
||||
if (!isAppLayout() && appShell.view === 'wartung') showView('abo')
|
||||
if (!isAppLayout() && appShell.view === 'projekt') showView('projects')
|
||||
updateAppBar()
|
||||
renderInstallOffers()
|
||||
@@ -1956,8 +1954,8 @@ function initAppShell() {
|
||||
renderInstallOffers()
|
||||
updateAppBar()
|
||||
|
||||
// Nach der Bestellung bei Stripe: Bestaetigung steht auf der Abo-Karte im Tab "Wartung"
|
||||
if (isAppLayout() && getQueryParam('abo') === 'success') showView('wartung')
|
||||
// Nach der Bestellung bei Stripe: Bestaetigung steht auf der Abo-Karte im Tab "Verträge"
|
||||
if (isAppLayout() && getQueryParam('abo') === 'success') showView('vertraege')
|
||||
}
|
||||
|
||||
// iOS zoomt beim Tippen in ein Feld hinein, wenn dessen Schrift effektiv unter 16 px liegt – z. B. bei
|
||||
|
||||
+22
-19
@@ -30,10 +30,10 @@
|
||||
<div class="kb-glow" aria-hidden="true"></div>
|
||||
|
||||
<header class="kb-header">
|
||||
<!-- App-Ansicht: Zurueck aus Unterseiten (Wartung, Projektdetails; Text setzt updateAppBar), Seitentitel beim Scrollen (initAppShell) -->
|
||||
<button type="button" class="kb-back hidden" id="kb-back" aria-label="Zurück zu Wartung">
|
||||
<!-- App-Ansicht: Zurueck aus Unterseiten (Verträge, Projektdetails; Text setzt updateAppBar), Seitentitel beim Scrollen (initAppShell) -->
|
||||
<button type="button" class="kb-back hidden" id="kb-back" aria-label="Zurück zu Verträge">
|
||||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
|
||||
<span>Wartung</span>
|
||||
<span>Verträge</span>
|
||||
</button>
|
||||
<div class="kb-bar-title">
|
||||
<a class="kb-logo" href="/dashboard.html"><svg class="kb-logo-mark" viewBox="0 0 512 512" aria-hidden="true"><rect width="512" height="512" fill="#fff"/><g transform="translate(256 256) scale(0.9) translate(-256 -256)"><ellipse cx="256" cy="256" rx="210" ry="150" fill="#111" transform="rotate(-28 256 256)"/><circle cx="356" cy="172" r="18" fill="#fff"/><path transform="translate(256 256) rotate(-28)" d="M 0,-170 C 22,-105 60,-72 120,-56 C 60,-40 22,-8 0,64 C -22,-8 -60,-40 -120,-56 C -60,-72 -22,-105 0,-170 Z" fill="#fff"/></g></svg>WEBKLAR</a>
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
<!-- Konto: auf dem Handy als Bottom-Sheet, am Desktop als Popover unter dem Avatar (initAccountSheet).
|
||||
Alles zu den Verträgen und "Abmelden" steht im Kundenbereich nur hier. Einzige Ausnahme: während
|
||||
der Widerrufsfrist zeigt die Wartungskarte "Vertrag widerrufen" (§ 356a BGB: hervorgehoben platziert).
|
||||
der Widerrufsfrist zeigt die Vertragskarte "Vertrag widerrufen" (§ 356a BGB: hervorgehoben platziert).
|
||||
Öffentlich, ohne Anmeldung: Login-Seite und Footer von webklar.com. -->
|
||||
<dialog class="kb-sheet" id="kb-sheet" aria-label="Mein Konto">
|
||||
<div class="kb-sheet-panel">
|
||||
@@ -70,9 +70,10 @@
|
||||
<div class="kb-install hidden" data-install></div>
|
||||
<p class="kb-label kb-sheet-label">Verträge</p>
|
||||
<nav class="kb-sheet-links" aria-label="Verträge">
|
||||
<!-- Nur mit Wartungs-Abo: Stripe-Kundenportal; Name wie in den Bedingungen § 7 ("Abo verwalten") -->
|
||||
<button type="button" data-view="vertraege">Mein Vertrag</button>
|
||||
<!-- Nur mit Abo: Stripe-Kundenportal; Name wie in den Bedingungen § 7 ("Abo verwalten") -->
|
||||
<button type="button" class="kb-sheet-ext hidden" id="kb-sheet-abo">Abo verwalten & Rechnungen</button>
|
||||
<a href="/abo-bedingungen.html" target="_blank" rel="noopener">Vertragsbedingungen</a>
|
||||
<a href="/abo-bedingungen.html" target="_blank" rel="noopener" id="kb-sheet-terms">Vertragsbedingungen</a>
|
||||
<a class="legal-strong" href="/kuendigen.html">Verträge hier kündigen</a>
|
||||
<a class="legal-strong" href="/widerrufen.html">Vertrag widerrufen</a>
|
||||
</nav>
|
||||
@@ -90,8 +91,8 @@
|
||||
</dialog>
|
||||
|
||||
<div class="kb-shell dashboard-content-reveal">
|
||||
<!-- Seitenleiste: Navigation, Ansprechpartner, Wartungs-Abo. In der App-Ansicht (Handy)
|
||||
wird die Navigation zur Tab-Leiste unten; die Karten wandern in Konto-Sheet bzw. Tab "Wartung". -->
|
||||
<!-- Seitenleiste: Navigation, Ansprechpartner, Abo-Karte. In der App-Ansicht (Handy)
|
||||
wird die Navigation zur Tab-Leiste unten; die Karten wandern in Konto-Sheet bzw. Tab "Verträge". -->
|
||||
<aside class="kb-side">
|
||||
<p class="kb-label">Kundenbereich</p>
|
||||
<nav class="kb-nav" aria-label="Kundenbereich">
|
||||
@@ -107,10 +108,9 @@
|
||||
<button type="button" class="kb-nav-item" data-view="chat">
|
||||
<svg class="kb-tab-ico" viewBox="0 0 24 24" aria-hidden="true"><path d="M20 14.5a2.5 2.5 0 0 1-2.5 2.5H8l-4 4V5.5A2.5 2.5 0 0 1 6.5 3h11A2.5 2.5 0 0 1 20 5.5z"/></svg>
|
||||
<span class="kb-tab-label">Chat</span> <span class="kb-badge hidden" id="chat-badge" title="ungelesene Nachrichten"></span></button>
|
||||
<!-- Nur App-Ansicht; am Desktop steht die Wartung als Karte in der Seitenleiste -->
|
||||
<button type="button" class="kb-nav-item kb-tab-wartung hidden" data-view="wartung" id="kb-tab-wartung">
|
||||
<button type="button" class="kb-nav-item kb-tab-vertraege" data-view="vertraege" id="kb-tab-vertraege">
|
||||
<svg class="kb-tab-ico" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3l7 3v5.5c0 4.3-2.9 8.1-7 9.5-4.1-1.4-7-5.2-7-9.5V6z"/><path d="M9 12l2 2 4-4"/></svg>
|
||||
<span class="kb-tab-label">Wartung</span> <span class="kb-badge hidden" id="kb-tab-wartung-badge"></span></button>
|
||||
<span class="kb-tab-label">Verträge</span> <span class="kb-badge hidden" id="kb-tab-vertraege-badge"></span></button>
|
||||
</nav>
|
||||
|
||||
<section class="kb-card kb-contact" aria-label="Ansprechpartner">
|
||||
@@ -120,7 +120,7 @@
|
||||
<button type="button" data-view="chat">Nachricht schreiben</button>
|
||||
</section>
|
||||
|
||||
<!-- Wartungs-Abo: Angebot bzw. Status (app.js) -->
|
||||
<!-- Abo: Angebot bzw. Status (app.js) -->
|
||||
<section class="kb-abo hidden" id="abo-card" aria-live="polite"></section>
|
||||
</aside>
|
||||
|
||||
@@ -184,18 +184,21 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- App-Ansicht, Tab "Wartung": die Abo-Karte der Seitenleiste als Übersicht;
|
||||
Stundenkonto bzw. Bestellung und Übernahmegutschrift öffnen sich als Unterseiten -->
|
||||
<section class="kb-view" id="view-wartung">
|
||||
<!-- Tab "Verträge": die Abo-Karte der Seitenleiste als Übersicht (App-Ansicht);
|
||||
Stundenkonto, Bestellung, Wechsel und Übernahmegutschrift öffnen sich als Unterseiten -->
|
||||
<section class="kb-view" id="view-vertraege">
|
||||
<header class="kb-head">
|
||||
<h1>Wartung</h1>
|
||||
<p>Betrieb, Pflege und Support für Ihre Website.</p>
|
||||
<h1>Verträge</h1>
|
||||
<p>Ihre Verträge mit WEBklar: Hosting, Wartung und Zusatzspeicher.</p>
|
||||
</header>
|
||||
<div id="kb-abo-slot"><p class="kb-empty">Lade…</p></div>
|
||||
</section>
|
||||
|
||||
<!-- Wartungs-Abo: Bestellung bzw. Stundenkonto (app.js) -->
|
||||
<section class="kb-view" id="view-abo" aria-live="polite"></section>
|
||||
<!-- Stundenkonto (Wartungs-Abo), Bestellungen und Wechsel (app.js, Aufgaben 15 bis 18) -->
|
||||
<section class="kb-view" id="view-stunden" aria-live="polite"></section>
|
||||
<section class="kb-view" id="view-bestellen-hosting" aria-live="polite"></section>
|
||||
<section class="kb-view" id="view-bestellen-wartung" aria-live="polite"></section>
|
||||
<section class="kb-view" id="view-wechsel" aria-live="polite"></section>
|
||||
|
||||
<!-- Übernahmegutschrift (app.js) -->
|
||||
<section class="kb-view" id="view-takeover">
|
||||
|
||||
+13
-14
@@ -533,7 +533,7 @@ button.kb-avatar:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
|
||||
}
|
||||
|
||||
/* Elemente, die es nur in der App-Ansicht gibt */
|
||||
.kb-back, .kb-logo-mark, .kb-app-title, .kb-tab-ico, .kb-nav-item.kb-tab-wartung, .kb-app-only, .kb-install { display: none; }
|
||||
.kb-back, .kb-logo-mark, .kb-app-title, .kb-tab-ico, .kb-app-only, .kb-install { display: none; }
|
||||
|
||||
@keyframes kb-pop-in { from { opacity: 0; transform: translateY(-6px) scale(0.98); } }
|
||||
@keyframes kb-sheet-up { from { transform: translateY(100%); } }
|
||||
@@ -552,7 +552,7 @@ button.kb-avatar:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
|
||||
|
||||
/* ----------------------------------------------------- App-Ansicht (Handy) --- */
|
||||
/* Unter 880px (und Handys quer): Kopfzeile als App-Leiste (Titel erscheint beim Scrollen),
|
||||
Navigation als Tab-Leiste unten, Karten der Seitenleiste im Konto-Sheet bzw. Tab "Wartung".
|
||||
Navigation als Tab-Leiste unten, Karten der Seitenleiste im Konto-Sheet bzw. Tab "Verträge".
|
||||
Dieselbe Bedingung steht in app.js (appLayout). */
|
||||
@media (max-width: 880px), (pointer: coarse) and (max-height: 500px) {
|
||||
.kb-page {
|
||||
@@ -625,7 +625,6 @@ button.kb-avatar:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
|
||||
padding: 4px 0 2px; border: none; border-radius: 12px; background: none; color: rgba(255, 255, 255, 0.55);
|
||||
font-size: 10.5px; font-weight: 600; letter-spacing: 0; text-align: center; touch-action: manipulation;
|
||||
}
|
||||
.kb-nav-item.kb-tab-wartung { display: flex; }
|
||||
.kb-nav-item::before {
|
||||
position: absolute; top: 3px; left: 50%; width: 56px; height: 30px; margin-left: -28px; border-radius: 999px;
|
||||
background: transparent; box-shadow: none; transition: background-color 0.2s;
|
||||
@@ -726,18 +725,18 @@ button.kb-avatar:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
|
||||
/* Eingabe des Chat-Composers als Pille, passend zu dessen runden Knoepfen (Senden-Knopf: chat-composer.css) */
|
||||
.chat-input-row textarea { box-sizing: border-box; min-height: 46px; padding: 11px 16px; border-radius: 23px; font-size: 16px; line-height: 1.35; }
|
||||
|
||||
/* Tab "Wartung": Abo-Karte gross; darunter Unterseiten Stundenkonto/Bestellung und Gutschrift */
|
||||
/* Tab "Verträge": Abo-Karte gross; darunter Unterseiten Stundenkonto/Bestellung und Gutschrift */
|
||||
#kb-abo-slot:has(> .kb-abo:not(.hidden)) > .kb-empty { display: none; }
|
||||
#view-wartung .kb-abo { padding: 20px 18px 18px; border-radius: 20px; }
|
||||
#view-wartung .kb-abo h3 { font-size: 22px; }
|
||||
#view-wartung .kb-price strong, #view-wartung .kb-hours strong { font-size: 32px; }
|
||||
#view-wartung .kb-price span, #view-wartung .kb-hours span, #view-wartung .kb-sub, #view-wartung .kb-offer-until { font-size: 14px; }
|
||||
#view-wartung .kb-checks { gap: 9px; font-size: 14.5px; }
|
||||
#view-wartung .kb-fine { font-size: 12.5px; }
|
||||
#view-wartung .kb-side-alert { font-size: 13.5px; }
|
||||
#view-wartung .kb-side-btn { display: flex; align-items: center; gap: 8px; margin-top: 10px; padding: 14px 16px; border-radius: 14px; font-size: 15px; }
|
||||
#view-wartung .kb-side-btn .kb-badge { float: none; flex: none; margin: 0 0 0 auto; }
|
||||
#view-wartung .kb-btn-primary { padding: 15px 22px; font-size: 15px; }
|
||||
#view-vertraege .kb-abo { padding: 20px 18px 18px; border-radius: 20px; }
|
||||
#view-vertraege .kb-abo h3 { font-size: 22px; }
|
||||
#view-vertraege .kb-price strong, #view-vertraege .kb-hours strong { font-size: 32px; }
|
||||
#view-vertraege .kb-price span, #view-vertraege .kb-hours span, #view-vertraege .kb-sub, #view-vertraege .kb-offer-until { font-size: 14px; }
|
||||
#view-vertraege .kb-checks { gap: 9px; font-size: 14.5px; }
|
||||
#view-vertraege .kb-fine { font-size: 12.5px; }
|
||||
#view-vertraege .kb-side-alert { font-size: 13.5px; }
|
||||
#view-vertraege .kb-side-btn { display: flex; align-items: center; gap: 8px; margin-top: 10px; padding: 14px 16px; border-radius: 14px; font-size: 15px; }
|
||||
#view-vertraege .kb-side-btn .kb-badge { float: none; flex: none; margin: 0 0 0 auto; }
|
||||
#view-vertraege .kb-btn-primary { padding: 15px 22px; font-size: 15px; }
|
||||
.kb-stats { gap: 10px; }
|
||||
.kb-stat strong { font-size: 24px; }
|
||||
.abo-summary, .abo-summary tbody, .abo-summary tr, .abo-summary td { display: block; width: auto !important; }
|
||||
|
||||
Reference in new issue
Block a user