Add interactive tutorial system for calibration and device cards
Some checks failed
Validate / validate (push) Failing after 8s
Some checks failed
Validate / validate (push) Failing after 8s
Generic tutorial engine supports absolute (modal) and fixed (viewport) positioning modes with spotlight backdrop, pulsing ring, and tooltip. Calibration tutorial covers LED count, corner, direction, offset, span, test, and toggle inputs. Device tutorial walks through card controls. Auto-triggers on first calibration open and first device add. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -206,7 +206,7 @@ section {
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
padding: 12px 20px 20px;
|
||||
position: relative;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
@@ -215,6 +215,31 @@ section {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.card-tutorial-btn {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
background: none;
|
||||
border: 1.5px solid var(--border-color);
|
||||
color: var(--text-muted, #777);
|
||||
font-size: 0.7rem;
|
||||
font-weight: bold;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
transition: color 0.2s, background 0.2s, border-color 0.2s;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-tutorial-btn:hover {
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.card-remove-btn {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
@@ -242,7 +267,7 @@ section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 10px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
|
||||
@@ -1368,3 +1393,202 @@ input:-webkit-autofill:focus {
|
||||
}
|
||||
}
|
||||
|
||||
/* Tutorial System */
|
||||
.tutorial-trigger-btn {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid var(--primary-color);
|
||||
background: transparent;
|
||||
color: var(--primary-color);
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-left: auto;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tutorial-trigger-btn:hover {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
#calibration-modal .modal-body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tutorial-overlay {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.tutorial-overlay.active {
|
||||
display: block;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.tutorial-backdrop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
transition: clip-path 0.3s ease;
|
||||
}
|
||||
|
||||
.tutorial-ring {
|
||||
position: absolute;
|
||||
border: 2px solid var(--primary-color);
|
||||
border-radius: 6px;
|
||||
pointer-events: none;
|
||||
transition: all 0.3s ease;
|
||||
animation: tutorial-pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes tutorial-pulse {
|
||||
0%, 100% { box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.6); }
|
||||
50% { box-shadow: 0 0 0 6px rgba(76, 175, 80, 0); }
|
||||
}
|
||||
|
||||
.tutorial-tooltip {
|
||||
position: absolute;
|
||||
width: 260px;
|
||||
background: var(--card-bg);
|
||||
border: 2px solid var(--primary-color);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
||||
z-index: 102;
|
||||
pointer-events: auto;
|
||||
animation: tutorial-tooltip-in 0.25s ease-out;
|
||||
}
|
||||
|
||||
@keyframes tutorial-tooltip-in {
|
||||
from { opacity: 0; transform: translateY(-8px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.tutorial-tooltip-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.tutorial-step-counter {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.tutorial-close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #777;
|
||||
font-size: 1.3rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
transition: color 0.2s, background 0.2s;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.tutorial-close-btn:hover {
|
||||
color: var(--text-color);
|
||||
background: rgba(128, 128, 128, 0.15);
|
||||
}
|
||||
|
||||
.tutorial-tooltip-text {
|
||||
margin: 0;
|
||||
padding: 12px;
|
||||
line-height: 1.5;
|
||||
color: var(--text-color);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tutorial-tooltip-nav {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.tutorial-prev-btn,
|
||||
.tutorial-next-btn {
|
||||
flex: 1;
|
||||
padding: 6px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.tutorial-prev-btn {
|
||||
background: var(--border-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.tutorial-next-btn {
|
||||
background: var(--primary-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tutorial-prev-btn:hover:not(:disabled),
|
||||
.tutorial-next-btn:hover:not(:disabled) {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.tutorial-prev-btn:disabled,
|
||||
.tutorial-next-btn:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.tutorial-target {
|
||||
position: relative;
|
||||
z-index: 101 !important;
|
||||
}
|
||||
|
||||
/* Fixed (viewport-level) tutorial overlay for device cards */
|
||||
.tutorial-overlay-fixed {
|
||||
position: fixed;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.tutorial-overlay-fixed .tutorial-backdrop {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.tutorial-overlay-fixed .tutorial-ring {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.tutorial-overlay-fixed .tutorial-tooltip {
|
||||
position: absolute;
|
||||
z-index: 10002;
|
||||
animation: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* target z-index for fixed overlay is set inline via JS (target is outside overlay DOM) */
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user