Showcase for the depth channel (mirrors /temas/color and /temas/tipografia):
- ESTADO: the 5 planes (flush/raised/overlay/modal/recessed) as elevated tiles
composing surface + shadow + z (`data-depth`), with a light/dark toggle showing
the mode-aware mix.
- EVENTO: stamping `data-event-*` (as sema would during the hold) fires the firma
live — emerge -> the shadow grows (rise); contact -> it flattens (recede).
Depth occurs.
Self-contained (eidos foundation + data-theme), distinctive dark/editorial aesthetic.
Verified: check 0 errors; browser — 5 planes render with their resting shadows;
firing emerge applies the present-rise firma (firmaFired true).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
active-uix
parent
a289ce666f
commit
fa8fa3b8d7
@ -0,0 +1,344 @@
|
||||
<script lang="ts">
|
||||
/**
|
||||
* Depth demo — the Eidos depth system, the novel "depth occurs" channel.
|
||||
*
|
||||
* Two moments, both live:
|
||||
* - ESTADO: the 5 planes (`data-depth`) — the resting elevation (where an element *is*),
|
||||
* composing surface + shadow + z. Toggle light/dark to see the mode-aware mix.
|
||||
* - EVENTO: stamping `data-event-*` (as sema would during the hold) fires the firma —
|
||||
* emerge → the shadow GROWS (rise); contact → it FLATTENS (recede). Depth *occurs*.
|
||||
*
|
||||
* Self-contained: imports the eidos foundation (planes + firma keyframes) + `data-theme`.
|
||||
*/
|
||||
import '@/uix/eidos/index.css'
|
||||
|
||||
let theme = $state<'light' | 'dark'>('dark')
|
||||
|
||||
const PLANES = [
|
||||
{ id: 'flush', label: 'flush', note: 'a ras de superficie' },
|
||||
{ id: 'raised', label: 'raised', note: 'tarjetas · reposo' },
|
||||
{ id: 'overlay', label: 'overlay', note: 'menús · popovers' },
|
||||
{ id: 'modal', label: 'modal', note: 'diálogos · cima' },
|
||||
{ id: 'recessed', label: 'recessed', note: 'pozos · inputs' }
|
||||
] as const
|
||||
|
||||
// ── Event moment: stamp data-event-* to fire the firma (as sema would) ──────
|
||||
let targetPlane = $state<'raised' | 'overlay' | 'modal'>('overlay')
|
||||
let evt = $state<{ event?: string; family?: string; phase?: string }>({})
|
||||
|
||||
function fire(next: { event?: string; family?: string }): void {
|
||||
evt = {} // clear → lets the one-shot animation restart on re-trigger
|
||||
requestAnimationFrame(() => {
|
||||
evt = { ...next, phase: 'active' }
|
||||
})
|
||||
}
|
||||
const fireEmerge = () => fire({ event: 'present' })
|
||||
const firePress = () => fire({ family: 'contact' })
|
||||
</script>
|
||||
|
||||
<svelte:head><title>Profundidad · Eidos</title></svelte:head>
|
||||
|
||||
<div class="root" data-theme={theme}>
|
||||
<header class="masthead">
|
||||
<div class="mast-row">
|
||||
<p class="kicker">Eidos · canal de profundidad</p>
|
||||
<button class="theme-toggle" onclick={() => (theme = theme === 'light' ? 'dark' : 'light')}>
|
||||
{theme === 'light' ? '◐ claro' : '◑ oscuro'}
|
||||
</button>
|
||||
</div>
|
||||
<h1 class="mast-title">La profundidad <em>ocurre</em></h1>
|
||||
<p class="mast-lede">
|
||||
No es una propiedad que un elemento <i>tiene</i> — es algo que <i>sucede</i>. Un plano en
|
||||
reposo (estado) <strong>y</strong> un ascenso al emerger (evento): los dos momentos, un solo
|
||||
canal.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<!-- ── Planos (momento-estado) ────────────────────────────────────────── -->
|
||||
<section class="section">
|
||||
<div class="sec-head">
|
||||
<h2 class="sec-title">Planos · momento-estado</h2>
|
||||
<p class="sec-note">
|
||||
<code>data-depth='{`{plane}`}'</code> — un nivel cohere superficie + sombra + z. La mezcla
|
||||
es mode-aware (en dark, "más arriba" = más claro). Cambia el tema arriba.
|
||||
</p>
|
||||
</div>
|
||||
<div class="planes">
|
||||
{#each PLANES as p}
|
||||
<div class="plane-cell">
|
||||
<div
|
||||
class="plane-card"
|
||||
data-depth={p.id}
|
||||
style="background: var(--depth-{p.id}-surface, var(--color-surface-default))"
|
||||
></div>
|
||||
<span class="plane-label">{p.label}</span>
|
||||
<span class="plane-note">{p.note}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── El evento (momento-evento) ─────────────────────────────────────── -->
|
||||
<section class="section">
|
||||
<div class="sec-head">
|
||||
<h2 class="sec-title">El evento · momento-evento</h2>
|
||||
<p class="sec-note">
|
||||
La elevación vive en la <em>firma</em>: dispara un evento (como haría sema durante el
|
||||
<code>hold</code>) y la sombra <strong>crece</strong> al emerger / se <strong>aplana</strong>
|
||||
al presionar — coordinado con posición + escala desde un solo evento.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="event-stage">
|
||||
<div class="event-controls">
|
||||
<div class="ctrl">
|
||||
<span class="ctrl-label">plano de reposo</span>
|
||||
<div class="chips">
|
||||
{#each ['raised', 'overlay', 'modal'] as pl}
|
||||
<button class="chip" data-on={targetPlane === pl} onclick={() => (targetPlane = pl as typeof targetPlane)}>{pl}</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div class="fire-row">
|
||||
<button class="fire-btn" onclick={fireEmerge}>↑ emerge <small>(sube)</small></button>
|
||||
<button class="fire-btn" onclick={firePress}>↓ contact <small>(recede)</small></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="event-arena">
|
||||
<div
|
||||
class="event-target"
|
||||
data-depth={targetPlane}
|
||||
data-event={evt.event}
|
||||
data-event-family={evt.family}
|
||||
data-event-phase={evt.phase}
|
||||
style="background: var(--depth-{targetPlane}-surface, var(--color-surface-overlay))"
|
||||
>
|
||||
<span class="target-glyph">↕</span>
|
||||
<span class="target-text">dispárame</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footnote">
|
||||
<p>
|
||||
<strong>Default fuerte, jaula abierta.</strong> El set de planos, su mezcla y la firma son
|
||||
config-driven y anulables; los primitivos (<code>--shadow-*</code>, <code>z-index</code>,
|
||||
<code>box-shadow</code> crudo) siguen a un paso. La capa eventful es <em>aditiva</em> sobre el
|
||||
plano de reposo — un elemento <i>flush</i> no eleva nada; uno <i>raised</i> sube proporcional
|
||||
a su plano. Y degrada con <code>prefers-reduced-motion</code>.
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.root {
|
||||
min-block-size: 100vh;
|
||||
background:
|
||||
radial-gradient(120% 80% at 50% -10%, var(--color-surface-raised), transparent 60%),
|
||||
var(--color-surface-default);
|
||||
color: var(--color-content-primary);
|
||||
font-family: var(--font-family-primary);
|
||||
padding: clamp(1.5rem, 5vw, 5rem) clamp(1.25rem, 5vw, 6rem) 6rem;
|
||||
--rule: color-mix(in srgb, var(--color-border-default) 100%, transparent);
|
||||
}
|
||||
|
||||
.masthead {
|
||||
max-inline-size: 56rem;
|
||||
margin-block-end: clamp(3rem, 8vw, 6rem);
|
||||
}
|
||||
.mast-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-block-end: 2.5rem;
|
||||
}
|
||||
.kicker {
|
||||
margin: 0;
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
letter-spacing: 0.18em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-content-muted);
|
||||
}
|
||||
.theme-toggle {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--color-content-secondary);
|
||||
background: var(--color-surface-raised);
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 999px;
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.theme-toggle:hover { color: var(--color-content-primary); }
|
||||
.mast-title {
|
||||
font-family: var(--font-family-display);
|
||||
font-size: var(--font-size-xxxl);
|
||||
font-weight: 600;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.03em;
|
||||
margin: 0 0 1.25rem;
|
||||
text-wrap: balance;
|
||||
}
|
||||
.mast-title em { font-style: italic; color: var(--color-primary-text, var(--color-content-primary)); }
|
||||
.mast-lede {
|
||||
max-inline-size: 46ch;
|
||||
font-size: var(--font-size-lg);
|
||||
line-height: 1.5;
|
||||
color: var(--color-content-secondary);
|
||||
margin: 0;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
.mast-lede i { font-style: italic; }
|
||||
|
||||
.section { margin-block-end: clamp(3.5rem, 9vw, 7rem); }
|
||||
.sec-head {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: baseline;
|
||||
gap: 0.75rem 2rem;
|
||||
padding-block-end: 1.25rem;
|
||||
margin-block-end: 2.5rem;
|
||||
border-block-end: 1px solid var(--rule);
|
||||
}
|
||||
.sec-title {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
}
|
||||
.sec-note {
|
||||
margin: 0;
|
||||
max-inline-size: 60ch;
|
||||
font-size: var(--font-size-sm);
|
||||
line-height: 1.55;
|
||||
color: var(--color-content-muted);
|
||||
}
|
||||
code { font-family: var(--font-family-mono); font-size: 0.92em; color: var(--color-content-secondary); background: var(--color-surface-muted); padding: 0.1em 0.4em; border-radius: 4px; }
|
||||
em { font-style: normal; color: var(--color-content-primary); font-weight: 500; }
|
||||
|
||||
/* Planes */
|
||||
.planes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
|
||||
gap: clamp(1.5rem, 4vw, 3rem);
|
||||
}
|
||||
.plane-cell { display: flex; flex-direction: column; align-items: center; gap: 1rem; }
|
||||
.plane-card {
|
||||
inline-size: 100%;
|
||||
block-size: 7rem;
|
||||
border-radius: var(--radius-lg);
|
||||
/* hairline so `flush` (no shadow, surface = canvas) still reads as a flat tile */
|
||||
border: 1px solid color-mix(in srgb, var(--rule) 70%, transparent);
|
||||
}
|
||||
.plane-label {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-sm);
|
||||
letter-spacing: 0.04em;
|
||||
color: var(--color-content-primary);
|
||||
}
|
||||
.plane-note {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-content-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Event stage */
|
||||
.event-stage {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 18rem) 1fr;
|
||||
gap: clamp(1.5rem, 4vw, 3rem);
|
||||
align-items: start;
|
||||
}
|
||||
@media (max-width: 720px) { .event-stage { grid-template-columns: 1fr; } }
|
||||
.event-controls { display: flex; flex-direction: column; gap: 1.75rem; }
|
||||
.ctrl { display: flex; flex-direction: column; gap: 0.7rem; }
|
||||
.ctrl-label {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-content-muted);
|
||||
}
|
||||
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
|
||||
.chip {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
color: var(--color-content-secondary);
|
||||
background: var(--color-surface-raised);
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 7px;
|
||||
padding: 0.35rem 0.7rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.chip[data-on='true'] {
|
||||
color: var(--color-primary-on-solid, #fff);
|
||||
background: var(--color-primary-solid);
|
||||
border-color: var(--color-primary-solid);
|
||||
}
|
||||
.fire-row { display: flex; flex-direction: column; gap: 0.6rem; }
|
||||
.fire-btn {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-sm);
|
||||
color: var(--color-content-primary);
|
||||
background: var(--color-surface-raised);
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.7rem 1rem;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition: border-color 140ms;
|
||||
}
|
||||
.fire-btn small { color: var(--color-content-muted); }
|
||||
.fire-btn:hover { border-color: var(--color-primary-solid); }
|
||||
|
||||
.event-arena {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-block-size: 18rem;
|
||||
border-radius: var(--radius-lg);
|
||||
background:
|
||||
repeating-linear-gradient(45deg, transparent 0 13px, color-mix(in srgb, var(--rule) 45%, transparent) 13px 14px),
|
||||
var(--color-surface-default);
|
||||
border: 1px solid var(--rule);
|
||||
}
|
||||
.event-target {
|
||||
inline-size: 11rem;
|
||||
block-size: 7.5rem;
|
||||
border-radius: var(--radius-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.target-glyph { font-size: var(--font-size-xl); color: var(--color-content-secondary); }
|
||||
.target-text {
|
||||
font-family: var(--font-family-mono);
|
||||
font-size: var(--font-size-xs);
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
color: var(--color-content-muted);
|
||||
}
|
||||
|
||||
.footnote {
|
||||
max-inline-size: 60rem;
|
||||
padding-block-start: 2rem;
|
||||
border-block-start: 1px solid var(--rule);
|
||||
}
|
||||
.footnote p {
|
||||
margin: 0;
|
||||
font-size: var(--font-size-sm);
|
||||
line-height: 1.6;
|
||||
color: var(--color-content-muted);
|
||||
text-wrap: pretty;
|
||||
}
|
||||
.footnote i { font-style: italic; }
|
||||
</style>
|
||||
Loading…
Reference in new issue