bigbullui logobigbullui
Componentticket-stub

Trophy Shelf

Trophy shelf with earned/empty slots and drop-in animation.

Preview

Live Preview
Kupa2026

1/1 kazanılan

Installation

Tokens guide →

Add to your project via CLI (zero dependencies, code you own):

npx bigbullui add trophy-shelf

Or install the full npm package:

npm install bigbullui

Usage

import { TrophyShelf } from "@/components/ui/trophy-shelf";

<TrophyShelf />

Source code

trophy-shelf.tsx

Zero dependencies (only React + utils). Copy and paste directly into your project:

"use client";

import * as React from "react";
import { cn } from "./lib/utils";

export interface TrophyShelfProps extends React.HTMLAttributes<HTMLDivElement> {
  trophies: { id: string; label: string; year: string; earned?: boolean }[];
}

/** Kupa rafı: kazanılan kupalar + parıltı + boş slotlar. */
export function TrophyShelf({ trophies, className, ...props }: TrophyShelfProps) {
  return (
    <div className={cn("w-full max-w-sm", className)} {...props}>
      <style>{`@keyframes trIn { 0% { transform: translateY(-14px) scale(0.8); opacity: 0; } 70% { transform: translateY(2px) scale(1.05); opacity: 1; } 100% { transform: translateY(0) scale(1); opacity: 1; } }`}</style>
      <div className="rounded-lg border-2 border-dashed border-border bg-card p-4">
        <div className="flex items-end justify-around gap-2">
          {trophies.map((t, idx) => (
            <div key={t.id} className="flex flex-col items-center gap-1" style={{ width: `${100 / trophies.length}%` }}>
              <span
                className={cn("text-3xl", !t.earned && "opacity-25 grayscale")}
                style={t.earned ? { animation: `trIn 0.5s cubic-bezier(0.34,1.56,0.64,1) both`, animationDelay: `${idx * 120}ms` } : undefined}
                aria-hidden="true"
              >
                🏆
              </span>
              <span className={cn("h-1 w-full rounded-full", t.earned ? "bg-accent" : "bg-border/40")} aria-hidden="true" />
              <span className={cn("text-center text-[9px] font-medium leading-tight", t.earned ? "text-foreground" : "text-muted-foreground")}>{t.label}</span>
              <span className="font-mono text-[8px] text-muted-foreground">{t.year}</span>
            </div>
          ))}
        </div>
        <p className="mt-2 text-center font-mono text-[9px] uppercase tracking-widest text-muted-foreground">
          {trophies.filter((t) => t.earned).length}/{trophies.length} kazanılan
        </p>
      </div>
    </div>
  );
}

Props

PropTypeDescription
trophies{ id: string; label: string; year: string; earned?: boolean }[]