Category Showcase
blockcommerceE-commerce category bento grid and featured collections showcase with interactive hover zoom effects, promo sale banner, and bento or uniform grid layouts.
Installation
$pnpm dlx uipkge-ng@latest add category-showcase$npx uipkge-ng@latest add category-showcase$yarn dlx uipkge-ng@latest add category-showcase$bunx uipkge-ng@latest add category-showcaseManifest:
https://uipkge.dev/r/angular/category-showcase.jsonInstalls to:src/app/components/blocks/category-showcase/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (2)
src/app/components/blocks/category-showcase/category-showcase.component.ts13.5 kB
// E-commerce "Shop by Category" section. Edit the tiles inline -- each one is spelled out as a // sibling so its image, copy and badges can change independently. import { Component, Input, ChangeDetectionStrategy } from '@angular/core' import { ArrowRight, LucideAngularModule, Percent, ShoppingBag } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component' export type CategoryShowcaseVariant = 'bento' | 'grid' const tileBase = 'group border-border bg-card relative flex flex-col justify-between overflow-hidden shadow-xs transition-colors duration-300 hover:shadow-md' /** * CategoryShowcase -- the React block, 1:1: a section header (badge, title, "View all * collections" link) over a bento (4x2, hero tile 2x2) or uniform grid of category tiles with * image scrims and hover zoom, closed by an archive sale promo tile. */ @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-category-showcase, [ui-category-showcase]', standalone: true, // React renders the root <section> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardContentComponent], template: ` <section data-slot="category-showcase" [class]="rootClass"> <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8"> <!-- Section Header --> <div class="mb-8 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-end lg:mb-12"> <div class="space-y-3"> <span ui-badge wrap variant="outline" class="gap-1.5 px-3 py-1 text-xs font-medium"> <lucide-icon [img]="ShoppingBag" class="text-primary size-3.5" /> Explore Collections </span> <h2 class="text-foreground text-3xl font-semibold tracking-tight sm:text-4xl">Shop by Category</h2> <p class="text-muted-foreground max-w-2xl text-sm sm:text-base"> Curated essentials designed for everyday performance. </p> </div> <a href="#" class="group/link text-primary hover:text-primary/80 inline-flex min-h-6 items-center gap-1.5 text-sm font-medium transition-colors" > View all collections <lucide-icon [img]="ArrowRight" [class]="'size-4 transition-transform duration-200 group-hover/link:translate-x-1'" /> </a> </div> <!-- Bento / Grid Showcase --> <div [class]="gridClass"> <!-- Tile 1: Featured Hero Tile (2x2 in bento) --> <div ui-card [class]="heroClass"> <img src="https://images.unsplash.com/photo-1544441893-675973e31985?w=1200&auto=format&fit=crop&q=80" alt="Performance Outerwear collection" class="absolute inset-0 size-full object-cover transition-transform duration-500 ease-out group-hover:scale-105" /> <div class="absolute inset-0 bg-gradient-to-t from-black/90 via-black/45 to-black/15"></div> <div ui-card-content class="relative z-10 flex h-full flex-col justify-between p-6 sm:p-8"> <div class="flex flex-wrap items-center justify-between gap-3"> <span ui-badge wrap variant="secondary" class="bg-background/80 text-foreground border-white/15 text-xs font-medium shadow-xs backdrop-blur-md" > Featured Collection </span> <span ui-badge wrap variant="outline" class="border-white/20 bg-white/10 text-xs font-medium text-white backdrop-blur-xs" > Explore 32 Styles </span> </div> <div class="space-y-4"> <div class="space-y-2"> <h3 class="text-2xl font-bold tracking-tight text-white sm:text-3xl lg:text-4xl"> Performance Outerwear </h3> <p class="line-clamp-2 max-w-md text-sm text-zinc-200"> Engineered weatherproof shells, insulated parkas, and technical layers designed for extreme climates. </p> </div> <button ui-button size="sm" class="group/btn w-fit bg-white font-medium text-zinc-900 shadow-sm hover:bg-white/90 focus-visible:ring-white" > Shop Collection <lucide-icon [img]="ArrowRight" [class]="'ml-1.5 size-4 transition-transform duration-200 group-hover/btn:translate-x-0.5'" /> </button> </div> </div> </div> <!-- Tile 2: Footwear & Running --> <div ui-card [class]="tileClass"> <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=800&auto=format&fit=crop&q=80" alt="Footwear and running sneakers" class="absolute inset-0 size-full object-cover transition-transform duration-500 ease-out group-hover:scale-105" /> <div class="absolute inset-0 bg-gradient-to-t from-black/85 via-black/35 to-black/10"></div> <div ui-card-content class="relative z-10 flex h-full flex-col justify-between p-6"> <div class="flex items-center justify-between"> <span ui-badge wrap variant="secondary" class="bg-background/80 text-foreground border-white/15 text-xs font-medium shadow-xs backdrop-blur-md" > 18 Items </span> </div> <div class="space-y-1"> <h3 class="text-lg font-semibold tracking-tight text-white transition-colors group-hover:text-white/90"> Footwear & Running </h3> <span class="inline-flex items-center gap-1 text-xs font-medium text-zinc-300"> View products <lucide-icon [img]="ArrowRight" [class]="'size-3 transition-transform duration-200 group-hover:translate-x-0.5'" /> </span> </div> </div> </div> <!-- Tile 3: Accessories & Bags --> <div ui-card [class]="tileClass"> <img src="https://images.unsplash.com/photo-1553062407-98eeb64c6a62?w=800&auto=format&fit=crop&q=80" alt="Accessories and bags collection" class="absolute inset-0 size-full object-cover transition-transform duration-500 ease-out group-hover:scale-105" /> <div class="absolute inset-0 bg-gradient-to-t from-black/85 via-black/35 to-black/10"></div> <div ui-card-content class="relative z-10 flex h-full flex-col justify-between p-6"> <div class="flex items-center gap-2"> <span ui-badge wrap class="bg-primary text-primary-foreground border-transparent text-xs font-medium shadow-xs" > New Season </span> <span ui-badge wrap variant="secondary" class="bg-background/80 text-foreground border-white/15 text-xs font-medium shadow-xs backdrop-blur-md" > 24 Items </span> </div> <div class="space-y-1"> <h3 class="text-lg font-semibold tracking-tight text-white transition-colors group-hover:text-white/90"> Accessories & Bags </h3> <span class="inline-flex items-center gap-1 text-xs font-medium text-zinc-300"> View products <lucide-icon [img]="ArrowRight" [class]="'size-3 transition-transform duration-200 group-hover:translate-x-0.5'" /> </span> </div> </div> </div> <!-- Tile 4: Everyday Apparel --> <div ui-card [class]="wideTileClass"> <img src="https://images.unsplash.com/photo-1521572267360-ee0c2909d518?w=800&auto=format&fit=crop&q=80" alt="Everyday apparel collection" class="absolute inset-0 size-full object-cover transition-transform duration-500 ease-out group-hover:scale-105" /> <div class="absolute inset-0 bg-gradient-to-t from-black/85 via-black/35 to-black/10"></div> <div ui-card-content class="relative z-10 flex h-full flex-col justify-between p-6"> <div class="flex items-center justify-between"> <span ui-badge wrap variant="secondary" class="bg-background/80 text-foreground border-white/15 text-xs font-medium shadow-xs backdrop-blur-md" > 45 Items </span> </div> <div class="space-y-1"> <h3 class="text-lg font-semibold tracking-tight text-white transition-colors group-hover:text-white/90"> Everyday Apparel </h3> <span class="inline-flex items-center gap-1 text-xs font-medium text-zinc-300"> View products <lucide-icon [img]="ArrowRight" [class]="'size-3 transition-transform duration-200 group-hover:translate-x-0.5'" /> </span> </div> </div> </div> <!-- Tile 5: Sale Special Promo Tile --> <div ui-card [class]="promoClass"> <div class="bg-primary/15 group-hover:bg-primary/25 pointer-events-none absolute -right-8 -bottom-8 size-36 rounded-full blur-2xl transition-colors duration-500" ></div> <div ui-card-content class="relative z-10 flex h-full flex-col justify-between p-6"> <div class="flex items-center justify-between gap-2"> <div class="bg-primary/10 text-primary flex size-9 items-center justify-center rounded-lg"> <lucide-icon [img]="Percent" class="size-4" /> </div> <span ui-badge wrap variant="outline" class="border-primary/30 bg-primary/10 text-primary font-mono text-xs uppercase" > ARCHIVE40 </span> </div> <div class="space-y-3"> <div class="space-y-1"> <p class="text-primary text-xs font-medium tracking-wider uppercase">Limited Time Promo</p> <h3 class="text-foreground text-base font-semibold tracking-tight">Archive Sale · Up to 40% Off</h3> <p class="text-muted-foreground text-xs leading-relaxed"> Seasonal essentials and core archive styles at exclusive discounted rates. </p> </div> <button ui-button size="sm" class="group/btn w-full"> Shop Sale <lucide-icon [img]="ArrowRight" [class]="'ml-1.5 size-4 transition-transform duration-200 group-hover/btn:translate-x-0.5'" /> </button> </div> </div> </div> </div> </div> </section> `, }) export class UiCategoryShowcaseComponent { /** `bento`: 4x2 grid with a 2x2 hero tile. `grid`: uniform 4-column grid. */ @Input() variant: CategoryShowcaseVariant = 'bento' @Input('class') className?: string protected readonly ArrowRight = ArrowRight protected readonly Percent = Percent protected readonly ShoppingBag = ShoppingBag private get bento(): boolean { return this.variant === 'bento' } protected get rootClass(): string { return cn('bg-background w-full py-12 sm:py-16 lg:py-20', this.className) } protected get gridClass(): string { return cn('grid grid-cols-1 gap-4 sm:grid-cols-2', this.bento ? 'lg:grid-cols-4 lg:grid-rows-2' : 'lg:grid-cols-4') } protected get heroClass(): string { return cn( tileBase, this.bento ? 'min-h-[460px] sm:col-span-2 lg:col-span-2 lg:row-span-2 lg:min-h-[560px]' : 'min-h-[320px] sm:col-span-2 lg:col-span-2', ) } protected get tileClass(): string { return cn(tileBase, 'col-span-1 min-h-[260px]') } protected get wideTileClass(): string { return cn( tileBase, this.bento ? 'col-span-1 min-h-[260px]' : 'col-span-1 min-h-[260px] sm:col-span-2 lg:col-span-2', ) } protected get promoClass(): string { return cn( 'group border-primary/20 bg-primary/5 hover:border-primary/40 dark:bg-primary/10 relative flex flex-col justify-between overflow-hidden shadow-xs transition-colors duration-300 hover:shadow-md', this.bento ? 'col-span-1 min-h-[260px]' : 'col-span-1 min-h-[260px] sm:col-span-2 lg:col-span-2', ) } }src/app/components/blocks/category-showcase/index.ts0.1 kB
export { UiCategoryShowcaseComponent, type CategoryShowcaseVariant } from './category-showcase.component'
Raw manifest:https://uipkge.dev/r/angular/category-showcase.json