Menu

Change language

GitHub repo

Testimonial — Single Featured

blockmarketing

One large pull quote given the full section: oversized text, attribution with avatar and role, the customer wordmark, and a supporting result metric beside it.

Installation

$npx uipkge-ng@latest add testimonial-single-featured
Manifest:https://uipkge.dev/r/angular/testimonial-single-featured.jsonInstalls to:src/app/components/blocks/testimonial-single-featured/

Variants

Loading interactive previews…

Files installed (2)

  • src/app/components/blocks/testimonial-single-featured/testimonial-single-featured.component.ts3.2 kB
    // One large pull quote given the full section: oversized text, attribution with
    // avatar and role, the customer wordmark, and a supporting result metric beside it.
    // Port of the Vue/React block 1:1.
    import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
    import { ArrowRight, LucideAngularModule } from 'lucide-angular'
    import { cn } from '@/lib/utils'
    import { UiAvatarComponent, UiAvatarFallbackComponent } from '@/ui/avatar/avatar.component'
    import { UiBadgeComponent } from '@/ui/badge/badge.component'
    import { UiButtonComponent } from '@/ui/button/button.component'
    import { UiSeparatorComponent } from '@/ui/separator/separator.component'
    
    @Component({
      changeDetection: ChangeDetectionStrategy.Eager,
      selector: 'ui-testimonial-single-featured, [ui-testimonial-single-featured]',
      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,
        UiAvatarComponent,
        UiAvatarFallbackComponent,
        UiBadgeComponent,
        UiButtonComponent,
        UiSeparatorComponent,
      ],
      template: `
        <section data-slot="testimonial-single-featured" [class]="rootClass">
          <div class="mx-auto max-w-5xl px-6 py-20 lg:py-28">
            <span ui-badge variant="secondary">Customer</span>
    
            <!-- One quote, given the whole section. Keep it short: the size is what
                 carries it, and a long quote at this scale stops being readable. -->
            <blockquote class="mt-6 text-2xl leading-tight font-medium tracking-tight text-balance sm:text-3xl lg:text-4xl">
              “We stopped arguing about whose number was right and started arguing about what to do next.”
            </blockquote>
    
            <div class="mt-10 grid gap-8 sm:grid-cols-[1fr_auto] sm:items-center">
              <div class="flex items-center gap-4">
                <ui-avatar class="size-12">
                  <ui-avatar-fallback>EW</ui-avatar-fallback>
                </ui-avatar>
                <div>
                  <p class="font-medium">Erin Walsh</p>
                  <p class="text-muted-foreground text-sm">VP Finance · Northwind Logistics</p>
                </div>
                <ui-separator orientation="vertical" class="ml-2 hidden h-10 sm:block" />
                <span class="hidden text-sm font-semibold tracking-[0.18em] uppercase sm:inline">Northwind</span>
              </div>
    
              <div class="sm:text-right">
                <p class="font-display text-3xl font-bold tracking-tight">5 days</p>
                <p class="text-muted-foreground mt-1 text-sm">off the monthly close</p>
              </div>
            </div>
    
            <ui-separator class="my-10" />
    
            <div class="flex flex-wrap items-center justify-between gap-4">
              <p class="text-muted-foreground text-sm">Freight forwarding · 1,200 staff · live since Q1 2026</p>
              <button ui-button variant="outline">
                Read the full story
                <lucide-icon [img]="ArrowRight" class="ml-2 size-4" aria-hidden="true" />
              </button>
            </div>
          </div>
        </section>
      `,
    })
    export class UiTestimonialSingleFeaturedComponent {
      protected readonly ArrowRight = ArrowRight
    
      @Input('class') className?: string
    
      get rootClass(): string {
        return cn('bg-background', this.className)
      }
    }
    
  • src/app/components/blocks/testimonial-single-featured/index.ts0.1 kB

Raw manifest:https://uipkge.dev/r/angular/testimonial-single-featured.json