{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "profile-menu",
  "title": "Profile Menu",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/profile-menu/profile-menu.component.ts",
      "content": "// Header-grade profile/account dropdown: default Avatar trigger (consumers can project their\n// own button), sections for upgrade / account / billing / notifications / settings / log out.\n// Emits `select` with the chosen item key. Port of the Vue block 1:1.\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, computed, signal } from '@angular/core'\nimport { BadgeCheck, Bell, CreditCard, LogOut, LucideAngularModule, Settings, Zap } from 'lucide-angular'\nimport { UiAvatarFallbackComponent, UiAvatarImageComponent, UiAvatarComponent } from '@/ui/avatar/avatar.component'\nimport {\n  UiDropdownMenuComponent,\n  UiDropdownMenuContentComponent,\n  UiDropdownMenuGroupComponent,\n  UiDropdownMenuItemComponent,\n  UiDropdownMenuLabelComponent,\n  UiDropdownMenuSeparatorComponent,\n  UiDropdownMenuTriggerComponent,\n} from '@/ui/dropdown-menu/dropdown-menu.component'\n\nexport interface ProfileMenuUser {\n  name: string\n  email: string\n  avatar?: string\n}\n\nexport type ProfileMenuKey = 'upgrade' | 'account' | 'billing' | 'notifications' | 'settings' | 'logout'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-profile-menu, [ui-profile-menu]',\n  standalone: true,\n  // Vue renders the DropdownMenu root itself: the host stays out of layout.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiAvatarComponent,\n    UiAvatarFallbackComponent,\n    UiAvatarImageComponent,\n    UiDropdownMenuComponent,\n    UiDropdownMenuContentComponent,\n    UiDropdownMenuGroupComponent,\n    UiDropdownMenuItemComponent,\n    UiDropdownMenuLabelComponent,\n    UiDropdownMenuSeparatorComponent,\n    UiDropdownMenuTriggerComponent,\n  ],\n  template: `\n    <ui-dropdown-menu data-slot=\"profile-menu\" [open]=\"open()\" (openChange)=\"open.set($event)\">\n      <button\n        ui-dropdown-menu-trigger\n        type=\"button\"\n        class=\"hover:bg-accent focus-visible:ring-ring flex size-8 items-center justify-center rounded-lg transition-colors focus-visible:ring-1 focus-visible:outline-none\"\n        aria-label=\"Open profile menu\"\n      >\n        <ng-content>\n          <ui-avatar class=\"size-7\">\n            @if (user().avatar) {\n              <ui-avatar-image [src]=\"user().avatar!\" [alt]=\"user().name\" />\n            }\n            <ui-avatar-fallback class=\"bg-primary/10 text-primary text-xs font-semibold\">\n              {{ initials() }}\n            </ui-avatar-fallback>\n          </ui-avatar>\n        </ng-content>\n      </button>\n      <ui-dropdown-menu-content class=\"w-60 rounded-lg\" align=\"end\" [sideOffset]=\"8\">\n        <ui-dropdown-menu-label class=\"p-0 font-normal\">\n          <div class=\"flex items-center gap-2 px-1 py-1.5 text-left text-sm\">\n            <ui-avatar class=\"size-9 rounded-lg\">\n              @if (user().avatar) {\n                <ui-avatar-image [src]=\"user().avatar!\" [alt]=\"user().name\" />\n              }\n              <ui-avatar-fallback class=\"bg-primary/10 text-primary rounded-lg text-xs font-semibold\">\n                {{ initials() }}\n              </ui-avatar-fallback>\n            </ui-avatar>\n            <div class=\"grid flex-1 text-left leading-tight\">\n              <span class=\"truncate text-sm font-semibold\">{{ user().name }}</span>\n              <span class=\"text-muted-foreground truncate text-xs\">{{ user().email }}</span>\n            </div>\n          </div>\n        </ui-dropdown-menu-label>\n        <ui-dropdown-menu-separator />\n        <ui-dropdown-menu-group>\n          <ui-dropdown-menu-item (select)=\"handleSelect('upgrade')\">\n            <lucide-icon [img]=\"Zap\" class=\"size-4\" />\n            Upgrade to Pro\n          </ui-dropdown-menu-item>\n        </ui-dropdown-menu-group>\n        <ui-dropdown-menu-separator />\n        <ui-dropdown-menu-group>\n          <ui-dropdown-menu-item (select)=\"handleSelect('account')\">\n            <lucide-icon [img]=\"BadgeCheck\" class=\"size-4\" />\n            Account\n          </ui-dropdown-menu-item>\n          <ui-dropdown-menu-item (select)=\"handleSelect('billing')\">\n            <lucide-icon [img]=\"CreditCard\" class=\"size-4\" />\n            Billing\n          </ui-dropdown-menu-item>\n          <ui-dropdown-menu-item (select)=\"handleSelect('notifications')\">\n            <lucide-icon [img]=\"Bell\" class=\"size-4\" />\n            Notifications\n          </ui-dropdown-menu-item>\n          <ui-dropdown-menu-item (select)=\"handleSelect('settings')\">\n            <lucide-icon [img]=\"Settings\" class=\"size-4\" />\n            Settings\n          </ui-dropdown-menu-item>\n        </ui-dropdown-menu-group>\n        <ui-dropdown-menu-separator />\n        <ui-dropdown-menu-item (select)=\"handleSelect('logout')\">\n          <lucide-icon [img]=\"LogOut\" class=\"size-4\" />\n          Log out\n        </ui-dropdown-menu-item>\n      </ui-dropdown-menu-content>\n    </ui-dropdown-menu>\n  `,\n})\nexport class UiProfileMenuComponent {\n  protected readonly BadgeCheck = BadgeCheck\n  protected readonly Bell = Bell\n  protected readonly CreditCard = CreditCard\n  protected readonly LogOut = LogOut\n  protected readonly Settings = Settings\n  protected readonly Zap = Zap\n\n  private readonly _user = signal<ProfileMenuUser>({ name: 'Alex Morgan', email: 'alex@example.com', avatar: '' })\n  readonly user = this._user.asReadonly()\n\n  @Input('user') set userInput(v: ProfileMenuUser | undefined) {\n    if (v) this._user.set(v)\n  }\n\n  @Output() select = new EventEmitter<ProfileMenuKey>()\n\n  readonly open = signal(false)\n\n  readonly initials = computed(() => {\n    const parts = this._user().name.trim().split(/\\s+/).slice(0, 2)\n    return parts.map((p) => p[0]?.toUpperCase()).join('') || 'U'\n  })\n\n  handleSelect(key: ProfileMenuKey): void {\n    this.select.emit(key)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/profile-menu/profile-menu.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/profile-menu/index.ts",
      "content": "export { UiProfileMenuComponent, type ProfileMenuKey, type ProfileMenuUser } from './profile-menu.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/profile-menu/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/avatar.json",
    "https://uipkge.dev/r/angular/dropdown-menu.json"
  ],
  "description": "Header-grade profile/account dropdown. Slot-trigger DropdownMenu the consumer wraps around their own avatar button (default trigger ships an Avatar fallback). Sections: upgrade, account/billing/notifications/settings, log out. Emits `select` with the chosen item key so consumers wire navigation and auth themselves.",
  "categories": [
    "layout",
    "dashboard",
    "overlay"
  ]
}