{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "settings-page",
  "title": "Settings Page",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-angular/blocks/settings-page/settings-page.component.ts",
      "content": "// Linear-style settings shell: a nav rail of icon sections (collapses to a horizontal\n// tab strip on narrow screens) switching between fully composed panels — profile form with\n// sticky save bar, notification switches, theme picker, workspace identity, billing summary,\n// and a type-to-confirm danger zone. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport {\n  Bell,\n  Building2,\n  CreditCard,\n  LucideAngularModule,\n  Palette,\n  TriangleAlert,\n  User,\n  type LucideIconData,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiDialogComponent,\n  UiDialogContentComponent,\n  UiDialogDescriptionComponent,\n  UiDialogFooterComponent,\n  UiDialogHeaderComponent,\n  UiDialogTitleComponent,\n} from '@/ui/dialog/dialog.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiLabelComponent } from '@/ui/label/label.component'\nimport { UiSectionCardComponent } from '@/ui/section-card/section-card.component'\nimport {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport { UiSwitchComponent } from '@/ui/switch/switch.component'\nimport { UiTextareaComponent } from '@/ui/textarea/textarea.component'\n\nexport type SectionId = 'profile' | 'notifications' | 'appearance' | 'workspace' | 'billing' | 'danger'\n\nexport interface SettingsSection {\n  id: SectionId\n  label: string\n  icon: LucideIconData\n}\n\nconst defaultSections: SettingsSection[] = [\n  { id: 'profile', label: 'Profile', icon: User },\n  { id: 'notifications', label: 'Notifications', icon: Bell },\n  { id: 'appearance', label: 'Appearance', icon: Palette },\n  { id: 'workspace', label: 'Workspace', icon: Building2 },\n  { id: 'billing', label: 'Billing', icon: CreditCard },\n  { id: 'danger', label: 'Danger zone', icon: TriangleAlert },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-settings-page, [ui-settings-page]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiButtonComponent,\n    UiDialogComponent,\n    UiDialogContentComponent,\n    UiDialogDescriptionComponent,\n    UiDialogFooterComponent,\n    UiDialogHeaderComponent,\n    UiDialogTitleComponent,\n    UiInputComponent,\n    UiLabelComponent,\n    UiSectionCardComponent,\n    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiSeparatorComponent,\n    UiSwitchComponent,\n    UiTextareaComponent,\n  ],\n  template: `\n    <div data-slot=\"settings-page\" [class]=\"rootClass\">\n      <!-- Nav rail -->\n      <nav class=\"border-border shrink-0 border-b p-3 lg:w-56 lg:border-r lg:border-b-0\" aria-label=\"Settings sections\">\n        <div\n          class=\"flex [scrollbar-width:none] gap-1 overflow-x-auto lg:flex-col lg:overflow-visible [&::-webkit-scrollbar]:hidden\"\n        >\n          @for (section of sections(); track section.id) {\n            <button type=\"button\" [class]=\"navButtonClass(section.id)\"\n              [attr.aria-current]=\"active() === section.id ? 'page' : null\"\n              (click)=\"switchPanel(section.id)\"\n            >\n              <lucide-icon [img]=\"section.icon\" class=\"size-4\" aria-hidden=\"true\" />\n              {{ section.label }}\n            </button>\n          }\n        </div>\n      </nav>\n\n      <!-- Content pane -->\n      <div class=\"flex min-w-0 flex-1 flex-col\">\n        @if (active() === 'profile') {\n          <section class=\"flex flex-1 flex-col\">\n            <div class=\"flex-1 space-y-6 p-6\">\n              <ui-section-card title=\"Public profile\" description=\"How teammates see you across the workspace.\">\n                <div class=\"space-y-4\">\n                  <div class=\"space-y-2\">\n                    <label ui-label for=\"sp-name\">Display name</label>\n                    <ui-input id=\"sp-name\" defaultValue=\"Amara Osei\" />\n                  </div>\n                  <div class=\"space-y-2\">\n                    <label ui-label for=\"sp-email\">Email</label>\n                    <ui-input id=\"sp-email\" defaultValue=\"amara@acme.com\" type=\"email\" />\n                  </div>\n                  <div class=\"space-y-2\">\n                    <label ui-label for=\"sp-bio\">Bio</label>\n                    <ui-textarea\n                      id=\"sp-bio\"\n                      defaultValue=\"Design engineer. Builds systems, breaks assumptions.\"\n                      [rows]=\"3\"\n                    />\n                  </div>\n                  <div class=\"space-y-2\">\n                    <label ui-label for=\"sp-role\">Role</label>\n                    <ui-select [value]=\"role()\" (valueChange)=\"role.set($event)\">\n                      <button ui-select-trigger id=\"sp-role\" class=\"w-full sm:w-56\">\n                        <ui-select-value />\n                      </button>\n                      <ui-select-content>\n                        <ui-select-item value=\"admin\">Admin</ui-select-item>\n                        <ui-select-item value=\"editor\">Editor</ui-select-item>\n                        <ui-select-item value=\"viewer\">Viewer</ui-select-item>\n                      </ui-select-content>\n                    </ui-select>\n                  </div>\n                </div>\n              </ui-section-card>\n            </div>\n            <div class=\"border-border flex items-center justify-end gap-2 border-t p-4\">\n              <button ui-button variant=\"ghost\" size=\"sm\">Discard</button>\n              <button ui-button size=\"sm\">Save changes</button>\n            </div>\n          </section>\n        } @else if (active() === 'notifications') {\n          <section class=\"flex-1 p-6\">\n            <ui-section-card title=\"Notifications\" description=\"Choose what reaches you and where.\">\n              <ul class=\"-my-4 divide-y\">\n                <li class=\"flex items-center justify-between gap-4 py-4\">\n                  <div>\n                    <p class=\"text-sm font-medium\">Email notifications</p>\n                    <p class=\"text-muted-foreground text-xs\">Mentions, assignments and approvals.</p>\n                  </div>\n                  <button\n                    ui-switch\n                    [checked]=\"notifyEmail()\"\n                    (checkedChange)=\"notifyEmail.set($event)\"\n                    aria-label=\"Toggle email notifications\"\n                  ></button>\n                </li>\n                <li class=\"flex items-center justify-between gap-4 py-4\">\n                  <div>\n                    <p class=\"text-sm font-medium\">Push notifications</p>\n                    <p class=\"text-muted-foreground text-xs\">Real-time browser alerts while you work.</p>\n                  </div>\n                  <button\n                    ui-switch\n                    [checked]=\"notifyPush()\"\n                    (checkedChange)=\"notifyPush.set($event)\"\n                    aria-label=\"Toggle push notifications\"\n                  ></button>\n                </li>\n                <li class=\"flex items-center justify-between gap-4 py-4\">\n                  <div>\n                    <p class=\"text-sm font-medium\">Weekly digest</p>\n                    <p class=\"text-muted-foreground text-xs\">A summary of everything, every Monday.</p>\n                  </div>\n                  <button\n                    ui-switch\n                    [checked]=\"notifyDigest()\"\n                    (checkedChange)=\"notifyDigest.set($event)\"\n                    aria-label=\"Toggle weekly digest\"\n                  ></button>\n                </li>\n              </ul>\n            </ui-section-card>\n          </section>\n        } @else if (active() === 'appearance') {\n          <section class=\"flex-1 p-6\">\n            <ui-section-card title=\"Appearance\" description=\"Theme follows your system by default.\">\n              <div class=\"space-y-5\">\n                <div class=\"grid grid-cols-3 gap-3\">\n                  @for (theme of themeChoices; track theme) {\n                    <button\n                      type=\"button\"\n                      [class]=\"themeButtonClass(theme)\"\n                      (click)=\"themeChoice.set(theme)\"\n                    >\n                      <span class=\"block text-sm font-medium capitalize\">{{ theme }}</span>\n                      <span class=\"text-muted-foreground block text-xs\">{{ themeHint(theme) }}</span>\n                    </button>\n                  }\n                </div>\n                <ui-separator />\n                <div class=\"flex items-center justify-between\">\n                  <div>\n                    <p class=\"text-sm font-medium\">Reduced motion</p>\n                    <p class=\"text-muted-foreground text-xs\">Collapse animations to instant transitions.</p>\n                  </div>\n                  <button ui-switch [checked]=\"false\" aria-label=\"Toggle reduced motion\"></button>\n                </div>\n              </div>\n            </ui-section-card>\n          </section>\n        } @else if (active() === 'workspace') {\n          <section class=\"flex-1 p-6\">\n            <ui-section-card title=\"Workspace\" description=\"Identity and defaults for everyone here.\">\n              <div class=\"space-y-4\">\n                <div class=\"space-y-2\">\n                  <label ui-label for=\"sp-ws-name\">Workspace name</label>\n                  <ui-input id=\"sp-ws-name\" defaultValue=\"Acme Inc\" />\n                </div>\n                <div class=\"space-y-2\">\n                  <label ui-label for=\"sp-ws-url\">URL slug</label>\n                  <div class=\"flex\">\n                    <span\n                      class=\"border-border bg-muted text-muted-foreground flex items-center rounded-l-md border px-3 font-mono text-xs\"\n                    >\n                      acme.uipkge.app\n                    </span>\n                    <ui-input id=\"sp-ws-url\" defaultValue=\"acme\" class=\"rounded-l-none font-mono text-xs\" />\n                  </div>\n                </div>\n                <p class=\"text-muted-foreground text-xs\">16 members · 4 pending invites</p>\n              </div>\n            </ui-section-card>\n          </section>\n        } @else if (active() === 'billing') {\n          <section class=\"flex-1 p-6\">\n            <ui-section-card title=\"Billing\" description=\"Plan, seats and invoices.\">\n              <div class=\"flex items-center justify-between gap-4\">\n                <div>\n                  <p class=\"text-sm font-medium\">Team plan · $12 / seat / month</p>\n                  <p class=\"text-muted-foreground mt-1 text-xs\">Next invoice Sep 1, 2026 · 18 seats</p>\n                </div>\n                <button ui-button variant=\"outline\" size=\"sm\">Manage billing</button>\n              </div>\n            </ui-section-card>\n          </section>\n        } @else {\n          <section class=\"flex-1 p-6\">\n            <div class=\"border-destructive/40 rounded-xl border p-6\">\n              <div class=\"flex items-center justify-between gap-4\">\n                <div>\n                  <p class=\"text-destructive text-sm font-medium\">Delete this workspace</p>\n                  <p class=\"text-muted-foreground mt-1 text-xs\">\n                    All projects, members and data will be permanently removed.\n                  </p>\n                </div>\n                <button ui-button variant=\"destructive\" size=\"sm\" (click)=\"deleteOpen.set(true)\">Delete…</button>\n              </div>\n            </div>\n          </section>\n        }\n      </div>\n\n      <ui-dialog [open]=\"deleteOpen()\" (openChange)=\"deleteOpen.set($event)\">\n        <ui-dialog-content class=\"max-w-sm\">\n          <div ui-dialog-header>\n            <h2 ui-dialog-title>Delete workspace?</h2>\n            <p ui-dialog-description>\n              This removes Acme Inc and all of its data for every member. This cannot be undone.\n            </p>\n          </div>\n          <ui-input\n            [value]=\"deleteConfirm()\"\n            (valueChange)=\"deleteConfirm.set($event)\"\n            placeholder='Type \"DELETE\" to confirm'\n          />\n          <div ui-dialog-footer>\n            <button ui-button variant=\"outline\" size=\"sm\" (click)=\"deleteOpen.set(false)\">Cancel</button>\n            <button\n              ui-button\n              variant=\"destructive\"\n              size=\"sm\"\n              [disabled]=\"deleteConfirm() !== 'DELETE'\"\n              (click)=\"deleteOpen.set(false)\"\n            >\n              Delete forever\n            </button>\n          </div>\n        </ui-dialog-content>\n      </ui-dialog>\n    </div>\n  `,\n})\nexport class UiSettingsPageComponent {\n  @Input('sections') set sectionsInput(v: SettingsSection[] | undefined) {\n    if (v) this.sectionsOverride.set([...v])\n  }\n  @Input('initialSection') set initialSectionInput(v: SectionId | undefined) {\n    if (v) this.active.set(v)\n  }\n  @Input('class') className?: string\n\n  readonly sectionsOverride = signal<SettingsSection[] | null>(null)\n  readonly sections = computed(() => this.sectionsOverride() ?? defaultSections)\n  readonly active = signal<SectionId>('profile')\n\n  readonly notifyEmail = signal(true)\n  readonly notifyPush = signal(false)\n  readonly notifyDigest = signal(true)\n  readonly role = signal('editor')\n  readonly themeChoice = signal<'light' | 'dark' | 'system'>('system')\n  readonly themeChoices: Array<'light' | 'dark' | 'system'> = ['light', 'dark', 'system']\n  readonly deleteOpen = signal(false)\n  readonly deleteConfirm = signal('')\n\n  get rootClass(): string {\n    return cn('bg-background border-border flex min-h-svh flex-col rounded-xl border lg:flex-row', this.className)\n  }\n\n  navButtonClass(id: SectionId): string {\n    // [class] overwrites the whole class attribute: the base layout/focus classes must be merged here.\n    return cn(\n      'focus-visible:ring-ring flex shrink-0 items-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n      this.active() === id\n        ? id === 'danger'\n          ? 'text-destructive bg-destructive/10'\n          : 'bg-accent text-accent-foreground'\n        : 'text-muted-foreground hover:bg-accent/50 hover:text-foreground',\n    )\n  }\n\n  themeButtonClass(theme: 'light' | 'dark' | 'system'): string {\n    return cn(\n      'focus-visible:ring-ring rounded-lg border p-3 text-left transition-colors focus-visible:ring-2 focus-visible:outline-none',\n      this.themeChoice() === theme ? 'border-primary ring-primary/20 ring-2' : 'hover:bg-accent/50',\n    )\n  }\n\n  themeHint(theme: 'light' | 'dark' | 'system'): string {\n    return theme === 'light' ? 'Bright surfaces' : theme === 'dark' ? 'Low-light friendly' : 'Match device'\n  }\n\n  switchPanel(id: SectionId): void {\n    this.active.set(id)\n  }\n}\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/settings-page/settings-page.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/settings-page/index.ts",
      "content": "export { UiSettingsPageComponent, type SectionId, type SettingsSection } from './settings-page.component'\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/settings-page/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/dialog.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/label.json",
    "https://uipkge.dev/r/angular/section-card.json",
    "https://uipkge.dev/r/angular/select.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/switch.json",
    "https://uipkge.dev/r/angular/textarea.json"
  ],
  "description": "Linear-style settings shell: a nav rail of icon sections (collapses to a horizontal tab strip on narrow screens) switching between fully composed panels — profile form with sticky save bar, notification switches, theme picker, workspace identity, billing summary, and a type-to-confirm danger zone. Swap the panel internals for your own forms.",
  "categories": [
    "layout",
    "dashboard"
  ]
}