Add Glaze material, pickers, slider and design guidelines

Glaze is glass with a dial: --nv-glass-frost (0 clear .. 1 heavy) moves
backdrop blur, tint and saturation together, read where the surface is
drawn so any subtree or slider can change it. A masked rim and a specular
bloom follow the pointer via niveus.js; without it the light sits at its
default and the material still reads. Falls back to the elevated solid
under reduced transparency or without backdrop-filter.

New components: .nv-slider (binds to a token with data-nv-var),
.nv-calendar, .nv-timepicker (24-hour by default, optional 24H / AM/PM
switch, value always HH:MM), and .nv-picker with .nv-menu--listbox (search,
type-ahead, keys). All render without niveus.js except where noted.

GUIDELINES.md is the normative rulebook for people and AI agents.

check.py, build.py and build.py --check pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Nexoniarz 2026-10-28 09:24:24 +01:00
commit 369d1cd8f7
17 changed files with 2679 additions and 6 deletions

View file

@ -67,6 +67,72 @@
place-items: center;
}
/* Glaze specimen: color behind the pane, so the frost has something to
act on. The orbs and the line of type are only there to be blurred. */
.glaze-demo {
position: relative;
margin-block-start: var(--nv-space-6);
min-block-size: 22rem;
display: grid;
place-items: center;
overflow: hidden;
}
.glaze-demo__scene {
position: absolute;
inset: 0;
pointer-events: none;
}
.glaze-demo__orb {
position: absolute;
border-radius: var(--nv-radius-full);
inline-size: var(--_size);
block-size: var(--_size);
inset-inline-start: var(--_x);
inset-block-start: var(--_y);
background: var(--_fill);
}
.glaze-demo__type {
position: absolute;
inset-inline: 0;
inset-block-end: var(--nv-space-4);
text-align: center;
font: var(--nv-font-display);
font-size: clamp(2.5rem, 9vw, 5.5rem);
font-weight: 700;
color: var(--nv-color-text-primary);
opacity: 0.85;
white-space: nowrap;
}
.glaze-demo__panel {
position: relative;
inline-size: min(26rem, 100%);
padding: var(--nv-space-6);
border-radius: var(--nv-radius-xl);
display: flex;
flex-direction: column;
gap: var(--nv-space-4);
}
.picker-demo {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: center;
gap: var(--nv-space-6);
margin-block-start: var(--nv-space-6);
}
.picker-demo__column {
display: flex;
flex-direction: column;
gap: var(--nv-space-4);
inline-size: min(16rem, 100%);
}
.specimen__name {
font: var(--nv-font-label);
}
@ -297,6 +363,84 @@
</div>
</div>
</div>
<div class="nv-bed glaze-demo" id="glaze-bed">
<div class="glaze-demo__scene" aria-hidden="true">
<span class="glaze-demo__orb" style="--_size: 11rem; --_x: 8%; --_y: 8%; --_fill: var(--nv-color-accent)"></span>
<span class="glaze-demo__orb" style="--_size: 8rem; --_x: 68%; --_y: 14%; --_fill: var(--nv-color-danger)"></span>
<span class="glaze-demo__orb" style="--_size: 9rem; --_x: 52%; --_y: 58%; --_fill: var(--nv-color-success)"></span>
<span class="glaze-demo__type">Niveus glaze</span>
</div>
<div class="nv-material-glaze glaze-demo__panel">
<div>
<h3 class="nv-heading">Glaze</h3>
<p class="nv-prose">
One dial controls how frosted this pane is. The rim brightens on
the side facing your pointer.
</p>
</div>
<div class="nv-field">
<label class="nv-field__label" for="frost">Frost</label>
<input class="nv-slider" id="frost" type="range" min="0" max="1" step="0.01"
data-nv-var="--nv-glass-frost" data-nv-var-target="#glaze-bed">
<span class="nv-field__hint">Clear glass on the left, heavy frost on the right.</span>
</div>
<div class="nv-cluster nv-cluster--tight">
<button class="nv-button nv-button--primary">Continue</button>
<button class="nv-button">Cancel</button>
</div>
</div>
</div>
</section>
<!-- ================================================================= -->
<section id="pickers">
<div class="section__head">
<h2 class="nv-heading">Pickers</h2>
<p class="nv-prose">
A calendar, wheels for time, and a popup list. They hold content, so
they sit on solid surfaces; here the first two float on Glaze
over a bed, which is where a date field's popover would be.
</p>
</div>
<div class="nv-bed picker-demo" id="picker-bed">
<div class="nv-calendar nv-material-glaze" data-nv-calendar data-nv-value="2026-10-28"
data-nv-min="2026-10-05">
<div class="nv-calendar__header">
<button class="nv-button nv-button--ghost nv-button--icon" data-nv-calendar-step="-1"
aria-label="Previous month">&lsaquo;</button>
<h3 class="nv-calendar__title" aria-live="polite"></h3>
<button class="nv-button nv-button--ghost nv-button--icon" data-nv-calendar-step="1"
aria-label="Next month">&rsaquo;</button>
</div>
<div class="nv-calendar__grid" role="grid"></div>
</div>
<div class="picker-demo__column">
<div class="nv-timepicker nv-material-glaze" data-nv-timepicker data-nv-value="09:30"
data-nv-step="5" data-nv-format-toggle aria-label="Start time"></div>
<output class="nv-caption nv-code" id="picker-output">09:30</output>
<div class="nv-field">
<label class="nv-field__label" id="fruit-label">Fruit</label>
<button class="nv-input nv-picker nv-menu-trigger" data-empty popovertarget="fruit"
aria-labelledby="fruit-label" style="--nv-anchor: --fruit">
<span data-nv-picker-label>Choose a fruit</span>
</button>
<div class="nv-menu nv-menu--listbox" popover id="fruit" style="--nv-anchor: --fruit">
<input class="nv-input nv-input--sm nv-menu__search" placeholder="Search…" aria-label="Search fruit">
<button class="nv-menu__item" role="option" data-value="apple">Apple</button>
<button class="nv-menu__item" role="option" data-value="apricot">Apricot</button>
<button class="nv-menu__item" role="option" data-value="banana">Banana</button>
<button class="nv-menu__item" role="option" data-value="cherry">Cherry</button>
<button class="nv-menu__item" role="option" data-value="mango">Mango</button>
<button class="nv-menu__item" role="option" data-value="pear">Pear</button>
</div>
</div>
</div>
</div>
</section>
<!-- ================================================================= -->
@ -1315,6 +1459,10 @@
</dialog>
<script>
document.addEventListener("nv:time", function (event) {
var out = document.getElementById("picker-output");
if (out) out.textContent = event.detail.value;
});
/* --------------------------------------------------------------------
Page behaviour. Note what is *not* here: no style values, no colors,
no durations. Continuity comes from nv.transition(); this file only