fix: Kontrast der Onboarding-Tour im Dark Mode verbessern

Backdrop mit Aussparung für den Spotlight-Bereich, damit hervorgehobene UI-Elemente
in voller Helligkeit sichtbar bleiben; Tooltip und Rahmen kontrastreicher gestaltet.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-29 18:03:43 +02:00
parent 0da855381d
commit 181cbe4895
2 changed files with 55 additions and 11 deletions
+23 -10
View File
@@ -2572,28 +2572,41 @@ html.theme-cupertino .events-scroll-container {
.app-tour-backdrop { .app-tour-backdrop {
position: absolute; position: absolute;
inset: 0; inset: 0;
background: rgba(2, 6, 23, 0.72); background: rgba(2, 6, 23, 0.62);
pointer-events: auto; pointer-events: auto;
} }
.app-tour-backdrop--cutout {
background: rgba(2, 6, 23, 0.5);
}
.app-tour-spotlight { .app-tour-spotlight {
position: fixed; position: fixed;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 0 0 9999px rgba(2, 6, 23, 0.72); border: 2px solid #38bdf8;
border: 2px solid rgba(56, 189, 248, 0.85); box-shadow:
0 0 0 1px rgba(255, 255, 255, 0.22),
0 0 32px rgba(56, 189, 248, 0.5),
0 12px 40px rgba(0, 0, 0, 0.35);
pointer-events: none; pointer-events: none;
z-index: 10001; z-index: 10001;
} }
body.app-tour-active .app-tour-target-active {
position: relative;
z-index: 10001 !important;
isolation: isolate;
}
.app-tour-tooltip { .app-tour-tooltip {
position: fixed; position: fixed;
z-index: 10002; z-index: 10002;
width: min(420px, calc(100vw - 32px)); width: min(420px, calc(100vw - 32px));
padding: 20px 20px 16px; padding: 20px 20px 16px;
border-radius: 16px; border-radius: 16px;
background: rgba(15, 23, 42, 0.96); background: #1e293b;
border: 1px solid rgba(148, 163, 184, 0.25); border: 1px solid rgba(148, 163, 184, 0.45);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.45); box-shadow: 0 24px 64px rgba(0, 0, 0, 0.65);
pointer-events: auto; pointer-events: auto;
} }
@@ -2627,7 +2640,7 @@ html.theme-cupertino .events-scroll-container {
.app-tour-progress { .app-tour-progress {
margin: 0 0 8px; margin: 0 0 8px;
font-size: 12px; font-size: 12px;
color: #64748b; color: #94a3b8;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
} }
@@ -2635,14 +2648,14 @@ html.theme-cupertino .events-scroll-container {
.app-tour-title { .app-tour-title {
margin: 0 0 8px; margin: 0 0 8px;
font-size: 20px; font-size: 20px;
color: #f8fafc; color: #ffffff;
} }
.app-tour-body { .app-tour-body {
margin: 0 0 16px; margin: 0 0 16px;
font-size: 14px; font-size: 14px;
line-height: 1.55; line-height: 1.55;
color: #cbd5e1; color: #e2e8f0;
} }
.app-tour-actions { .app-tour-actions {
@@ -2655,7 +2668,7 @@ html.theme-cupertino .events-scroll-container {
.app-tour-link { .app-tour-link {
border: none; border: none;
background: transparent; background: transparent;
color: #94a3b8; color: #cbd5e1;
font-size: 13px; font-size: 13px;
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
+32 -1
View File
@@ -15,6 +15,12 @@ interface SpotlightRect {
height: number height: number
} }
function buildCutoutClipPath(rect: SpotlightRect): string {
const right = rect.left + rect.width
const bottom = rect.top + rect.height
return `polygon(evenodd, 0 0, 100vw 0, 100vw 100vh, 0 100vh, 0 0, ${rect.left}px ${rect.top}px, ${right}px ${rect.top}px, ${right}px ${bottom}px, ${rect.left}px ${bottom}px, ${rect.left}px ${rect.top}px)`
}
export default function AppTourOverlay() { export default function AppTourOverlay() {
const { t } = useTranslation() const { t } = useTranslation()
const { const {
@@ -68,6 +74,23 @@ export default function AppTourOverlay() {
} }
}, [currentStepId, isActive]) }, [currentStepId, isActive])
useEffect(() => {
if (!isActive) return
document.body.classList.add('app-tour-active')
return () => document.body.classList.remove('app-tour-active')
}, [isActive])
useEffect(() => {
if (!isActive || !currentStepId || isCenteredTourStep(currentStepId)) return
const selector = getTourTargetSelector(currentStepId)
if (!selector) return
const el = document.querySelector(selector)
el?.classList.add('app-tour-target-active')
return () => el?.classList.remove('app-tour-target-active')
}, [currentStepId, isActive])
useEffect(() => { useEffect(() => {
if (!isActive) return if (!isActive) return
const onKeyDown = (event: KeyboardEvent) => { const onKeyDown = (event: KeyboardEvent) => {
@@ -92,9 +115,17 @@ export default function AppTourOverlay() {
} }
: { top: '20%', left: '50%', transform: 'translateX(-50%)', maxWidth: '420px' } : { top: '20%', left: '50%', transform: 'translateX(-50%)', maxWidth: '420px' }
const backdropStyle = spotlight && !centered
? { clipPath: buildCutoutClipPath(spotlight) }
: undefined
return ( return (
<div className="app-tour-root" role="dialog" aria-modal="true" aria-label={title}> <div className="app-tour-root" role="dialog" aria-modal="true" aria-label={title}>
<div className="app-tour-backdrop" onClick={skipTour} /> <div
className={`app-tour-backdrop${spotlight && !centered ? ' app-tour-backdrop--cutout' : ''}`}
style={backdropStyle}
onClick={skipTour}
/>
{!centered && spotlight && ( {!centered && spotlight && (
<div <div