Takazudo Modular Styleguide

Shared/ProductBundleBadge

Bundle
Not Bundle

Component Source

product-bundle-badge.tsx

/**
 * BUNDLE badge overlay for product listing images.
 *
 * Renders a diagonal ribbon at TOP-RIGHT of the thumbnail for the 5 ADDAC120
 * system bundles. Positioned at TOP-RIGHT to avoid clashing with the
 * `ProductStatusBadge` incoming-status ribbon which occupies TOP-LEFT.
 *
 * Gate: render only when `isBundle` is true (`bundle != null` on the product).
 * Never gates on `brandBasedCategory` — that would incorrectly include the
 * 7 ADDAC120 modules and the frame.
 */

interface ProductBundleBadgeProps {
  isBundle: boolean;
}

export function ProductBundleBadge({ isBundle }: ProductBundleBadgeProps) {
  if (!isBundle) return null;

  return (
    <div className="absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none">
      <div className="absolute top-[12px] right-[-35px] sm:top-[18px] sm:right-[-40px] md:top-[22px] md:right-[-45px] w-[140px] sm:w-[160px] md:w-[180px] bg-zd-warning text-zd-black text-center py-[3px] md:py-[4px] text-[10px] sm:text-[11px] md:text-xs leading-normal font-bold font-futura transform rotate-45">
        BUNDLE
      </div>
    </div>
  );
}

Story Source

product-bundle-badge.stories.tsx

import { ProductBundleBadge } from './product-bundle-badge';

/**
 * ProductBundleBadge Component
 *
 * BUNDLE marker overlay for product listing images. Renders a flat orange
 * diagonal corner-ribbon at TOP-RIGHT for the 5 ADDAC120 system bundles
 * (master-data `bundle != null`). Positioned at TOP-RIGHT to avoid clashing
 * with the `ProductStatusBadge` incoming-status ribbon at TOP-LEFT.
 */
export const meta = {
  title: 'Shared/ProductBundleBadge',
};

const ImageBox = ({ children }: { children: preact.ComponentChildren }) => (
  <div className="relative w-[200px] h-[200px] border border-zd-white bg-zd-gray/20 overflow-hidden">
    <img
      src="https://placehold.co/200x200/333/ccc?text=Product"
      alt="placeholder"
      className="w-full h-full object-cover"
    />
    {children}
  </div>
);

/**
 * Bundle product — flat orange BUNDLE ribbon at top-right
 */
export const Bundle = () => (
  <ImageBox>
    <ProductBundleBadge isBundle={true} />
  </ImageBox>
);

/**
 * Non-bundle product — renders nothing
 */
export const NotBundle = () => (
  <ImageBox>
    <ProductBundleBadge isBundle={false} />
  </ImageBox>
);