Code — Multi-Language Tabs
blockmarketingCode sample switcher with a language tab row, a copy control reporting its own success state, and a caption line naming the endpoint the sample calls.
Installation
$pnpm dlx uipkge-ng@latest add code-tabs-multi-language$npx uipkge-ng@latest add code-tabs-multi-language$yarn dlx uipkge-ng@latest add code-tabs-multi-language$bunx uipkge-ng@latest add code-tabs-multi-languageManifest:
https://uipkge.dev/r/angular/code-tabs-multi-language.jsonInstalls to:src/app/components/blocks/code-tabs-multi-language/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
CodeSampleinterface CodeSample {
id: string
label: string
code: string
}npm dependencies
Files installed (2)
src/app/components/blocks/code-tabs-multi-language/code-tabs-multi-language.component.ts5.2 kB
// Code sample switcher with a language tab row, a copy control reporting its own // success state, and a caption line naming the endpoint the sample calls. // Port of the React block 1:1. import { ChangeDetectionStrategy, Component, DestroyRef, inject, Input, signal } from '@angular/core' import { Check, Copy, LucideAngularModule } 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' import { UiTabsComponent, UiTabsContentComponent, UiTabsListComponent, UiTabsTriggerComponent, } from '@/ui/tabs/tabs.component' export interface CodeSample { id: string label: string code: string } // Samples are plain strings, so a highlighter can be layered on later without // touching this component. const samples: CodeSample[] = [ { id: 'curl', label: 'cURL', code: `curl https://api.northwind.dev/v1/metrics/revenue_net \\ -H "Authorization: Bearer $NORTHWIND_TOKEN" \\ -d 'window=trailing_28d' \\ -d 'group_by=region'`, }, { id: 'ts', label: 'TypeScript', code: `import { Northwind } from '@northwind/metrics' const client = new Northwind(process.env.NORTHWIND_TOKEN) const revenue = await client.metrics.get('revenue_net', { window: 'trailing_28d', groupBy: ['region'], })`, }, { id: 'python', label: 'Python', code: `from northwind import Northwind client = Northwind(os.environ["NORTHWIND_TOKEN"]) revenue = client.metrics.get( "revenue_net", window="trailing_28d", group_by=["region"], )`, }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-code-tabs-multi-language, [ui-code-tabs-multi-language]', 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, UiTabsComponent, UiTabsContentComponent, UiTabsListComponent, UiTabsTriggerComponent, ], template: ` <section data-slot="code-tabs-multi-language" [class]="rootClass"> <div class="mx-auto max-w-3xl px-6 py-20"> <span ui-badge variant="secondary">API</span> <h2 class="mt-4 text-2xl font-semibold tracking-tight">Read a certified metric in three lines</h2> <p class="text-muted-foreground mt-2"> The same definition the dashboards use. Scope is applied from the caller's token, not the query. </p> <ui-tabs defaultValue="curl" class="mt-6"> <ui-tabs-list variant="segmented" class="flex-nowrap overflow-x-auto"> @for (sample of samplesList; track sample.id) { <button ui-tabs-trigger [value]="sample.id" variant="segmented"> {{ sample.label }} </button> } </ui-tabs-list> @for (sample of samplesList; track sample.id) { <ui-tabs-content [value]="sample.id" class="mt-4"> <div ui-card> <div ui-card-content class="p-0"> <div class="border-border flex items-center gap-3 border-b px-4 py-2"> <span class="text-muted-foreground font-mono text-xs">GET /v1/metrics/revenue_net</span> <button ui-button variant="ghost" size="sm" class="ml-auto h-7 gap-1.5 text-xs" [attr.aria-label]="'Copy the ' + sample.label + ' sample'" (click)="copy(sample.code, sample.id)" > @if (copied() === sample.id) { <lucide-icon [img]="Check" class="text-success size-3.5" aria-hidden="true" /> } @else { <lucide-icon [img]="Copy" class="size-3.5" aria-hidden="true" /> } {{ copied() === sample.id ? 'Copied' : 'Copy' }} </button> </div> <pre class="overflow-x-auto p-4 font-mono text-xs leading-relaxed" ><code>{{ sample.code }}</code></pre> </div> </div> </ui-tabs-content> } </ui-tabs> </div> </section> `, }) export class UiCodeTabsMultiLanguageComponent { protected readonly Check = Check protected readonly Copy = Copy protected readonly samplesList = samples @Input('class') className?: string readonly copied = signal('') private copyTimer: ReturnType<typeof setTimeout> | undefined constructor() { inject(DestroyRef).onDestroy(() => clearTimeout(this.copyTimer)) } get rootClass(): string { return cn('bg-background', this.className) } async copy(code: string, id: string): Promise<void> { try { await navigator.clipboard.writeText(code) this.copied.set(id) clearTimeout(this.copyTimer) this.copyTimer = setTimeout(() => this.copied.set(''), 1600) } catch { // Clipboard blocked: the sample stays selectable by hand. } } }src/app/components/blocks/code-tabs-multi-language/index.ts0.1 kB
export { UiCodeTabsMultiLanguageComponent, type CodeSample } from './code-tabs-multi-language.component'
Raw manifest:https://uipkge.dev/r/angular/code-tabs-multi-language.json