Files
sigpro-ui/docs/components/indicator.md
2026-04-03 01:41:07 +02:00

9.3 KiB
Raw Blame History

Indicator

Indicator component for adding badges, status markers, or notifications to elements. Perfect for showing counts, online status, or alerts.

Tag

Indicator

Props

Prop Type Default Description
value string | VNode | Signal - Content to display as indicator
class string '' Additional CSS classes for the badge
children VNode - Element to attach the indicator to

Styling

Indicator uses daisyUI Indicator and Badge classes:

Category Keywords Description
Position indicator-start, indicator-end, indicator-top, indicator-bottom Indicator position (default: top-end)
Badge Color badge-primary, badge-secondary, badge-accent, badge-info, badge-success, badge-warning, badge-error Badge visual variants
Badge Size badge-xs, badge-sm, badge-md, badge-lg Badge scale

For further details, check the daisyUI Indicator Documentation Full reference for CSS classes.

Example

Indicator({ value: "3", class: "badge-primary" },
  Button({ class: "btn" }, "Notifications")
);

Live Examples

Basic Indicator

Live Demo

const BasicDemo = () => {
  return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
    Indicator({ value: '3', class: 'badge-primary' },
      Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '📦')
    ),
    Indicator({ value: '99+', class: 'badge-secondary' },
      Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '🔔')
    ),
    Indicator({ value: 'New', class: 'badge-accent' },
      Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '✨')
    )
  ]);
};
$mount(BasicDemo, '#demo-basic');

Online Status Indicator

Live Demo

const StatusDemo = () => {
  return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
    Indicator({ value: '●', class: 'badge-success badge-xs' },
      Div({ class: 'avatar placeholder' }, [
        Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'JD')
      ])
    ),
    Indicator({ value: '●', class: 'badge-warning badge-xs' },
      Div({ class: 'avatar placeholder' }, [
        Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'JS')
      ])
    ),
    Indicator({ value: '●', class: 'badge-error badge-xs' },
      Div({ class: 'avatar placeholder' }, [
        Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'BC')
      ])
    )
  ]);
};
$mount(StatusDemo, '#demo-status');

Reactive Counter

Live Demo

const ReactiveDemo = () => {
  const count = $(0);
  
  return Div({ class: 'flex flex-col gap-4 items-center' }, [
    Indicator({ 
      value: () => count() > 0 ? count() : null,
      class: 'badge-primary'
    },
      Button({ 
        class: 'btn btn-lg btn-primary',
        onclick: () => count(count() + 1)
      }, 'Notifications')
    ),
    Div({ class: 'flex gap-2' }, [
      Button({ 
        class: 'btn btn-sm',
        onclick: () => count(Math.max(0, count() - 1))
      }, 'Decrease'),
      Button({ 
        class: 'btn btn-sm btn-ghost',
        onclick: () => count(0)
      }, 'Clear')
    ])
  ]);
};
$mount(ReactiveDemo, '#demo-reactive');

Shopping Cart

Live Demo

const CartDemo = () => {
  const cart = $([
    { id: 1, name: 'Product 1', price: 29 },
    { id: 2, name: 'Product 2', price: 49 }
  ]);
  
  const addItem = () => {
    const newId = Math.max(...cart().map(i => i.id), 0) + 1;
    cart([...cart(), { id: newId, name: `Product ${newId}`, price: Math.floor(Math.random() * 100) + 10 }]);
    Toast('Item added to cart', 'alert-success', 1500);
  };
  
  const removeItem = (id) => {
    cart(cart().filter(item => item.id !== id));
    Toast('Item removed', 'alert-info', 1500);
  };
  
  const total = () => cart().reduce((sum, item) => sum + item.price, 0);
  
  return Div({ class: 'flex flex-col gap-4' }, [
    Div({ class: 'flex justify-between items-center' }, [
      Indicator({ 
        value: () => cart().length,
        class: 'badge-primary'
      },
        Button({ class: 'btn', onclick: addItem }, '🛒 Add to Cart')
      ),
      Span({ class: 'text-lg font-bold' }, () => `Total: $${total()}`)
    ]),
    cart().length === 0 
      ? Div({ class: 'alert alert-soft text-center' }, 'Cart is empty')
      : Div({ class: 'flex flex-col gap-2' }, cart().map(item =>
        Div({ class: 'flex justify-between items-center p-2 bg-base-200 rounded-lg' }, [
          Span({}, item.name),
          Div({ class: 'flex gap-2 items-center' }, [
            Span({ class: 'text-sm font-bold' }, `$${item.price}`),
            Button({ 
              class: 'btn btn-xs btn-ghost btn-circle',
              onclick: () => removeItem(item.id)
            }, '✕')
          ])
        ])
      ))
  ]);
};
$mount(CartDemo, '#demo-cart');

Email Inbox

Live Demo

const InboxDemo = () => {
  const unread = $(3);
  const messages = $([
    { id: 1, from: 'john@example.com', subject: 'Meeting tomorrow', read: false },
    { id: 2, from: 'jane@example.com', subject: 'Project update', read: false },
    { id: 3, from: 'bob@example.com', subject: 'Question about design', read: false },
    { id: 4, from: 'alice@example.com', subject: 'Weekly report', read: true }
  ]);
  
  const markAsRead = (id) => {
    const msg = messages().find(m => m.id === id);
    if (!msg.read) {
      msg.read = true;
      messages([...messages()]);
      unread(unread() - 1);
    }
  };
  
  return Div({ class: 'flex flex-col gap-4' }, [
    Div({ class: 'flex justify-between items-center' }, [
      Indicator({ 
        value: () => unread(),
        class: 'badge-primary'
      },
        Span({ class: 'text-lg font-bold' }, 'Inbox')
      ),
      Button({ 
        class: 'btn btn-sm btn-ghost',
        onclick: () => {
          messages().forEach(m => m.read = true);
          messages([...messages()]);
          unread(0);
        }
      }, 'Mark all read')
    ]),
    Div({ class: 'flex flex-col gap-2' }, messages().map(msg =>
      Div({ 
        class: `p-3 rounded-lg cursor-pointer transition-all ${msg.read ? 'bg-base-200 opacity-60' : 'bg-primary/10 border-l-4 border-primary'}`,
        onclick: () => markAsRead(msg.id)
      }, [
        Div({ class: 'font-medium' }, msg.from),
        Div({ class: 'text-sm' }, msg.subject),
        !msg.read && Span({ class: 'badge badge-xs badge-primary mt-1' }, 'New')
      ])
    ))
  ]);
};
$mount(InboxDemo, '#demo-inbox');

All Variants

Live Demo

const VariantsDemo = () => {
  return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [
    Indicator({ value: '3', class: 'badge-primary badge-sm' },
      Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '📧')
    ),
    Indicator({ value: '99+', class: 'badge-secondary badge-md' },
      Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '🔔')
    ),
    Indicator({ value: '●', class: 'badge-success badge-xs' },
      Div({ class: 'avatar' }, [
        Div({ class: 'w-10 h-10 rounded-full bg-primary' })
      ])
    ),
    Indicator({ value: '!', class: 'badge-error badge-sm' },
      Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '⚠️')
    )
  ]);
};
$mount(VariantsDemo, '#demo-variants');