Update design system with centered layout, PIN input, floating back button
Add true-center layout pattern, back-wrapper for floating navigation, PIN digit input component with all states, and centered page demo with HomeKit logo example. Document PIN input JS pattern.
This commit is contained in:
+214
-2
@@ -88,8 +88,8 @@
|
||||
2. PAGE LAYOUTS
|
||||
============================================================ */
|
||||
|
||||
/* --- 2a. Centered layout (index.html, homekit.html) ---
|
||||
For single-purpose pages: one form, one action. */
|
||||
/* --- 2a. Centered layout (index.html) ---
|
||||
For entry pages: one form, one action. Content near top. */
|
||||
.screen-centered {
|
||||
min-height: 100vh;
|
||||
padding: 1.5rem;
|
||||
@@ -110,6 +110,43 @@
|
||||
.container-narrow { max-width: 540px; }
|
||||
}
|
||||
|
||||
/* --- 2a-alt. True-centered layout (homekit.html) ---
|
||||
For single-action pages: content vertically centered on screen.
|
||||
Back button floats outside the container via .back-wrapper. */
|
||||
.screen-true-center {
|
||||
min-height: 100vh;
|
||||
padding: 1.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
animation: fadeIn var(--transition-base);
|
||||
}
|
||||
|
||||
.container-true-center {
|
||||
max-width: 480px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.screen-true-center { padding: 3rem 1.5rem; }
|
||||
.container-true-center { max-width: 540px; }
|
||||
}
|
||||
|
||||
/* --- 2e. Floating back button (for centered layouts) ---
|
||||
Positioned at top, horizontally aligned wider than container
|
||||
so it sits outside the content area. */
|
||||
.back-wrapper {
|
||||
position: absolute; top: 1.5rem;
|
||||
left: 50%; transform: translateX(-50%);
|
||||
width: 100%; max-width: 600px;
|
||||
padding: 0 1.5rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.back-wrapper { max-width: 660px; }
|
||||
}
|
||||
|
||||
/* --- 2b. Standard layout (most pages) ---
|
||||
For content pages with back button and scrollable content. */
|
||||
.screen {
|
||||
@@ -451,6 +488,70 @@
|
||||
.toggle.on::after { transform: translateX(16px); }
|
||||
|
||||
|
||||
/* --- 5i. PIN digit input (homekit.html) --- */
|
||||
.pin-row {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.pin-group { display: flex; gap: 0.375rem; }
|
||||
|
||||
.pin-separator {
|
||||
font-size: 1.5rem; font-weight: 300;
|
||||
color: var(--text-tertiary);
|
||||
padding: 0 0.5rem;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.pin-digit {
|
||||
width: 57px; height: 69px;
|
||||
background: var(--bg-secondary);
|
||||
border: 2px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
color: var(--text-primary);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 1.375rem; font-weight: 600;
|
||||
text-align: center;
|
||||
outline: none;
|
||||
transition: all var(--transition-fast);
|
||||
caret-color: var(--purple-primary);
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.pin-digit::-webkit-inner-spin-button,
|
||||
.pin-digit::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none; margin: 0;
|
||||
}
|
||||
|
||||
.pin-digit:focus {
|
||||
border-color: var(--purple-primary);
|
||||
box-shadow: 0 0 0 3px var(--purple-glow);
|
||||
}
|
||||
|
||||
.pin-digit.filled {
|
||||
border-color: var(--purple-light);
|
||||
background: rgba(139, 92, 246, 0.06);
|
||||
}
|
||||
|
||||
.pin-digit.error {
|
||||
border-color: var(--error);
|
||||
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2);
|
||||
animation: shake 0.4s ease;
|
||||
}
|
||||
|
||||
.pin-digit.success {
|
||||
border-color: var(--success);
|
||||
box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.2);
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
.pin-digit { width: 36px; height: 48px; font-size: 1.125rem; }
|
||||
.pin-separator { padding: 0 0.25rem; font-size: 1.25rem; }
|
||||
.pin-group { gap: 0.25rem; }
|
||||
}
|
||||
|
||||
|
||||
/* ============================================================
|
||||
6. TOOLTIPS & INFO ICONS
|
||||
============================================================ */
|
||||
@@ -1397,6 +1498,46 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== PIN INPUT ==================== -->
|
||||
<div class="ds-section">
|
||||
<div class="ds-title">4b. PIN Digit Input</div>
|
||||
<div class="ds-subtitle">Segmented code entry (homekit.html pairing)</div>
|
||||
|
||||
<div class="ds-demo">
|
||||
<div class="ds-label">PIN Input (3-2-3 format)</div>
|
||||
<div class="pin-row" style="margin-bottom:1.5rem;">
|
||||
<div class="pin-group">
|
||||
<input type="text" class="pin-digit" value="1" maxlength="1" readonly>
|
||||
<input type="text" class="pin-digit" value="2" maxlength="1" readonly>
|
||||
<input type="text" class="pin-digit filled" value="3" maxlength="1" readonly>
|
||||
</div>
|
||||
<span class="pin-separator">-</span>
|
||||
<div class="pin-group">
|
||||
<input type="text" class="pin-digit filled" value="4" maxlength="1" readonly>
|
||||
<input type="text" class="pin-digit" maxlength="1" readonly>
|
||||
</div>
|
||||
<span class="pin-separator">-</span>
|
||||
<div class="pin-group">
|
||||
<input type="text" class="pin-digit" maxlength="1" readonly>
|
||||
<input type="text" class="pin-digit" maxlength="1" readonly>
|
||||
<input type="text" class="pin-digit" maxlength="1" readonly>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ds-label">States</div>
|
||||
<div class="ds-inline">
|
||||
<input type="text" class="pin-digit" value="" maxlength="1" readonly style="flex:none;">
|
||||
<span style="font-size:0.625rem; color:var(--text-tertiary);">empty</span>
|
||||
<input type="text" class="pin-digit filled" value="5" maxlength="1" readonly style="flex:none;">
|
||||
<span style="font-size:0.625rem; color:var(--text-tertiary);">filled</span>
|
||||
<input type="text" class="pin-digit error" value="9" maxlength="1" readonly style="flex:none;">
|
||||
<span style="font-size:0.625rem; color:var(--text-tertiary);">error</span>
|
||||
<input type="text" class="pin-digit success" value="7" maxlength="1" readonly style="flex:none;">
|
||||
<span style="font-size:0.625rem; color:var(--text-tertiary);">success</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== BADGES & TAGS ==================== -->
|
||||
<div class="ds-section">
|
||||
<div class="ds-title">5. Badges & Tags</div>
|
||||
@@ -1800,6 +1941,37 @@ cameras:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== CENTERED PAGE PATTERN ==================== -->
|
||||
<div class="ds-section">
|
||||
<div class="ds-title">15. Centered Page Pattern</div>
|
||||
<div class="ds-subtitle">True-center layout with floating back button (homekit.html)</div>
|
||||
|
||||
<div class="ds-demo" style="position:relative; min-height:300px; display:flex; align-items:center; justify-content:center;">
|
||||
<!-- Floating back button outside container -->
|
||||
<div style="position:absolute; top:1rem; left:1rem;">
|
||||
<button class="btn-back" style="margin:0; padding:0.5rem 0;">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"><path d="M12 4L6 10l6 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Centered content -->
|
||||
<div style="text-align:center; max-width:320px;">
|
||||
<div style="margin-bottom:1.5rem;">
|
||||
<svg style="width:48px; height:48px; margin:0 auto 0.5rem; display:block; filter:drop-shadow(0 4px 12px rgba(255, 171, 31, 0.3));" viewBox="100 120 824 780" fill="none">
|
||||
<path fill="#FA9012" d="M883.2,413.1l-70.4-55.6V231.1c0-8.6-3.4-11-9.5-11h-64.4c-7,0-11.3,1.4-11.3,11v59.1C634.5,216.7,533.6,137,529.8,134c-7.6-6-12.3-7.6-17.8-7.6c-5.4,0-10.1,1.6-17.8,7.6c-7.6,6-343.2,271.1-353.4,279.1c-12.4,9.8-8.9,23.9,4.9,23.9h65.5v355.6c0,23,9.2,32.2,31.1,32.2h539.4c21.9,0,31.1-9.2,31.1-32.2V436.9h65.5C892.1,436.9,895.6,422.9,883.2,413.1z"/>
|
||||
<path fill="#FFAB1F" d="M739.6,371.1L527.1,203.3c-5.6-4.4-10.6-6.3-15.1-6.3c-4.6,0-9.5,1.9-15.1,6.4L284.4,371.1c-9.6,7.6-18.1,19.9-18.1,39.2v332.3c0,15.9,8.2,26.9,24.8,26.9h441.7c16.6,0,24.8-11,24.8-26.9V410.3C757.6,391,749.2,378.7,739.6,371.1z"/>
|
||||
<path fill="#FFBE41" d="M688.9,402.5c-5.8-4.5-160.3-126.6-164.4-129.8c-4.1-3.3-8.5-4.9-12.5-4.9c-4,0-8.4,1.7-12.5,4.9c-4.1,3.3-158.6,125.3-164.4,129.8c-10.2,8.1-13.6,16.4-13.6,30.7v259.5c0,14.8,8.4,21.7,20.7,21.7h339.7c12.3,0,20.7-6.9,20.7-21.7V433.2C702.5,418.9,699.1,410.6,688.9,402.5z"/>
|
||||
<path fill="#FFD260" d="M638.3,434c-6-4.8-113.2-89.4-116.4-91.9c-2.8-2.4-6.3-3.7-9.9-3.8c-3.5,0-6.7,1.3-9.9,3.8S391.6,429.2,385.7,434c-9.1,7.3-9.1,13.9-9.1,22.2v186.6c0,11.9,6.6,16.5,15.6,16.5h239.5c9,0,15.6-4.6,15.6-16.5V456.2C647.4,447.8,647.4,441.2,638.3,434z"/>
|
||||
<path fill="#FFE780" d="M512,604.1h69.2c6.4,0,11-2.1,11-11.2V479.1c0-6.4-2.9-12.6-7.8-16.6c-2.8-2.3-63-49.4-65.1-51.1c-4.2-3.5-10.4-3.5-14.6,0c-2.1,1.7-62.3,48.8-65.1,51.1c-5,4.1-7.9,10.2-7.8,16.6v113.8c0,9.2,4.6,11.2,11,11.2L512,604.1z"/>
|
||||
</svg>
|
||||
<div style="font-size:1.25rem; font-weight:600; color:var(--text-primary);">Apple HomeKit</div>
|
||||
</div>
|
||||
<div style="font-size:0.75rem; color:var(--text-tertiary);">Content centered on screen, back button floats at top</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================== SVG ICONS ==================== -->
|
||||
<div class="ds-section">
|
||||
<div class="ds-title">15. SVG Icons</div>
|
||||
@@ -2030,6 +2202,46 @@ cameras:
|
||||
document.getElementById('btn-back').addEventListener('click', function() {
|
||||
history.back();
|
||||
});
|
||||
|
||||
For centered layouts (homekit.html), the back button is placed
|
||||
OUTSIDE the container in a .back-wrapper div with position:absolute,
|
||||
aligned wider than the content so it floats at the top-left of
|
||||
the content area but not the screen edge.
|
||||
================================================================ */
|
||||
|
||||
/* ================================================================
|
||||
PIN INPUT PATTERN
|
||||
For segmented code entry. Each digit is a separate <input>.
|
||||
Auto-advance on input, backspace goes to previous field.
|
||||
Supports paste (distributes digits across fields).
|
||||
|
||||
HTML structure:
|
||||
<div class="pin-row">
|
||||
<div class="pin-group" id="group-0"></div>
|
||||
<span class="pin-separator">-</span>
|
||||
<div class="pin-group" id="group-1"></div>
|
||||
<span class="pin-separator">-</span>
|
||||
<div class="pin-group" id="group-2"></div>
|
||||
</div>
|
||||
|
||||
JS creates inputs dynamically:
|
||||
var pinGroups = [3, 2, 3]; // digits per group
|
||||
var inputs = [];
|
||||
pinGroups.forEach(function(count, gi) {
|
||||
var group = document.getElementById('group-' + gi);
|
||||
for (var i = 0; i < count; i++) {
|
||||
var input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.inputMode = 'numeric';
|
||||
input.maxLength = 1;
|
||||
input.className = 'pin-digit';
|
||||
input.autocomplete = 'off';
|
||||
group.appendChild(input);
|
||||
inputs.push(input);
|
||||
}
|
||||
});
|
||||
|
||||
States: .filled (has value), .error (wrong), .success (paired)
|
||||
================================================================ */
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user