Files
sigpro-ui/docs/components_old/stack.md
2026-04-06 03:19:15 +02:00

19 KiB

Stack

Stack component for layering multiple elements on top of each other, creating depth and visual hierarchy.

Tag

Stack

Props

Prop Type Default Description
class string '' Additional CSS classes (DaisyUI + Tailwind)
children Array<VNode> | VNode - Elements to stack (first is bottom, last is top)

Live Examples

Basic Stack

Live Demo

const BasicDemo = () => {
  return Stack({ class: 'w-40' }, [
    Div({ class: 'bg-primary text-primary-content rounded-lg p-4 shadow-lg' }, 'Layer 1'),
    Div({ class: 'bg-secondary text-secondary-content rounded-lg p-4 shadow-lg' }, 'Layer 2'),
    Div({ class: 'bg-accent text-accent-content rounded-lg p-4 shadow-lg' }, 'Layer 3')
  ]);
};
Mount(BasicDemo, '#demo-basic');

Card Stack

Live Demo

const CardsDemo = () => {
  return Stack({ class: 'w-64' }, [
    Div({ class: 'card bg-base-100 shadow-xl border border-base-300' }, [
      Div({ class: 'card-body p-4' }, [
        Span({ class: 'text-sm opacity-70' }, 'Back Card'),
        Span({ class: 'font-bold' }, 'Additional info')
      ])
    ]),
    Div({ class: 'card bg-primary text-primary-content shadow-xl' }, [
      Div({ class: 'card-body p-4' }, [
        Span({ class: 'text-sm' }, 'Front Card'),
        Span({ class: 'font-bold text-lg' }, 'Main Content')
      ])
    ])
  ]);
};
Mount(CardsDemo, '#demo-cards');

Avatar Stack

Live Demo

const AvatarsDemo = () => {
  return Stack({ class: 'w-32' }, [
    Div({ class: 'avatar placeholder' }, [
      Div({ class: 'bg-neutral text-neutral-content rounded-full w-16' }, [
        Span({}, 'JD')
      ])
    ]),
    Div({ class: 'avatar placeholder' }, [
      Div({ class: 'bg-primary text-primary-content rounded-full w-16' }, [
        Span({}, 'JS')
      ])
    ]),
    Div({ class: 'avatar placeholder' }, [
      Div({ class: 'bg-secondary text-secondary-content rounded-full w-16' }, [
        Span({}, 'BC')
      ])
    ])
  ]);
};
Mount(AvatarsDemo, '#demo-avatars');

Image Stack

Live Demo

const ImagesDemo = () => {
  return Stack({ class: 'w-48' }, [
    Div({ class: 'w-full h-32 bg-gradient-to-r from-primary to-secondary rounded-lg shadow-lg' }, [
      Div({ class: 'p-2 text-white text-sm' }, 'Background Image')
    ]),
    Div({ class: 'w-full h-32 bg-gradient-to-r from-secondary to-accent rounded-lg shadow-lg translate-x-2 translate-y-2' }, [
      Div({ class: 'p-2 text-white text-sm' }, 'Middle Layer')
    ]),
    Div({ class: 'w-full h-32 bg-gradient-to-r from-accent to-primary rounded-lg shadow-lg translate-x-4 translate-y-4 flex items-center justify-center' }, [
      Span({ class: 'text-white font-bold' }, 'Top Layer')
    ])
  ]);
};
Mount(ImagesDemo, '#demo-images');

Live Demo

const GalleryDemo = () => {
  const photos = [
    { color: 'bg-primary', label: 'Photo 1' },
    { color: 'bg-secondary', label: 'Photo 2' },
    { color: 'bg-accent', label: 'Photo 3' },
    { color: 'bg-info', label: 'Photo 4' }
  ];
  
  return Stack({ class: 'w-48 cursor-pointer hover:scale-105 transition-transform' }, [
    ...photos.map((photo, idx) => 
      Div({ 
        class: `${photo.color} rounded-lg shadow-lg transition-all`,
        style: `transform: translate(${idx * 4}px, ${idx * 4}px); width: 100%; height: 100%;`
      }, [
        Div({ class: 'p-4 text-white font-bold' }, photo.label)
      ])
    )
  ]);
};
Mount(GalleryDemo, '#demo-gallery');

Interactive Stack

Live Demo

const InteractiveDemo = () => {
  const active = $(0);
  const colors = ['primary', 'secondary', 'accent', 'info', 'success'];
  const labels = ['Home', 'Profile', 'Settings', 'Messages', 'Notifications'];
  
  return Div({ class: 'flex flex-col gap-6 items-center' }, [
    Stack({ class: 'w-56' }, colors.map((color, idx) => 
      Div({ 
        class: `bg-${color} text-${color}-content rounded-lg p-4 shadow-lg transition-all cursor-pointer ${idx === active() ? 'scale-105 z-10' : ''}`,
        style: `transform: translate(${idx * 8}px, ${idx * 8}px);`,
        onclick: () => active(idx)
      }, [
        Div({ class: 'font-bold' }, labels[idx]),
        Div({ class: 'text-sm opacity-80' }, `Layer ${idx + 1}`)
      ])
    )),
    Div({ class: 'mt-4 text-center' }, [
      Span({ class: 'font-bold' }, () => `Active: ${labels[active()]}`),
      Div({ class: 'flex gap-2 mt-2' }, colors.map((_, idx) =>
        Button({ 
          class: `btn btn-xs ${idx === active() ? 'btn-primary' : 'btn-ghost'}`,
          onclick: () => active(idx)
        }, `${idx + 1}`)
      ))
    ])
  ]);
};
Mount(InteractiveDemo, '#demo-interactive');

Notification Stack

Live Demo

const NotificationsDemo = () => {
  const notifications = $([
    { id: 1, message: 'New message from John', type: 'info' },
    { id: 2, message: 'Your order has shipped', type: 'success' },
    { id: 3, message: 'Meeting in 10 minutes', type: 'warning' }
  ]);
  
  const removeNotification = (id) => {
    notifications(notifications().filter(n => n.id !== id));
  };
  
  const typeClasses = {
    info: 'bg-info text-info-content',
    success: 'bg-success text-success-content',
    warning: 'bg-warning text-warning-content',
    error: 'bg-error text-error-content'
  };
  
  return Div({ class: 'flex flex-col gap-4 items-center' }, [
    Stack({ class: 'w-80' }, notifications().map((notif, idx) => 
      Div({ 
        class: `${typeClasses[notif.type]} rounded-lg p-3 shadow-lg transition-all cursor-pointer`,
        style: `transform: translate(${idx * 4}px, ${idx * 4}px);`,
        onclick: () => removeNotification(notif.id)
      }, [
        Div({ class: 'flex justify-between items-center' }, [
          Span({ class: 'text-sm' }, notif.message),
          Span({ class: 'text-xs opacity-70 cursor-pointer hover:opacity-100' }, '✕')
        ])
      ])
    )),
    notifications().length === 0 
      ? Div({ class: 'alert alert-soft' }, 'No notifications')
      : Button({ 
          class: 'btn btn-sm btn-ghost mt-2',
          onclick: () => notifications([])
        }, 'Clear All')
  ]);
};
Mount(NotificationsDemo, '#demo-notifications');

All Variants

Live Demo

const VariantsDemo = () => {
  return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
    Div({ class: 'text-center' }, [
      Div({ class: 'text-sm mb-2' }, 'Small Stack'),
      Stack({ class: 'w-24' }, [
        Div({ class: 'bg-primary rounded p-2 text-xs' }, '1'),
        Div({ class: 'bg-secondary rounded p-2 text-xs' }, '2'),
        Div({ class: 'bg-accent rounded p-2 text-xs' }, '3')
      ])
    ]),
    Div({ class: 'text-center' }, [
      Div({ class: 'text-sm mb-2' }, 'Medium Stack'),
      Stack({ class: 'w-32' }, [
        Div({ class: 'bg-primary rounded p-3' }, 'A'),
        Div({ class: 'bg-secondary rounded p-3' }, 'B'),
        Div({ class: 'bg-accent rounded p-3' }, 'C')
      ])
    ]),
    Div({ class: 'text-center' }, [
      Div({ class: 'text-sm mb-2' }, 'Large Stack'),
      Stack({ class: 'w-40' }, [
        Div({ class: 'bg-primary rounded p-4' }, 'X'),
        Div({ class: 'bg-secondary rounded p-4' }, 'Y'),
        Div({ class: 'bg-accent rounded p-4' }, 'Z')
      ])
    ])
  ]);
};
Mount(VariantsDemo, '#demo-variants');
<script> (function() { const initStackExamples = () => { // 1. Basic Stack const basicTarget = document.querySelector('#demo-basic'); if (basicTarget && !basicTarget.hasChildNodes()) { const BasicDemo = () => { return Stack({ class: 'w-40' }, [ Div({ class: 'bg-primary text-primary-content rounded-lg p-4 shadow-lg' }, 'Layer 1'), Div({ class: 'bg-secondary text-secondary-content rounded-lg p-4 shadow-lg' }, 'Layer 2'), Div({ class: 'bg-accent text-accent-content rounded-lg p-4 shadow-lg' }, 'Layer 3') ]); }; Mount(BasicDemo, basicTarget); } // 2. Card Stack const cardsTarget = document.querySelector('#demo-cards'); if (cardsTarget && !cardsTarget.hasChildNodes()) { const CardsDemo = () => { return Stack({ class: 'w-64' }, [ Div({ class: 'card bg-base-100 shadow-xl border border-base-300' }, [ Div({ class: 'card-body p-4' }, [ Span({ class: 'text-sm opacity-70' }, 'Back Card'), Span({ class: 'font-bold' }, 'Additional info') ]) ]), Div({ class: 'card bg-primary text-primary-content shadow-xl' }, [ Div({ class: 'card-body p-4' }, [ Span({ class: 'text-sm' }, 'Front Card'), Span({ class: 'font-bold text-lg' }, 'Main Content') ]) ]) ]); }; Mount(CardsDemo, cardsTarget); } // 3. Avatar Stack const avatarsTarget = document.querySelector('#demo-avatars'); if (avatarsTarget && !avatarsTarget.hasChildNodes()) { const AvatarsDemo = () => { return Stack({ class: 'w-32' }, [ Div({ class: 'avatar placeholder' }, [ Div({ class: 'bg-neutral text-neutral-content rounded-full w-16' }, [ Span({}, 'JD') ]) ]), Div({ class: 'avatar placeholder' }, [ Div({ class: 'bg-primary text-primary-content rounded-full w-16' }, [ Span({}, 'JS') ]) ]), Div({ class: 'avatar placeholder' }, [ Div({ class: 'bg-secondary text-secondary-content rounded-full w-16' }, [ Span({}, 'BC') ]) ]) ]); }; Mount(AvatarsDemo, avatarsTarget); } // 4. Image Stack const imagesTarget = document.querySelector('#demo-images'); if (imagesTarget && !imagesTarget.hasChildNodes()) { const ImagesDemo = () => { return Stack({ class: 'w-48' }, [ Div({ class: 'w-full h-32 bg-gradient-to-r from-primary to-secondary rounded-lg shadow-lg' }, [ Div({ class: 'p-2 text-white text-sm' }, 'Background Image') ]), Div({ class: 'w-full h-32 bg-gradient-to-r from-secondary to-accent rounded-lg shadow-lg translate-x-2 translate-y-2' }, [ Div({ class: 'p-2 text-white text-sm' }, 'Middle Layer') ]), Div({ class: 'w-full h-32 bg-gradient-to-r from-accent to-primary rounded-lg shadow-lg translate-x-4 translate-y-4 flex items-center justify-center' }, [ Span({ class: 'text-white font-bold' }, 'Top Layer') ]) ]); }; Mount(ImagesDemo, imagesTarget); } // 5. Photo Gallery Stack const galleryTarget = document.querySelector('#demo-gallery'); if (galleryTarget && !galleryTarget.hasChildNodes()) { const GalleryDemo = () => { const photos = [ { color: 'bg-primary', label: 'Photo 1' }, { color: 'bg-secondary', label: 'Photo 2' }, { color: 'bg-accent', label: 'Photo 3' }, { color: 'bg-info', label: 'Photo 4' } ]; return Stack({ class: 'w-48 cursor-pointer hover:scale-105 transition-transform' }, [ ...photos.map((photo, idx) => Div({ class: `${photo.color} rounded-lg shadow-lg transition-all`, style: `transform: translate(${idx * 4}px, ${idx * 4}px); width: 100%; height: 100%;` }, [ Div({ class: 'p-4 text-white font-bold' }, photo.label) ]) ) ]); }; Mount(GalleryDemo, galleryTarget); } // 6. Interactive Stack const interactiveTarget = document.querySelector('#demo-interactive'); if (interactiveTarget && !interactiveTarget.hasChildNodes()) { const InteractiveDemo = () => { const active = $(0); const colors = ['primary', 'secondary', 'accent', 'info', 'success']; const labels = ['Home', 'Profile', 'Settings', 'Messages', 'Notifications']; return Div({ class: 'flex flex-col gap-6 items-center' }, [ Stack({ class: 'w-56' }, colors.map((color, idx) => Div({ class: `bg-${color} text-${color}-content rounded-lg p-4 shadow-lg transition-all cursor-pointer ${idx === active() ? 'scale-105 z-10' : ''}`, style: `transform: translate(${idx * 8}px, ${idx * 8}px);`, onclick: () => active(idx) }, [ Div({ class: 'font-bold' }, labels[idx]), Div({ class: 'text-sm opacity-80' }, `Layer ${idx + 1}`) ]) )), Div({ class: 'mt-4 text-center' }, [ Span({ class: 'font-bold' }, () => `Active: ${labels[active()]}`), Div({ class: 'flex gap-2 mt-2' }, colors.map((_, idx) => Button({ class: `btn btn-xs ${idx === active() ? 'btn-primary' : 'btn-ghost'}`, onclick: () => active(idx) }, `${idx + 1}`) )) ]) ]); }; Mount(InteractiveDemo, interactiveTarget); } // 7. Notification Stack const notificationsTarget = document.querySelector('#demo-notifications'); if (notificationsTarget && !notificationsTarget.hasChildNodes()) { const NotificationsDemo = () => { const notifications = $([ { id: 1, message: 'New message from John', type: 'info' }, { id: 2, message: 'Your order has shipped', type: 'success' }, { id: 3, message: 'Meeting in 10 minutes', type: 'warning' } ]); const removeNotification = (id) => { notifications(notifications().filter(n => n.id !== id)); }; const typeClasses = { info: 'bg-info text-info-content', success: 'bg-success text-success-content', warning: 'bg-warning text-warning-content', error: 'bg-error text-error-content' }; return Div({ class: 'flex flex-col gap-4 items-center' }, [ Stack({ class: 'w-80' }, notifications().map((notif, idx) => Div({ class: `${typeClasses[notif.type]} rounded-lg p-3 shadow-lg transition-all cursor-pointer`, style: `transform: translate(${idx * 4}px, ${idx * 4}px);`, onclick: () => removeNotification(notif.id) }, [ Div({ class: 'flex justify-between items-center' }, [ Span({ class: 'text-sm' }, notif.message), Span({ class: 'text-xs opacity-70 cursor-pointer hover:opacity-100' }, '✕') ]) ]) )), notifications().length === 0 ? Div({ class: 'alert alert-soft' }, 'No notifications') : Button({ class: 'btn btn-sm btn-ghost mt-2', onclick: () => notifications([]) }, 'Clear All') ]); }; Mount(NotificationsDemo, notificationsTarget); } // 8. All Variants const variantsTarget = document.querySelector('#demo-variants'); if (variantsTarget && !variantsTarget.hasChildNodes()) { const VariantsDemo = () => { return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [ Div({ class: 'text-center' }, [ Div({ class: 'text-sm mb-2' }, 'Small Stack'), Stack({ class: 'w-24' }, [ Div({ class: 'bg-primary rounded p-2 text-xs' }, '1'), Div({ class: 'bg-secondary rounded p-2 text-xs' }, '2'), Div({ class: 'bg-accent rounded p-2 text-xs' }, '3') ]) ]), Div({ class: 'text-center' }, [ Div({ class: 'text-sm mb-2' }, 'Medium Stack'), Stack({ class: 'w-32' }, [ Div({ class: 'bg-primary rounded p-3' }, 'A'), Div({ class: 'bg-secondary rounded p-3' }, 'B'), Div({ class: 'bg-accent rounded p-3' }, 'C') ]) ]), Div({ class: 'text-center' }, [ Div({ class: 'text-sm mb-2' }, 'Large Stack'), Stack({ class: 'w-40' }, [ Div({ class: 'bg-primary rounded p-4' }, 'X'), Div({ class: 'bg-secondary rounded p-4' }, 'Y'), Div({ class: 'bg-accent rounded p-4' }, 'Z') ]) ]) ]); }; Mount(VariantsDemo, variantsTarget); } }; initStackExamples(); if (window.$docsify) { window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => { hook.doneEach(initStackExamples); }); } })(); </script>