Gallery — OutfitKit
Gallery
Grid de miniaturas multimedia con selección. Construido a partir de primitivos: no existe ningún componente Gallery en OutfitKit. Es composición de un Grid + Img con aspect ratio + overlay de selección. Consulta el ejemplo completo en examples/mini-apps/gallery.html.
Composición:
Grid cols="4" + cada item es un <div> relativo con Img aspect="1/1" fallback_icon + overlay (position:absolute) con checkbox y caption.
Default · 8 miniaturas con selección
cuadro-soldadura-01.jpg · 2,4 MB
cuadro-soldadura-02.jpg · 2,1 MB
pintura-cabina-01.jpg · 3,8 MB
qa-frenos.jpg · 1,9 MB
linea-l2-tour.mp4 · 24 MB
embalaje-final.jpg · 1,4 MB
stand-feria.jpg · 3,2 MB
backstage.jpg · 2,8 MB
<div class="grid grid-auto-cols cols-4 gap-3" style="width:100%">
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g1/300/300" loading="lazy"/></div>
<span class="chip success sm" style="position:absolute;top:6px;right:6px">✓</span>
<div class="meta" style="margin-top:4px">cuadro-soldadura-01.jpg · 2,4 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g2/300/300" loading="lazy"/></div>
<div class="meta" style="margin-top:4px">cuadro-soldadura-02.jpg · 2,1 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g3/300/300" loading="lazy"/></div>
<span class="chip success sm" style="position:absolute;top:6px;right:6px">✓</span>
<div class="meta" style="margin-top:4px">pintura-cabina-01.jpg · 3,8 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g4/300/300" loading="lazy"/></div>
<div class="meta" style="margin-top:4px">qa-frenos.jpg · 1,9 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g5/300/300" loading="lazy"/></div>
<span class="chip brand sm" style="position:absolute;bottom:6px;left:6px">▶ 0:42</span>
<div class="meta" style="margin-top:4px">linea-l2-tour.mp4 · 24 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g6/300/300" loading="lazy"/></div>
<div class="meta" style="margin-top:4px">embalaje-final.jpg · 1,4 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g7/300/300" loading="lazy"/></div>
<div class="meta" style="margin-top:4px">stand-feria.jpg · 3,2 MB</div>
</div>
<div style="position:relative">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/g8/300/300" loading="lazy"/></div>
<div class="meta" style="margin-top:4px">backstage.jpg · 2,8 MB</div>
</div>
</div>
<Grid cols="4">
<div style="position:relative">
<Img src="https://picsum.photos/seed/g1/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm" attrs={"style": "position:absolute;top:6px;right:6px"}>✓</Chip>
<div class="meta" style="margin-top:4px">cuadro-soldadura-01.jpg · 2,4 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g2/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">cuadro-soldadura-02.jpg · 2,1 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g3/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm" attrs={"style": "position:absolute;top:6px;right:6px"}>✓</Chip>
<div class="meta" style="margin-top:4px">pintura-cabina-01.jpg · 3,8 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g4/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">qa-frenos.jpg · 1,9 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g5/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:video" />
<Chip color="brand" size="sm" attrs={"style": "position:absolute;bottom:6px;left:6px"}>▶ 0:42</Chip>
<div class="meta" style="margin-top:4px">linea-l2-tour.mp4 · 24 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g6/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">embalaje-final.jpg · 1,4 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g7/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">stand-feria.jpg · 3,2 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g8/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">backstage.jpg · 2,8 MB</div>
</div>
</Grid>
<Grid cols="4">
<div style="position:relative">
<Img src="https://picsum.photos/seed/g1/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm" attrs={"style": "position:absolute;top:6px;right:6px"}>✓</Chip>
<div class="meta" style="margin-top:4px">cuadro-soldadura-01.jpg · 2,4 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g2/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">cuadro-soldadura-02.jpg · 2,1 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g3/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm" attrs={"style": "position:absolute;top:6px;right:6px"}>✓</Chip>
<div class="meta" style="margin-top:4px">pintura-cabina-01.jpg · 3,8 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g4/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">qa-frenos.jpg · 1,9 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g5/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:video" />
<Chip color="brand" size="sm" attrs={"style": "position:absolute;bottom:6px;left:6px"}>▶ 0:42</Chip>
<div class="meta" style="margin-top:4px">linea-l2-tour.mp4 · 24 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g6/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">embalaje-final.jpg · 1,4 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g7/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">stand-feria.jpg · 3,2 MB</div>
</div>
<div style="position:relative">
<Img src="https://picsum.photos/seed/g8/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<div class="meta" style="margin-top:4px">backstage.jpg · 2,8 MB</div>
</div>
</Grid>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />
Datastar · selección reactiva
A — click para alternar
B
C
D
Seleccionados: a, c
<div data-signals="{ selected: ['a', 'c'] }" style="width:100%">
<div class="grid grid-auto-cols cols-4 gap-3">
<div style="position:relative;cursor:pointer" data-on:click="$selected = $selected.includes('a') ? $selected.filter(x => x !== 'a') : [...$selected, 'a']">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/a/300/300" loading="lazy"/></div>
<span class="chip success sm" style="position:absolute;top:6px;right:6px" data-show="$selected.includes('a')">✓</span>
<div class="meta" style="margin-top:4px">A — click para alternar</div>
</div>
<div style="position:relative;cursor:pointer" data-on:click="$selected = $selected.includes('b') ? $selected.filter(x => x !== 'b') : [...$selected, 'b']">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/b/300/300" loading="lazy"/></div>
<span class="chip success sm" style="position:absolute;top:6px;right:6px" data-show="$selected.includes('b')">✓</span>
<div class="meta" style="margin-top:4px">B</div>
</div>
<div style="position:relative;cursor:pointer" data-on:click="$selected = $selected.includes('c') ? $selected.filter(x => x !== 'c') : [...$selected, 'c']">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/c/300/300" loading="lazy"/></div>
<span class="chip success sm" style="position:absolute;top:6px;right:6px" data-show="$selected.includes('c')">✓</span>
<div class="meta" style="margin-top:4px">C</div>
</div>
<div style="position:relative;cursor:pointer" data-on:click="$selected = $selected.includes('d') ? $selected.filter(x => x !== 'd') : [...$selected, 'd']">
<div class="img rounded" style="--aspect:1/1"><img src="https://picsum.photos/seed/d/300/300" loading="lazy"/></div>
<span class="chip success sm" style="position:absolute;top:6px;right:6px" data-show="$selected.includes('d')">✓</span>
<div class="meta" style="margin-top:4px">D</div>
</div>
</div>
<p class="meta" style="margin-top:8px">Seleccionados: <span data-text="$selected.join(', ')">a, c</span></p>
</div>
<div data-signals="{ selected: ['a', 'c'] }">
<Grid cols="4">
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('a') ? $selected.filter(x => x !== 'a') : [...$selected, 'a']">
<Img src="https://picsum.photos/seed/a/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('a')"}>✓</Chip>
<div class="meta" style="margin-top:4px">A — click para alternar</div>
</div>
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('b') ? $selected.filter(x => x !== 'b') : [...$selected, 'b']">
<Img src="https://picsum.photos/seed/b/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('b')"}>✓</Chip>
<div class="meta" style="margin-top:4px">B</div>
</div>
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('c') ? $selected.filter(x => x !== 'c') : [...$selected, 'c']">
<Img src="https://picsum.photos/seed/c/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('c')"}>✓</Chip>
<div class="meta" style="margin-top:4px">C</div>
</div>
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('d') ? $selected.filter(x => x !== 'd') : [...$selected, 'd']">
<Img src="https://picsum.photos/seed/d/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('d')"}>✓</Chip>
<div class="meta" style="margin-top:4px">D</div>
</div>
</Grid>
<p class="meta" style="margin-top:8px">Seleccionados: <span data-text="$selected.join(', ')">a, c</span></p>
</div>
<div data-signals="{ selected: ['a', 'c'] }">
<Grid cols="4">
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('a') ? $selected.filter(x => x !== 'a') : [...$selected, 'a']">
<Img src="https://picsum.photos/seed/a/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('a')"}>✓</Chip>
<div class="meta" style="margin-top:4px">A — click para alternar</div>
</div>
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('b') ? $selected.filter(x => x !== 'b') : [...$selected, 'b']">
<Img src="https://picsum.photos/seed/b/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('b')"}>✓</Chip>
<div class="meta" style="margin-top:4px">B</div>
</div>
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('c') ? $selected.filter(x => x !== 'c') : [...$selected, 'c']">
<Img src="https://picsum.photos/seed/c/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('c')"}>✓</Chip>
<div class="meta" style="margin-top:4px">C</div>
</div>
<div style="position:relative;cursor:pointer"
data-on:click="$selected = $selected.includes('d') ? $selected.filter(x => x !== 'd') : [...$selected, 'd']">
<Img src="https://picsum.photos/seed/d/300/300" aspect="1/1" shape="rounded" fallback_icon="lucide:image" />
<Chip color="success" size="sm"
attrs={"style": "position:absolute;top:6px;right:6px",
"data-show": "$selected.includes('d')"}>✓</Chip>
<div class="meta" style="margin-top:4px">D</div>
</div>
</Grid>
<p class="meta" style="margin-top:8px">Seleccionados: <span data-text="$selected.join(', ')">a, c</span></p>
</div>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />