Initial commit: Lagerbestand Blazor Projekt

This commit is contained in:
spaethf committed 2026-09-21 21:28:23 +02:00
commit cba9414e92
105 files changed
+36431

No files matched your search

File diff suppressed because it is too large. Load diff
+7
View File
@@ -0,0 +1,7 @@
@charset "UTF-8";/*!
* Bootstrap v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){leLine truncated
/*# sourceMappingURL=bootstrap.min.css.map */
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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 truncated
+217
View File
@@ -0,0 +1,217 @@
/*
* Reifen Späth – App Interop styles
* Reconnect overlay + idle-lock overlay.
* Uses global design tokens from app.css.
*/
/* =============================================
Blazor reconnect overlay (replaces default)
The framework toggles styles on:
#components-reconnect-modal
via classes: components-reconnect-show / hide / failed / rejected
============================================= */
#components-reconnect-modal {
display: none;
position: fixed;
inset: 0;
z-index: 2147483000;
align-items: center;
justify-content: center;
padding: var(--space-4, 1rem);
background: rgba(0, 0, 0, 0.78);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
font-family: var(--font-family-base, sans-serif);
color: var(--text-primary, #fff);
}
#components-reconnect-modal.components-reconnect-show,
#components-reconnect-modal.components-reconnect-failed,
#components-reconnect-modal.components-reconnect-rejected {
display: flex;
}
#components-reconnect-modal .reconnect-dialog {
background: var(--surface-primary, rgba(28, 28, 30, 0.95));
border: 0.5px solid var(--border-default, rgba(255, 255, 255, 0.1));
border-radius: var(--radius-xl, 20px);
box-shadow: var(--shadow-xl, 0 20px 40px rgba(0, 0, 0, 0.5));
padding: var(--space-6, 1.5rem);
width: 100%;
max-width: 420px;
text-align: center;
}
#components-reconnect-modal .reconnect-icon {
width: 56px;
height: 56px;
margin: 0 auto var(--space-4, 1rem);
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(220, 38, 38, 0.15);
color: var(--color-primary-light, #ef4444);
}
#components-reconnect-modal .reconnect-icon svg {
animation: reconnect-spin 1.4s linear infinite;
}
@keyframes reconnect-spin {
to { transform: rotate(360deg); }
}
#components-reconnect-modal h2 {
margin: 0 0 var(--space-2, 0.5rem);
font-size: var(--text-xl, 1.25rem);
font-family: var(--font-family-base, sans-serif);
font-weight: var(--font-weight-semibold, 600);
}
#components-reconnect-modal p {
margin: 0 0 var(--space-5, 1.25rem);
color: var(--text-secondary, rgba(255, 255, 255, 0.7));
font-size: var(--text-sm, 0.875rem);
line-height: var(--line-height-relaxed, 1.6);
}
#components-reconnect-modal .reconnect-actions {
display: flex;
flex-direction: column;
gap: var(--space-3, 0.75rem);
}
#components-reconnect-modal .reconnect-text-show,
#components-reconnect-modal .reconnect-text-failed,
#components-reconnect-modal .reconnect-text-rejected,
#components-reconnect-modal .reconnect-actions-failed {
display: none;
}
#components-reconnect-modal.components-reconnect-show .reconnect-text-show { display: block; }
#components-reconnect-modal.components-reconnect-failed .reconnect-text-failed,
#components-reconnect-modal.components-reconnect-failed .reconnect-actions-failed { display: block; }
#components-reconnect-modal.components-reconnect-failed .reconnect-actions-failed { display: flex; flex-direction: column; gap: var(--space-3, 0.75rem); }
#components-reconnect-modal.components-reconnect-rejected .reconnect-text-rejected,
#components-reconnect-modal.components-reconnect-rejected .reconnect-actions-failed { display: block; }
#components-reconnect-modal.components-reconnect-rejected .reconnect-actions-failed { display: flex; flex-direction: column; gap: var(--space-3, 0.75rem); }
/* Hide default retry countdown */
#components-reconnect-modal .components-reconnect-current-attempt,
#components-reconnect-modal .components-reconnect-max-retries {
color: var(--text-tertiary, rgba(255, 255, 255, 0.5));
font-size: var(--text-xs, 0.75rem);
}
#components-reconnect-modal button {
min-height: var(--touch-target, 44px);
padding: var(--space-3, 0.75rem) var(--space-5, 1.25rem);
border-radius: var(--radius-md, 10px);
border: none;
font-family: var(--font-family-base, sans-serif);
font-size: var(--text-sm, 0.875rem);
font-weight: var(--font-weight-semibold, 600);
cursor: pointer;
transition: all var(--duration-fast, 150ms) var(--ease-out, ease);
}
#components-reconnect-modal .reconnect-retry {
background: linear-gradient(180deg, var(--color-primary-light, #ef4444) 0%, var(--color-primary, #dc2626) 100%);
color: var(--text-primary, #fff);
box-shadow: var(--shadow-btn-primary, 0 4px 12px rgba(220, 38, 38, 0.3));
}
#components-reconnect-modal .reconnect-reload {
background: rgba(255, 255, 255, 0.08);
color: var(--text-primary, #fff);
border: 0.5px solid var(--border-default, rgba(255, 255, 255, 0.1));
}
#components-reconnect-modal button:hover:not(:disabled) {
transform: translateY(-1px);
}
/* =============================================
Idle lock overlay
============================================= */
#app-idle-overlay {
display: none;
position: fixed;
inset: 0;
z-index: 2147482000;
align-items: center;
justify-content: center;
padding: var(--space-4, 1rem);
background: rgba(0, 0, 0, 0.82);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
font-family: var(--font-family-base, sans-serif);
color: var(--text-primary, #fff);
animation: fadeIn var(--duration-normal, 250ms) var(--ease-out, ease);
}
#app-idle-overlay.visible {
display: flex;
}
#app-idle-overlay .app-idle-dialog {
background: var(--surface-primary, rgba(28, 28, 30, 0.95));
border: 0.5px solid var(--border-default, rgba(255, 255, 255, 0.1));
border-radius: var(--radius-xl, 20px);
box-shadow: var(--shadow-xl, 0 20px 40px rgba(0, 0, 0, 0.5));
padding: var(--space-6, 1.5rem);
width: 100%;
max-width: 420px;
text-align: center;
}
#app-idle-overlay .app-idle-icon {
width: 64px;
height: 64px;
margin: 0 auto var(--space-4, 1rem);
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: rgba(251, 191, 36, 0.15);
color: var(--color-warning, #fbbf24);
}
#app-idle-overlay h2 {
margin: 0 0 var(--space-2, 0.5rem);
font-size: var(--text-xl, 1.25rem);
font-weight: var(--font-weight-semibold, 600);
}
#app-idle-overlay p {
margin: 0 0 var(--space-5, 1.25rem);
color: var(--text-secondary, rgba(255, 255, 255, 0.7));
font-size: var(--text-sm, 0.875rem);
line-height: var(--line-height-relaxed, 1.6);
}
#app-idle-overlay .app-idle-resume {
min-height: var(--touch-target, 44px);
width: 100%;
padding: var(--space-3, 0.75rem) var(--space-5, 1.25rem);
border-radius: var(--radius-md, 10px);
border: none;
background: linear-gradient(180deg, var(--color-primary-light, #ef4444) 0%, var(--color-primary, #dc2626) 100%);
color: var(--text-primary, #fff);
font-family: var(--font-family-base, sans-serif);
font-size: var(--text-base, 1rem);
font-weight: var(--font-weight-semibold, 600);
cursor: pointer;
box-shadow: var(--shadow-btn-primary, 0 4px 12px rgba(220, 38, 38, 0.3));
transition: transform var(--duration-fast, 150ms) var(--ease-out, ease);
}
#app-idle-overlay .app-idle-resume:hover {
transform: translateY(-1px);
}
#app-idle-overlay .app-idle-resume:focus-visible {
outline: 3px solid rgba(220, 38, 38, 0.5);
outline-offset: 2px;
}
+7
View File
@@ -0,0 +1,7 @@
@charset "UTF-8";/*!
* Bootstrap v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/:root{--bs-blue:#0d6efd;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#dc3545;--bs-orange:#fd7e14;--bs-yellow:#ffc107;--bs-green:#198754;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-white:#fff;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#e9ecef;--bs-gray-300:#dee2e6;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#6c757d;--bs-gray-700:#495057;--bs-gray-800:#343a40;--bs-gray-900:#212529;--bs-primary:#0d6efd;--bs-secondary:#6c757d;--bs-success:#198754;--bs-info:#0dcaf0;--bs-warning:#ffc107;--bs-danger:#dc3545;--bs-light:#f8f9fa;--bs-dark:#212529;--bs-primary-rgb:13,110,253;--bs-secondary-rgb:108,117,125;--bs-success-rgb:25,135,84;--bs-info-rgb:13,202,240;--bs-warning-rgb:255,193,7;--bs-danger-rgb:220,53,69;--bs-light-rgb:248,249,250;--bs-dark-rgb:33,37,41;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-body-rgb:33,37,41;--bs-font-sans-serif:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:400;--bs-body-line-height:1.5;--bs-body-color:#212529;--bs-body-bg:#fff}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){.h1,h1{font-size:2.5rem}}.h2,h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h2,h2{font-size:2rem}}.h3,h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h3,h3{font-size:1.75rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){leLine truncated
/*# sourceMappingURL=bootstrap.min.css.map */
@@ -0,0 +1 @@
{"version":3,"sources":["../../scss/bootstrap.scss","../../scss/_root.scss","../../scss/_reboot.scss","dist/css/bootstrap.css","../../scss/vendor/_rfs.scss","../../scss/mixins/_border-radius.scss","../../scss/_type.scss","../../scss/mixins/_lists.scss","../../scss/_images.scss","../../scss/mixins/_image.scss","../../scss/_containers.scss","../../scss/mixins/_container.scss","../../scss/mixins/_breakpoints.scss","../../scss/_grid.scss","../../scss/mixins/_grid.scss","../../scss/_tables.scss","../../scss/mixins/_table-variants.scss","../../scss/forms/_labels.scss","../../scss/forms/_form-text.scss","../../scss/forms/_form-control.scss","../../scss/mixins/_transition.scss","../../scss/mixins/_gradients.scss","../../scss/forms/_form-select.scss","../../scss/forms/_form-check.scss","../../scss/forms/_form-range.scss","../../scss/forms/_floating-labels.scss","../../scss/forms/_input-group.scss","../../scss/mixins/_forms.scss","../../scss/_buttons.scss","../../scss/mixins/_buttons.scss","../../scss/_transitions.scss","../../scss/_dropdown.scss","../../scss/mixins/_caret.scss","../../scss/_button-group.scss","../../scss/_nav.scss","../../scss/_navbar.scss","../../scss/_card.scss","../../scss/_accordion.scss","../../scss/_breadcrumb.scss","../../scss/_pagination.scss","../../scss/mixins/_pagination.scss","../../scss/_badge.scss","../../scss/_alert.scss","../../scss/mixins/_alert.scss","../../scss/_progress.scss","../../scss/_list-group.scss","../../scss/mixins/_list-group.scss","../../scss/_close.scss","../../scss/_toasts.scss","../../scss/_modal.scss","../../scss/mixins/_backdrop.scss","../../scss/_tooltip.scss","../../scss/mixins/_reset-text.scss","../../scss/_popover.scss","../../scss/_carousel.scss","../../scss/mixins/_clearfix.scss","../../scss/_spinners.scss","../../scss/_offcanvas.scss","../../scss/_placeholders.scss","../../scss/helpers/_colored-links.scss","../../scss/helpers/_ratio.scss","../../scss/helpers/_position.scss","../../scss/helpers/_stacks.scss","../../scss/helpers/_visually-hidden.scss","../../scss/mixins/_visually-hidden.scss","../../scss/helpers/_stretched-link.scss","../../scss/helpers/_text-truncation.scss","../../scss/mixins/_text-truncate.scss","../../scss/helpers/_vr.scss","../../scss/mixins/_utilities.scss","../../scss/utilities/_api.scss"],"names":[],"mappings":"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 truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

@@ -0,0 +1 @@
google-site-verification: google6d5a1b5c60a38816.html
+334
View File
@@ -0,0 +1,334 @@
/*
* Reifen Späth – App Interop
* =============================================================
* Browser-side helpers for long-duration usage:
* - Visibility refresh (tab re-activated after N minutes)
* - Idle-lock overlay (confirm-to-continue after N minutes)
* - beforeunload warning when a form has unsaved draft data
* - sessionStorage draft helpers (per-tab)
* - focus-trap + Escape + click-outside helpers for modals/menus
* - Custom Blazor reconnect UI wiring (handled via CSS selectors
* on #components-reconnect-modal in App.razor)
* =============================================================
*/
(function () {
'use strict';
// ---------------------------------------------------------
// sessionStorage drafts (per-browser, per-tab)
// ---------------------------------------------------------
const DRAFT_PREFIX = 'rs-draft:';
window.appInterop = window.appInterop || {};
window.appInterop.saveDraft = function (key, json) {
try {
if (json == null) {
sessionStorage.removeItem(DRAFT_PREFIX + key);
return true;
}
sessionStorage.setItem(DRAFT_PREFIX + key, json);
return true;
} catch (e) {
console.warn('[appInterop] saveDraft failed', e);
return false;
}
};
window.appInterop.loadDraft = function (key) {
try {
return sessionStorage.getItem(DRAFT_PREFIX + key);
} catch (e) {
return null;
}
};
window.appInterop.clearDraft = function (key) {
try {
sessionStorage.removeItem(DRAFT_PREFIX + key);
} catch (e) { /* ignore */ }
};
// ---------------------------------------------------------
// beforeunload: warn user when draft flag is set
// ---------------------------------------------------------
let hasUnsavedChanges = false;
window.appInterop.setUnsaved = function (value) {
hasUnsavedChanges = !!value;
};
window.addEventListener('beforeunload', function (e) {
if (hasUnsavedChanges) {
e.preventDefault();
// Most browsers ignore the custom message and show a generic one.
e.returnValue = '';
return '';
}
});
// ---------------------------------------------------------
// Visibility refresh: fire .NET callback when tab returns
// after being hidden for more than `thresholdSeconds`.
//
// One .NET target per page; replacing cancels the previous.
// ---------------------------------------------------------
let visibilityHiddenAt = null;
let visibilityTarget = null; // DotNetObjectReference
let visibilityMethod = null;
let visibilityThresholdSec = 120;
function onVisibilityChange() {
if (document.visibilityState === 'hidden') {
visibilityHiddenAt = Date.now();
} else if (document.visibilityState === 'visible') {
if (!visibilityTarget || !visibilityHiddenAt) return;
const hiddenFor = (Date.now() - visibilityHiddenAt) / 1000;
visibilityHiddenAt = null;
if (hiddenFor >= visibilityThresholdSec) {
try {
visibilityTarget.invokeMethodAsync(visibilityMethod, Math.round(hiddenFor));
} catch (e) {
console.warn('[appInterop] visibility invoke failed', e);
}
}
}
}
document.addEventListener('visibilitychange', onVisibilityChange);
window.appInterop.registerVisibilityRefresh = function (dotNetRef, methodName, thresholdSeconds) {
visibilityTarget = dotNetRef;
visibilityMethod = methodName || 'OnVisibilityReturn';
visibilityThresholdSec = thresholdSeconds > 0 ? thresholdSeconds : 120;
visibilityHiddenAt = null;
};
window.appInterop.unregisterVisibilityRefresh = function () {
visibilityTarget = null;
visibilityMethod = null;
visibilityHiddenAt = null;
};
// ---------------------------------------------------------
// Idle lock overlay (per-tab).
// Fires after N minutes of no user input; requires a click
// on the "Weiter" button to resume (no password — matches
// confirmed UX decision).
// ---------------------------------------------------------
const IDLE_EVENTS = ['mousemove', 'mousedown', 'keydown', 'touchstart', 'scroll', 'wheel'];
let idleTimerId = null;
let idleTimeoutMs = 60 * 60 * 1000; // 60 min default
let idleActive = false;
let idleLocked = false;
function resetIdleTimer() {
if (!idleActive || idleLocked) return;
if (idleTimerId) clearTimeout(idleTimerId);
idleTimerId = setTimeout(triggerIdleLock, idleTimeoutMs);
}
function triggerIdleLock() {
idleLocked = true;
const overlay = document.getElementById('app-idle-overlay');
if (overlay) {
overlay.classList.add('visible');
const btn = overlay.querySelector('.app-idle-resume');
if (btn) {
setTimeout(function () { try { btn.focus(); } catch (e) { } }, 50);
}
}
}
function releaseIdleLock() {
idleLocked = false;
const overlay = document.getElementById('app-idle-overlay');
if (overlay) overlay.classList.remove('visible');
resetIdleTimer();
}
window.appInterop.startIdleWatcher = function (idleMinutes) {
const minutes = parseInt(idleMinutes, 10);
if (!minutes || minutes <= 0) {
window.appInterop.stopIdleWatcher();
return;
}
idleTimeoutMs = minutes * 60 * 1000;
if (!idleActive) {
idleActive = true;
IDLE_EVENTS.forEach(function (ev) {
window.addEventListener(ev, resetIdleTimer, { passive: true });
});
const btn = document.querySelector('#app-idle-overlay .app-idle-resume');
if (btn && !btn.dataset.bound) {
btn.dataset.bound = '1';
btn.addEventListener('click', releaseIdleLock);
}
}
resetIdleTimer();
};
window.appInterop.stopIdleWatcher = function () {
if (!idleActive) return;
idleActive = false;
if (idleTimerId) clearTimeout(idleTimerId);
idleTimerId = null;
IDLE_EVENTS.forEach(function (ev) {
window.removeEventListener(ev, resetIdleTimer);
});
releaseIdleLock();
};
// Auto-load session settings and start watcher once DOM is ready.
// Only activates if the body has [data-authenticated="true"], which
// MainLayout sets when a user is logged in.
function tryAutoStartIdle() {
if (document.body && document.body.dataset.authenticated === 'true') {
fetch('/api/session-settings', { credentials: 'same-origin' })
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (s) {
if (s && s.idleTimeoutMinutes > 0) {
window.appInterop.startIdleWatcher(s.idleTimeoutMinutes);
}
})
.catch(function () { /* non-fatal */ });
}
}
// Observe auth marker on <body> so the watcher (re)starts after login/logout.
document.addEventListener('DOMContentLoaded', function () {
tryAutoStartIdle();
if (document.body) {
const mo = new MutationObserver(function () { tryAutoStartIdle(); });
mo.observe(document.body, { attributes: true, attributeFilter: ['data-authenticated'] });
}
});
// ---------------------------------------------------------
// Click-outside for user-menu dropdown and mobile-menu.
// The Blazor component sets [data-click-outside-id="..."] on
// the open panel and exposes a .NET method we call back.
// ---------------------------------------------------------
let clickOutsideTarget = null;
let clickOutsideMethod = null;
let clickOutsideContainerSelector = null;
function onDocumentClick(e) {
if (!clickOutsideTarget || !clickOutsideContainerSelector) return;
const container = document.querySelector(clickOutsideContainerSelector);
if (!container) return;
if (!container.contains(e.target)) {
try {
clickOutsideTarget.invokeMethodAsync(clickOutsideMethod);
} catch (err) { /* circuit may be reconnecting */ }
}
}
window.appInterop.registerClickOutside = function (dotNetRef, methodName, containerSelector) {
clickOutsideTarget = dotNetRef;
clickOutsideMethod = methodName;
clickOutsideContainerSelector = containerSelector;
// Use capture phase so stopPropagation inside the panel still works for us.
document.addEventListener('mousedown', onDocumentClick, true);
document.addEventListener('touchstart', onDocumentClick, { capture: true, passive: true });
};
window.appInterop.unregisterClickOutside = function () {
clickOutsideTarget = null;
clickOutsideMethod = null;
clickOutsideContainerSelector = null;
document.removeEventListener('mousedown', onDocumentClick, true);
document.removeEventListener('touchstart', onDocumentClick, { capture: true });
};
// ---------------------------------------------------------
// Focus trap for modals (autofocus + Tab cycle + Escape).
// Caller passes the container selector; we remember the
// previously-focused element and restore it on release.
// ---------------------------------------------------------
const FOCUSABLE = [
'a[href]', 'area[href]', 'input:not([disabled])', 'select:not([disabled])',
'textarea:not([disabled])', 'button:not([disabled])', 'iframe',
'object', 'embed', '[contenteditable]', '[tabindex]:not([tabindex="-1"])'
].join(',');
let trapState = null;
function onTrapKey(e) {
if (!trapState) return;
if (e.key === 'Escape' && trapState.escapeMethod) {
try { trapState.dotNetRef.invokeMethodAsync(trapState.escapeMethod); } catch (err) { }
return;
}
if (e.key !== 'Tab') return;
const container = document.querySelector(trapState.selector);
if (!container) return;
const focusables = Array.prototype.filter.call(
container.querySelectorAll(FOCUSABLE),
function (el) { return el.offsetParent !== null; });
if (focusables.length === 0) return;
const first = focusables[0];
const last = focusables[focusables.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
window.appInterop.trapFocus = function (selector, dotNetRef, escapeMethod) {
if (trapState) { try { document.removeEventListener('keydown', onTrapKey, true); } catch (e) { } }
trapState = {
selector: selector,
dotNetRef: dotNetRef || null,
escapeMethod: escapeMethod || null,
previouslyFocused: document.activeElement
};
document.addEventListener('keydown', onTrapKey, true);
// Autofocus the first tabbable element.
setTimeout(function () {
const container = document.querySelector(selector);
if (!container) return;
const focusables = Array.prototype.filter.call(
container.querySelectorAll(FOCUSABLE),
function (el) { return el.offsetParent !== null; });
if (focusables.length > 0) {
try { focusables[0].focus(); } catch (e) { }
}
}, 30);
};
window.appInterop.releaseFocusTrap = function () {
document.removeEventListener('keydown', onTrapKey, true);
if (trapState && trapState.previouslyFocused && typeof trapState.previouslyFocused.focus === 'function') {
try { trapState.previouslyFocused.focus(); } catch (e) { }
}
trapState = null;
};
// ---------------------------------------------------------
// Blazor reconnect UI — replace the default overlay.
// App.razor provides #components-reconnect-modal with German
// copy; Blazor sets body[data-reconnect-state] automatically
// via the official contract (components-reconnect-show etc.).
// We just add a manual reload button handler.
// ---------------------------------------------------------
document.addEventListener('DOMContentLoaded', function () {
const reload = document.querySelector('#components-reconnect-modal .reconnect-reload');
if (reload) {
reload.addEventListener('click', function () { location.reload(); });
}
const retry = document.querySelector('#components-reconnect-modal .reconnect-retry');
if (retry) {
retry.addEventListener('click', function () {
if (window.Blazor && typeof window.Blazor.reconnect === 'function') {
window.Blazor.reconnect();
} else {
location.reload();
}
});
}
});
})();
+25
View File
@@ -0,0 +1,25 @@
# Robots.txt for Reifen Späth - www.reifenspaeth.de
# https://www.robotstxt.org/robotstxt.html
User-agent: *
# Allow public pages
Allow: /
Allow: /impressum
Allow: /datenschutz
# Disallow internal/admin pages
Disallow: /login
Disallow: /tire-storage
Disallow: /tire-checkin
Disallow: /tire-checkout
Disallow: /customers
Disallow: /storage-locations
Disallow: /users
Disallow: /status
# Allow required rendering assets so search engines can render the page correctly
Allow: /_framework/
Allow: /_content/
Sitemap: https://www.reifenspaeth.de/sitemap.xml
+31
View File
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<!-- Homepage - highest priority -->
<url>
<loc>https://www.reifenspaeth.de/</loc>
<lastmod>2026-05-11</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<!-- Impressum - legal page -->
<url>
<loc>https://www.reifenspaeth.de/impressum</loc>
<lastmod>2026-05-11</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<!-- Datenschutz - legal page -->
<url>
<loc>https://www.reifenspaeth.de/datenschutz</loc>
<lastmod>2026-05-11</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
</urlset>
Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB