Glass-morphism icon gallery demonstrating:
vars for a static array of family::name:variant icon keysforEachString with pattern: family::name:variant — exposes item.family, item.name, item.variant in the templatefamily-{{item.family}} drives per-family color theming via CSS variablesdata-is-selected attribute with expression {{selectedIcon==item}} for selected state stylingsetState with dataAttribute — reads the clicked element's data-icon-key instead of a hardcoded valueproto-svg-icon web component for the selected icon displaystyle and script elements for CSS variable theming and runtime service loadingshowToast and emitEvent actions# Icon Gallery - Mixed Families with Glass-Morphism Design
# Generated by generate-icon-gallery.py
# Icons: 42 from mixed families
name: IconGallery
description: Beautiful icon gallery with glass-morphism cards and color-coded family badges
tagName: icon-gallery-wc
vars:
iconKeys:
type: array
defaultValue:
- tabler::pilcrow-left:outline
- phosphor::intersect-three:bold
- tabler::air-conditioning-disabled:outline
- nucleo-ui::align-3-left:outline
- lucide-lab::belt:outline
- phosphor::text-h-three:bold
- tabler::cash-heart:outline
- nucleo-ui::face-smile-2:outline
- tabler::rotate-clockwise-2:outline
- phosphor::park:bold
- phosphor::game-controller:bold
- phosphor::resize:bold
- tabler::currency-dirham:outline
- tabler::tag-starred:outline
- lucide::thumbs-down:outline
- tabler::arrow-down-left-circle:outline
- lucide::file-search-corner:outline
- lucide::x:outline
- tabler::alert-square:filled
- lucide::book-open-check:outline
- lucide::nut-off:outline
- tabler::polygon-off:outline
- phosphor::shovel:bold
- lucide-lab::fox-face-tail:outline
- tabler::tilt-shift-off:outline
- tabler::message-circle-pause:outline
- lucide::square-arrow-right:outline
- tabler::number-5-small:outline
- tabler::building-cottage:outline
- tabler::map-pin-pause:outline
- tabler::view-360:outline
- lucide::plane:outline
- phosphor::play-circle:bold
- lucide::lectern:outline
- tabler::grid-goldenratio:outline
- tabler::bowl-chopsticks:filled
- lucide::folder-plus:outline
- tabler::settings-check:outline
- tabler::crop-landscape:filled
- phosphor::orange-slice:bold
- tabler::arrow-big-right-lines:filled
- tabler::help-square:filled
state:
selectedIcon:
type: string
defaultValue: ''
globalScrollMode:
type: boolean
defaultValue: false
elements:
- type: style
content: |
/* Icon family color mappings - using CSS variables */
.family-mdi {
--color-400: rgb(251 146 60);
--color-500: rgb(249 115 22);
--color-600: rgb(234 88 12);
}
.family-material {
--color-400: rgb(96 165 250);
--color-500: rgb(59 130 246);
--color-600: rgb(37 99 235);
}
.family-lucide {
--color-400: rgb(192 132 252);
--color-500: rgb(168 85 247);
--color-600: rgb(147 51 234);
}
.family-feather {
--color-400: rgb(74 222 128);
--color-500: rgb(34 197 94);
--color-600: rgb(22 163 74);
}
.family-lucide-lab {
--color-400: rgb(250 204 21);
--color-500: rgb(234 179 8);
--color-600: rgb(202 138 4);
}
.family-auto {
--color-400: rgb(248 113 113);
--color-500: rgb(239 68 68);
--color-600: rgb(220 38 38);
}
.family-nucleo-ui {
--color-400: rgb(244 114 182);
--color-500: rgb(236 72 153);
--color-600: rgb(219 39 119);
}
.family-phosphor {
--color-400: rgb(103 232 249);
--color-500: rgb(6 182 212);
--color-600: rgb(14 116 144);
}
.family-tabler {
--color-400: rgb(165 180 252);
--color-500: rgb(99 102 241);
--color-600: rgb(79 70 229);
}
.banner {
background-color: var(--color-500);
}
.icon-bg {
background: linear-gradient(to bottom right, var(--color-400), var(--color-600));
}
- type: style
content: |
.selected-card {
position: relative;
}
.selected-card[data-is-selected="true"] {
border-color: rgb(168, 85, 247) !important;
border-width: 3px !important;
box-shadow: 0 0 20px rgba(168, 85, 247, 0.6), 0 0 40px rgba(168, 85, 247, 0.3) !important;
transform: translateY(-4px) !important;
}
.selected-card[data-is-selected="true"]::before {
content: '✓';
position: absolute;
top: 8px;
right: 8px;
background: rgb(168, 85, 247);
color: white;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 14px;
z-index: 10;
}
- type: script
attributes:
type: module
content: |
import svgIconService from 'http://localhost:3005/runtime/services/svg-icon-service.js';
window.protoSpec.svgIconService = svgIconService;
await import('http://localhost:3005/runtime/components/proto-svg-icon.js');
console.log('✅ SVG Icon Service and proto-svg-icon loaded');
- type: div
classes:
- min-h-screen
- bg-gradient-to-br
- from-gray-800
- via-gray-900
- to-slate-900
- p-5
- rounded-xl
children:
- type: div
classes:
- text-center
- mb-8
children:
- type: div
classes:
- text-5xl
- font-extrabold
- mb-2
- bg-gradient-to-r
- from-purple-200
- via-purple-400
- to-pink-400
- bg-clip-text
- text-transparent
text: Mixed Icon Gallery
- type: div
classes:
- text-xl
- text-purple-200
- mb-6
text: 42 Random Icons from Mixed Families
- type: div
classes:
- mb-4
children:
- type: ds:switch
id: globalScrollMode
description: Page Scroll
size: md
color: purple
- type: div
classes:
- grid
- grid-cols-[repeat(auto-fit,minmax(140px,1fr))]
- gap-6
- p-5
children:
- type: forEachString
collection: '{{vars.iconKeys}}'
pattern: family::name:variant
as: item
template:
type: div
attributes:
data-icon-key: '{{item}}'
data-is-selected: '{{selectedIcon==item}}'
classes:
- selected-card
- bg-gray-700
- bg-opacity-80
- backdrop-blur-md
- border
- border-gray-600
- border-opacity-50
- rounded-2xl
- flex
- flex-col
- items-center
- shadow-xl
- transition-all
- duration-300
- cursor-pointer
- hover:bg-gray-600
- hover:border-gray-500
- hover:-translate-y-2
- hover:shadow-2xl
- relative
- overflow-hidden
actions:
onClick: selectIcon
children:
- type: div
classes:
- w-20
- h-20
- flex
- items-center
- justify-center
- icon-bg
- family-{{item.family}}
- rounded-xl
- transition-transform
- duration-300
- mt-5
children:
- type: md:icon
name: '{{item}}'
size: 48
classes:
- text-white
- type: div
classes:
- text-sm
- font-semibold
- text-gray-100
- text-center
- break-all
- px-5
- py-3
- flex-grow
text: '{{item.name}}'
- type: div
classes:
- w-full
- py-2.5
- px-3
- banner
- family-{{item.family}}
- text-white
- text-xs
- font-semibold
- uppercase
- tracking-wide
- text-center
- mt-auto
text: '{{item.family}}'
- type: div
classes:
- mt-8
- p-6
- bg-gray-700
- bg-opacity-80
- backdrop-blur-md
- rounded-2xl
- border
- border-gray-600
- border-opacity-50
children:
- type: div
classes:
- text-xl
- font-bold
- text-purple-200
- mb-4
text: Selected Icon
- type: div
classes:
- flex
- items-center
- gap-4
- p-4
- rounded-xl
children:
- type: proto-svg-icon
attributes:
name: '{{selectedIcon}}'
classes:
- w-24
- h-24
- text-purple-400
- flex-shrink-0
- type: div
classes:
- flex
- flex-col
- gap-2
children:
- type: div
classes:
- text-3xl
- font-bold
- text-purple-300
- font-mono
- break-all
text: '{{selectedIcon}}'
- type: div
classes:
- text-sm
- text-gray-400
text: 'Format: family::icon:variant'
actions:
selectIcon:
type: setState
target: selectedIcon
dataAttribute: data-icon-key
showIconToast:
type: showToast
stateKey: selectedIcon
toastType: success
message: 'Selected: {{selectedIcon}}'
duration: 2000
handleScrollModeToast:
type: showToast
stateKey: globalScrollMode
toastType: warning
message: Scroll mode changed! Layout updated via event bus.
duration: 3000
handleScrollModeEvent:
type: emitEvent
stateKey: globalScrollMode
eventName: globalScrollMode-changed