@ziadshalaby/ngx-zs-component 2.0.9 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { Component, signal, Injectable, inject, input, computed, effect, output, viewChild, model, untracked, HostListener, ChangeDetectionStrategy } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
- import * as i2 from '@angular/router';
5
+ import * as i1$1 from '@angular/router';
6
6
  import { RouterModule } from '@angular/router';
7
7
  import { FormsModule } from '@angular/forms';
8
8
 
@@ -372,7 +372,7 @@ class NavItem {
372
372
  : '';
373
373
  }
374
374
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NavItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
375
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: NavItem, isStandalone: true, selector: "ZS-nav-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, collectionName: { classPropertyName: "collectionName", publicName: "collectionName", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { anyItemClickedEv: "anyItemClickedEv" }, ngImport: i0, template: "<!-- ========================= Conditional Rendering ========================= -->\n@if (item()) {\n @if (item().children?.length) {\n\n <!-- ========================= Parent Item with Dropdown ========================= -->\n <div class=\"zs:relative zs:w-full\">\n\n <!-- ========================= Main Toggle Button ========================= -->\n <button\n type=\"button\"\n (click)=\"toggle()\"\n [ngClass]=\"getItemClasses(item())\"\n class=\"zs:flex zs:w-full zs:items-center zs:gap-2 zs:rounded-md zs:px-3 zs:py-2 zs:text-left \n zs:text-sm zs:font-medium zs:md:text-base\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"'submenu-' + index()\"\n >\n <div class=\"zs:flex zs:items-center\">\n @if (item().icon) {\n <i [ngClass]=\"[\n item().icon, \n item().iconClass ?? '',\n (item().icon && item().label) ? 'zs:mr-2' : ''\n ]\" aria-hidden=\"true\"></i>\n }\n <span class=\"zs:wrap-break-word\" [ngClass]=\"labelLineClass(item())\">{{ item().label }}</span>\n </div>\n <i class=\"fas fa-chevron-down zs:ml-auto zs:p-0.5 zs:text-xs\" aria-hidden=\"true\"></i>\n </button>\n\n <!-- ========================= Dropdown Menu ========================= -->\n <div\n [id]=\"'submenu-' + index()\"\n [ngClass]=\"{\n 'zs:block': isOpen(),\n 'zs:hidden': !isOpen(),\n 'zs:absolute zs:left-6 zs:w-50 zs:mt-1 zs:py-1 zs:bg-white zs:dark:bg-gray-800 \n zs:rounded-md shadow-md-all shadow-md-all-night': item().childrenOpenWindow,\n 'zs:px-4 zs:mt-1': !item().childrenOpenWindow\n }\"\n class=\"{{ zIndices.navItemDropdown }}\"\n role=\"menu\"\n [attr.aria-label]=\"item().label + ' submenu'\"\n >\n @for (child of item().children; track $index) {\n <ZS-nav-item\n [item]=\"child\"\n [collectionName]=\"collectionName() + '-' + index()\"\n (anyItemClickedEv)=\"handleChildClick($event)\"\n role=\"menuitem\"\n ></ZS-nav-item>\n }\n </div>\n\n </div>\n\n } @else {\n\n <!-- ========================= Leaf Item (No Children) ========================= -->\n <a\n [routerLink]=\"item().routerLink\"\n [routerLinkActive]=\"item().routerLinkActive ?? ''\"\n #rla=\"routerLinkActive\"\n [ngClass]=\"rla.isActive ? '' : getItemClasses(item())\"\n class=\"zs:flex zs:items-center zs:rounded-md zs:px-3 zs:py-2 \n zs:text-sm zs:font-medium zs:md:text-base\"\n (click)=\"onItemClick()\"\n role=\"menuitem\"\n >\n @if (item().icon) {\n <i [ngClass]=\"[\n item().icon,\n rla.isActive ? '' : item().iconClass ?? '',\n (item().icon && item().label) ? 'zs:mr-2' : ''\n ]\"\n aria-hidden=\"true\"></i>\n }\n <span class=\"zs:wrap-break-word zs:line-clamp-3\" [ngClass]=\"labelLineClass(item())\">{{ item().label }}</span>\n </a>\n }\n}", styles: [""], dependencies: [{ kind: "component", type: NavItem, selector: "ZS-nav-item", inputs: ["item", "collectionName"], outputs: ["anyItemClickedEv"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
375
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: NavItem, isStandalone: true, selector: "ZS-nav-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, collectionName: { classPropertyName: "collectionName", publicName: "collectionName", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { anyItemClickedEv: "anyItemClickedEv" }, ngImport: i0, template: "<!-- ========================= Conditional Rendering ========================= -->\n@if (item()) {\n @if (item().children?.length) {\n\n <!-- ========================= Parent Item with Dropdown ========================= -->\n <div class=\"zs:relative zs:w-full\">\n\n <!-- ========================= Main Toggle Button ========================= -->\n <button\n type=\"button\"\n (click)=\"toggle()\"\n [ngClass]=\"getItemClasses(item())\"\n class=\"zs:flex zs:w-full zs:items-center zs:gap-2 zs:rounded-md zs:px-3 zs:py-2 zs:text-left \n zs:text-sm zs:font-medium zs:md:text-base\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"'submenu-' + index()\"\n >\n <div class=\"zs:flex zs:items-center\">\n @if (item().icon) {\n <i [ngClass]=\"[\n item().icon, \n item().iconClass ?? '',\n (item().icon && item().label) ? 'zs:mr-2' : ''\n ]\" aria-hidden=\"true\"></i>\n }\n <span class=\"zs:wrap-break-word\" [ngClass]=\"labelLineClass(item())\">{{ item().label }}</span>\n </div>\n <i class=\"fas fa-chevron-down zs:ml-auto zs:p-0.5 zs:text-xs\" aria-hidden=\"true\"></i>\n </button>\n\n <!-- ========================= Dropdown Menu ========================= -->\n <div\n [id]=\"'submenu-' + index()\"\n [ngClass]=\"{\n 'zs:block': isOpen(),\n 'zs:hidden': !isOpen(),\n 'zs:absolute zs:left-6 zs:w-50 zs:mt-1 zs:py-1 zs:bg-white zs:dark:bg-gray-800 \n zs:rounded-md shadow-md-all shadow-md-all-night': item().childrenOpenWindow,\n 'zs:px-4 zs:mt-1': !item().childrenOpenWindow\n }\"\n class=\"{{ zIndices.navItemDropdown }}\"\n role=\"menu\"\n [attr.aria-label]=\"item().label + ' submenu'\"\n >\n @for (child of item().children; track $index) {\n <ZS-nav-item\n [item]=\"child\"\n [collectionName]=\"collectionName() + '-' + index()\"\n (anyItemClickedEv)=\"handleChildClick($event)\"\n role=\"menuitem\"\n ></ZS-nav-item>\n }\n </div>\n\n </div>\n\n } @else {\n\n <!-- ========================= Leaf Item (No Children) ========================= -->\n <a\n [routerLink]=\"item().routerLink\"\n [routerLinkActive]=\"item().routerLinkActive ?? ''\"\n #rla=\"routerLinkActive\"\n [ngClass]=\"rla.isActive ? '' : getItemClasses(item())\"\n class=\"zs:flex zs:items-center zs:rounded-md zs:px-3 zs:py-2 \n zs:text-sm zs:font-medium zs:md:text-base\"\n (click)=\"onItemClick()\"\n role=\"menuitem\"\n >\n @if (item().icon) {\n <i [ngClass]=\"[\n item().icon,\n rla.isActive ? '' : item().iconClass ?? '',\n (item().icon && item().label) ? 'zs:mr-2' : ''\n ]\"\n aria-hidden=\"true\"></i>\n }\n <span class=\"zs:wrap-break-word zs:line-clamp-3\" [ngClass]=\"labelLineClass(item())\">{{ item().label }}</span>\n </a>\n }\n}", styles: [""], dependencies: [{ kind: "component", type: NavItem, selector: "ZS-nav-item", inputs: ["item", "collectionName"], outputs: ["anyItemClickedEv"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i1$1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }] });
376
376
  }
377
377
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NavItem, decorators: [{
378
378
  type: Component,
@@ -1362,8 +1362,8 @@ class Button {
1362
1362
  const outlineClasses = this.join('zs:bg-transparent', 'zs:border-[1px]', outlinePalette.border, outlinePalette.btnBGHover, outlinePalette.text, 'zs:hover:text-gray-50', 'zs:hover:shadow-sm');
1363
1363
  const stateClasses = this.disabled()
1364
1364
  ? 'zs:opacity-60 zs:cursor-not-allowed zs:shadow-none'
1365
- : this.join('zs:active:scale-[0.97]', 'zs:transition-[background-color,color,border-color,box-shadow,opacity]', 'zs:duration-200', 'zs:ease-in-out', 'zs:inline-flex zs:items-center zs:justify-center', 'zs:focus-visible:ring-2', 'zs:select-none', 'zs:outline-hidden', ['xl'].includes(size) ? 'zs:rounded-xl' : 'zs:rounded-lg');
1366
- return this.join(variant === 'solid' ? solidPadding : outlinePadding, variant === 'solid' ? solidClasses : outlineClasses, stateClasses, ringConfig.ring);
1365
+ : this.join('zs:active:scale-[0.97]', 'zs:transition-[background-color,color,border-color,box-shadow,opacity]', 'zs:duration-200', 'zs:ease-in-out');
1366
+ return this.join(variant === 'solid' ? solidPadding : outlinePadding, variant === 'solid' ? solidClasses : outlineClasses, stateClasses, ringConfig.ring, 'zs:inline-flex zs:items-center zs:justify-center', ['xl'].includes(size) ? 'zs:rounded-xl' : 'zs:rounded-lg', 'zs:focus-visible:ring-2', 'zs:select-none', 'zs:outline-hidden');
1367
1367
  }, ...(ngDevMode ? [{ debugName: "baseClasses" }] : []));
1368
1368
  // ==============================================
1369
1369
  // Methods
@@ -1610,7 +1610,7 @@ class Navbar {
1610
1610
  this.resizeObserver.disconnect();
1611
1611
  }
1612
1612
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Navbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1613
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: Navbar, isStandalone: true, selector: "ZS-navbar", inputs: { fixed: { classPropertyName: "fixed", publicName: "fixed", isSignal: true, isRequired: false, transformFunction: null }, logoUrl: { classPropertyName: "logoUrl", publicName: "logoUrl", isSignal: true, isRequired: false, transformFunction: null }, siteNameConfig: { classPropertyName: "siteNameConfig", publicName: "siteNameConfig", isSignal: true, isRequired: false, transformFunction: null }, authButtons: { classPropertyName: "authButtons", publicName: "authButtons", isSignal: true, isRequired: false, transformFunction: null }, showUserSection: { classPropertyName: "showUserSection", publicName: "showUserSection", isSignal: true, isRequired: false, transformFunction: null }, showSearchBar: { classPropertyName: "showSearchBar", publicName: "showSearchBar", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, isLoggedIn: { classPropertyName: "isLoggedIn", publicName: "isLoggedIn", isSignal: true, isRequired: false, transformFunction: null }, userProfile: { classPropertyName: "userProfile", publicName: "userProfile", isSignal: true, isRequired: false, transformFunction: null }, userMenuItems: { classPropertyName: "userMenuItems", publicName: "userMenuItems", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchValue: { classPropertyName: "searchValue", publicName: "searchValue", isSignal: true, isRequired: false, transformFunction: null }, isMobileMenuOpen: { classPropertyName: "isMobileMenuOpen", publicName: "isMobileMenuOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loginClickedEv: "loginClickedEv", signupClickedEv: "signupClickedEv", searchSubmittedEv: "searchSubmittedEv", anyItemClickedEv: "anyItemClickedEv", searchValue: "searchValueChange", isMobileMenuOpen: "isMobileMenuOpenChange" }, ngImport: i0, template: "<!-- ========================= Fixed Navbar Container ========================= -->\n\n<nav\n class=\"zs:bg-white zs:dark:bg-[#18202F] zs:top-0 zs:left-0 zs:right-0 {{ zIndices.navbar }} zs:shadow-md zs:dark:shadow-gray-400/30\"\n [ngClass]=\"fixed() ? 'zs:fixed' : 'zs:relative'\"\n role=\"navigation\"\n aria-label=\"Main Navigation\"\n>\n <div class=\"zs:max-w-7xl zs:mx-auto zs:px-4 zs:sm:px-6 zs:lg:px-8\">\n <div class=\"zs:flex zs:justify-between zs:h-16 zs:gap-4\">\n\n <!-- ========================= Logo & Site Name ========================= -->\n <div class=\"zs:flex zs:items-center\">\n @if (logoUrl() || siteNameConfig()) {\n <a\n [routerLink]=\"[siteNameConfig()?.routerLink ?? '/']\"\n class=\"zs:shrink-0 zs:flex zs:items-center zs:gap-2 zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-blue-500\"\n aria-label=\"Homepage\"\n >\n @if (logoUrl()) {\n <img\n [src]=\"logoUrl()\"\n alt=\"{{ siteNameConfig()?.siteName ?? 'Site Logo' }}\"\n class=\"zs:h-8 zs:w-auto\"\n />\n }\n @if (siteNameConfig()) {\n <span\n [class]=\"siteNameConfig()?.siteNameColorClass ?? 'zs:text-gray-800 zs:dark:text-gray-100'\"\n class=\"zs:font-bold zs:text-xl\"\n >\n {{ siteNameConfig()?.siteName }}\n </span>\n }\n </a>\n }\n </div>\n\n <!-- ========================= Desktop Navigation ========================= -->\n <div class=\"zs:hidden zs:lg:flex zs:items-center zs:gap-4\" role=\"menubar\">\n @for (item of visibleNavItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'navItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n\n @if (moreNavItems().length > 0) {\n <div class=\"zs:relative\" role=\"none\">\n <button\n (click)=\"isMoreOpen.set(!isMoreOpen())\"\n [attr.aria-expanded]=\"isMoreOpen()\"\n aria-haspopup=\"true\"\n aria-controls=\"more-menu\"\n class=\"zs:px-3 zs:py-2 zs:text-sm zs:font-bold zs:text-blue-600 zs:dark:text-blue-400 zs:hover:text-blue-700 zs:dark:hover:text-blue-300 zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-blue-500\"\n >\n More\n <i class=\"fas fa-chevron-down zs:ml-1 zs:text-xs zs:text-gray-500 zs:dark:text-gray-400\"></i>\n </button>\n <div\n id=\"more-menu\"\n [ngClass]=\"{ 'zs:block': isMoreOpen(), 'zs:hidden': !isMoreOpen() }\"\n class=\"zs:absolute zs:bg-white zs:dark:bg-[#18202F] shadow-md-all shadow-md-all-night zs:rounded-md zs:mt-1 zs:py-1 zs:min-w-48 zs:z-200\"\n role=\"menu\"\n >\n @for (item of moreNavItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'navItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n </div>\n </div>\n }\n </div>\n\n <!-- ========================= Right Controls ========================= -->\n <div class=\"zs:flex zs:items-center zs:gap-3\">\n\n <!-- Search Bar (Desktop) -->\n @if (showSearchBar()) {\n <div class=\"zs:hidden zs:lg:block\" role=\"search\">\n <div class=\"zs:relative\">\n <label for=\"desktop-search\" class=\"sr-only\">Search</label>\n <input\n id=\"desktop-search\"\n type=\"text\"\n [value]=\"searchValue()\"\n (input)=\"searchValue.set($any($event.target).value)\"\n (keyup.enter)=\"onSearchSubmit()\"\n [placeholder]=\"searchPlaceholder()\"\n class=\"zs:bg-gray-100 zs:dark:bg-gray-700 zs:text-gray-800 zs:dark:text-gray-200 zs:rounded-full zs:py-2 zs:px-4 zs:w-64\n zs:transition-all zs:duration-200 zs:focus:outline-hidden zs:focus:ring-2 zs:focus:ring-blue-500\n zs:focus:bg-white zs:dark:focus:bg-gray-600 zs:shadow-sm zs:dark:shadow-gray-500/40\n zs:hover:shadow-md zs:dark:hover:shadow-gray-500/50\"\n />\n <button\n (click)=\"onSearchSubmit()\"\n class=\"zs:absolute zs:py-1 zs:px-2 zs:right-2 zs:top-1/2 zs:-translate-y-1/2 zs:text-gray-500 zs:dark:text-gray-400\n zs:hover:text-gray-700 zs:dark:hover:text-gray-300 zs:transition-colors zs:duration-200\"\n aria-label=\"Submit search\"\n >\n <i class=\"fas fa-search\"></i>\n </button>\n </div>\n </div>\n }\n\n <!-- User Profile Dropdown -->\n @if (isLoggedIn() && userProfile() && showUserSection()) {\n <div class=\"zs:relative\">\n <button\n (click)=\"toggleUserMenu()\"\n class=\"zs:flex zs:items-center zs:gap-2 zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-blue-500\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"isUserMenuOpen()\"\n aria-controls=\"user-menu\"\n aria-label=\"User menu\"\n >\n @if (userProfile()?.imageUrl) {\n <img\n [src]=\"userProfile()?.imageUrl\"\n alt=\"{{ userProfile()?.name ?? 'User profile image' }}\"\n class=\"zs:h-8 zs:w-8 zs:rounded-full zs:object-cover\"\n />\n } @else {\n <div\n class=\"zs:h-8 zs:w-8 zs:rounded-full zs:bg-blue-500 zs:flex zs:items-center zs:justify-center zs:text-white zs:font-semibold\"\n aria-hidden=\"true\"\n >\n {{ userProfile()?.name?.charAt(0) || 'U' }}\n </div>\n }\n <i class=\"fas fa-chevron-down zs:text-xs zs:text-gray-600 zs:dark:text-gray-400\n zs:hover:text-gray-700 zs:dark:hover:text-gray-300\"></i>\n </button>\n\n @if (isUserMenuOpen() && userMenuItems().length > 0) {\n <div\n id=\"user-menu\"\n class=\"zs:absolute zs:right-0 zs:mt-2.5 zs:min-w-56 zs:bg-white zs:dark:bg-gray-800 zs:rounded-md\n shadow-md-all shadow-md-all-night zs:pt-2 zs:z-400\"\n role=\"menu\"\n >\n <!-- User Info Section -->\n <div class=\"zs:px-4 zs:py-2 zs:border-b zs:border-gray-200 zs:dark:border-gray-700\">\n @if (userProfile()?.name) {\n <div class=\"zs:font-semibold zs:text-gray-900 zs:dark:text-gray-100\">\n {{ userProfile()?.name }}\n </div>\n }\n @if (userProfile()?.username) {\n <div class=\"zs:text-sm zs:text-gray-600 zs:dark:text-gray-400\">\n @{{ userProfile()?.username }}\n </div>\n }\n @if (userProfile()?.email) {\n <div class=\"zs:text-sm zs:text-gray-500 zs:dark:text-gray-400\">\n {{ userProfile()?.email }}\n </div>\n }\n </div>\n\n <!-- Menu Items -->\n @if (userMenuItems().length > 0) {\n <div class=\"zs:py-1\">\n @for (item of getUserMenuItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'MenuItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Auth Buttons -->\n @else if (authButtons().showAuthButtons && !isLoggedIn()) {\n <div class=\"zs:hidden zs:lg:flex zs:items-center zs:gap-3\" role=\"group\" aria-label=\"Authentication\">\n <ZS-button\n [btnStyle]=\"authButtons().login?.btnStyle ?? 'secondary'\"\n [variant]=\"authButtons().login?.variant ?? 'outline'\"\n [size]=\"authButtons().login?.size ?? 'md'\"\n [icon]=\"authButtons().login?.icon ?? ''\"\n (clickedEv)=\"onLogin()\"\n >\n Login\n </ZS-button>\n\n <ZS-button\n [btnStyle]=\"authButtons().signup?.btnStyle ?? 'primary'\"\n [variant]=\"authButtons().signup?.variant ?? 'solid'\"\n [size]=\"authButtons().signup?.size ?? 'md'\"\n [icon]=\"authButtons().signup?.icon ?? ''\"\n (clickedEv)=\"onSignup()\"\n >\n Sign Up\n </ZS-button>\n </div>\n }\n\n <!-- Mobile Menu Toggle -->\n <div class=\"zs:lg:hidden\">\n <button\n (click)=\"toggleMobileMenu()\"\n class=\"zs:p-2 zs:rounded-md zs:text-gray-600 zs:dark:text-gray-300\n zs:hover:text-gray-900 zs:dark:hover:text-gray-100\n zs:focus:outline-hidden zs:focus:ring-2 zs:focus:ring-inset\n zs:focus:ring-gray-200 zs:dark:focus:ring-gray-700\"\n aria-controls=\"mobile-menu\"\n aria-expanded=\"{{ isMobileMenuOpen() }}\"\n aria-label=\"Toggle mobile menu\"\n >\n <i class=\"fas fa-bars zs:px-1\"></i>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- ========================= Mobile Menu ========================= -->\n @if (isMobileMenuOpen()) {\n <div\n id=\"mobile-menu\"\n class=\"zs:lg:hidden zs:bg-white zs:dark:bg-[#18202F] \n zs:[box-shadow:0_8px_0_0_#364153] zs:dark:[box-shadow:0_8px_0_0_black]\"\n role=\"menu\"\n aria-label=\"Mobile navigation\"\n >\n <div class=\"zs:px-2 zs:pt-2 zs:pb-3 zs:flex zs:flex-col zs:gap-1 zs:sm:px-3\">\n\n <!-- Navigation Items -->\n <div class=\"zs:max-h-96 zs:overflow-y-auto\">\n @for (item of mobileNavItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'navItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n </div>\n\n <!-- Search Bar (Mobile) -->\n @if (showSearchBar()) {\n <div class=\"zs:px-3 zs:py-2\" role=\"search\">\n <label for=\"mobile-search\" class=\"sr-only\">Search</label>\n <div class=\"zs:relative\">\n <input\n id=\"mobile-search\"\n type=\"text\"\n [value]=\"searchValue()\"\n (input)=\"searchValue.set($any($event.target).value)\"\n (keyup.enter)=\"onSearchSubmit()\"\n [placeholder]=\"searchPlaceholder()\"\n class=\"zs:w-full zs:bg-gray-100 zs:dark:bg-gray-700 zs:text-gray-800 zs:dark:text-gray-200\n zs:rounded-full zs:py-2 zs:px-4 zs:transition-all zs:duration-200 zs:focus:outline-hidden\n zs:focus:ring-2 zs:focus:ring-blue-500 zs:focus:bg-white zs:dark:focus:bg-gray-600\n zs:shadow-sm zs:dark:shadow-gray-500/40 zs:hover:shadow-md zs:dark:hover:shadow-gray-500/50\"\n />\n <button\n (click)=\"onSearchSubmit()\"\n class=\"zs:absolute zs:py-1 zs:px-2 zs:right-2 zs:top-1/2 zs:-translate-y-1/2 zs:text-gray-500 zs:dark:text-gray-400\n zs:hover:text-gray-700 zs:dark:hover:text-gray-300 zs:transition-colors zs:duration-200\"\n aria-label=\"Submit search\"\n >\n <i class=\"fas fa-search\"></i>\n </button>\n </div>\n </div>\n }\n\n <!-- Auth Buttons (Mobile) -->\n @if (authButtons().showAuthButtons && !isLoggedIn()) {\n <div\n class=\"zs:pt-3 zs:pb-4 zs:border-t zs:border-gray-300 zs:dark:border-gray-500\n zs:flex zs:flex-wrap zs:justify-start zs:items-center zs:gap-2\"\n role=\"group\"\n aria-label=\"Authentication (mobile)\"\n >\n <ZS-button\n [btnStyle]=\"authButtons().login?.btnStyle ?? 'secondary'\"\n [variant]=\"authButtons().login?.variant ?? 'outline'\"\n [size]=\"authButtons().login?.size ?? 'md'\"\n [icon]=\"authButtons().login?.icon ?? ''\"\n (clickedEv)=\"onLogin(); isMobileMenuOpen.set(false)\"\n >\n Login\n </ZS-button>\n\n <ZS-button\n [btnStyle]=\"authButtons().signup?.btnStyle ?? 'primary'\"\n [variant]=\"authButtons().signup?.variant ?? 'solid'\"\n [size]=\"authButtons().signup?.size ?? 'md'\"\n [icon]=\"authButtons().signup?.icon ?? ''\"\n (clickedEv)=\"onSignup(); isMobileMenuOpen.set(false)\"\n >\n Sign Up\n </ZS-button>\n </div>\n }\n </div>\n </div>\n }\n</nav>\n\n<!-- ========================= Spacer for Fixed Navbar ========================= -->\n@if (fixed()) {\n <div class=\"zs:h-16\" aria-hidden=\"true\"></div>\n}\n\n<!-- ========================= Overlay for Menu Closing ========================= -->\n@if (isMobileMenuOpen()) {\n <div\n class=\"zs:fixed zs:inset-0 zs:bg-gray-700 zs:dark:bg-black zs:z-700\"\n (click)=\"closeAllMenus()\"\n aria-hidden=\"true\"\n ></div>\n}\n", styles: [":host{display:block}body{font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif}a,button{transition:all .2s ease-in-out}img{object-fit:cover}.shadow-lg{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d}@media (max-width: 768px){.rtl\\:space-x-reverse{margin-right:0;margin-left:.75rem}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: NavItem, selector: "ZS-nav-item", inputs: ["item", "collectionName"], outputs: ["anyItemClickedEv"] }, { kind: "component", type: Button, selector: "ZS-button", inputs: ["Id", "btnStyle", "variant", "size", "disabled", "icon", "type"], outputs: ["clickedEv"] }] });
1613
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: Navbar, isStandalone: true, selector: "ZS-navbar", inputs: { fixed: { classPropertyName: "fixed", publicName: "fixed", isSignal: true, isRequired: false, transformFunction: null }, logoUrl: { classPropertyName: "logoUrl", publicName: "logoUrl", isSignal: true, isRequired: false, transformFunction: null }, siteNameConfig: { classPropertyName: "siteNameConfig", publicName: "siteNameConfig", isSignal: true, isRequired: false, transformFunction: null }, authButtons: { classPropertyName: "authButtons", publicName: "authButtons", isSignal: true, isRequired: false, transformFunction: null }, showUserSection: { classPropertyName: "showUserSection", publicName: "showUserSection", isSignal: true, isRequired: false, transformFunction: null }, showSearchBar: { classPropertyName: "showSearchBar", publicName: "showSearchBar", isSignal: true, isRequired: false, transformFunction: null }, navItems: { classPropertyName: "navItems", publicName: "navItems", isSignal: true, isRequired: false, transformFunction: null }, isLoggedIn: { classPropertyName: "isLoggedIn", publicName: "isLoggedIn", isSignal: true, isRequired: false, transformFunction: null }, userProfile: { classPropertyName: "userProfile", publicName: "userProfile", isSignal: true, isRequired: false, transformFunction: null }, userMenuItems: { classPropertyName: "userMenuItems", publicName: "userMenuItems", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, searchValue: { classPropertyName: "searchValue", publicName: "searchValue", isSignal: true, isRequired: false, transformFunction: null }, isMobileMenuOpen: { classPropertyName: "isMobileMenuOpen", publicName: "isMobileMenuOpen", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loginClickedEv: "loginClickedEv", signupClickedEv: "signupClickedEv", searchSubmittedEv: "searchSubmittedEv", anyItemClickedEv: "anyItemClickedEv", searchValue: "searchValueChange", isMobileMenuOpen: "isMobileMenuOpenChange" }, ngImport: i0, template: "<!-- ========================= Fixed Navbar Container ========================= -->\n\n<nav\n class=\"zs:bg-white zs:dark:bg-[#18202F] zs:top-0 zs:left-0 zs:right-0 {{ zIndices.navbar }} zs:shadow-md zs:dark:shadow-gray-400/30\"\n [ngClass]=\"fixed() ? 'zs:fixed' : 'zs:relative'\"\n role=\"navigation\"\n aria-label=\"Main Navigation\"\n>\n <div class=\"zs:max-w-7xl zs:mx-auto zs:px-4 zs:sm:px-6 zs:lg:px-8\">\n <div class=\"zs:flex zs:justify-between zs:h-16 zs:gap-4\">\n\n <!-- ========================= Logo & Site Name ========================= -->\n <div class=\"zs:flex zs:items-center\">\n @if (logoUrl() || siteNameConfig()) {\n <a\n [routerLink]=\"[siteNameConfig()?.routerLink ?? '/']\"\n class=\"zs:shrink-0 zs:flex zs:items-center zs:gap-2 zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-blue-500\"\n aria-label=\"Homepage\"\n >\n @if (logoUrl()) {\n <img\n [src]=\"logoUrl()\"\n alt=\"{{ siteNameConfig()?.siteName ?? 'Site Logo' }}\"\n class=\"zs:h-8 zs:w-auto\"\n />\n }\n @if (siteNameConfig()) {\n <span\n [class]=\"siteNameConfig()?.siteNameColorClass ?? 'zs:text-gray-800 zs:dark:text-gray-100'\"\n class=\"zs:font-bold zs:text-xl\"\n >\n {{ siteNameConfig()?.siteName }}\n </span>\n }\n </a>\n }\n </div>\n\n <!-- ========================= Desktop Navigation ========================= -->\n <div class=\"zs:hidden zs:lg:flex zs:items-center zs:gap-4\" role=\"menubar\">\n @for (item of visibleNavItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'navItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n\n @if (moreNavItems().length > 0) {\n <div class=\"zs:relative\" role=\"none\">\n <button\n (click)=\"isMoreOpen.set(!isMoreOpen())\"\n [attr.aria-expanded]=\"isMoreOpen()\"\n aria-haspopup=\"true\"\n aria-controls=\"more-menu\"\n class=\"zs:px-3 zs:py-2 zs:text-sm zs:font-bold zs:text-blue-600 zs:dark:text-blue-400 zs:hover:text-blue-700 zs:dark:hover:text-blue-300 zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-blue-500\"\n >\n More\n <i class=\"fas fa-chevron-down zs:ml-1 zs:text-xs zs:text-gray-500 zs:dark:text-gray-400\"></i>\n </button>\n <div\n id=\"more-menu\"\n [ngClass]=\"{ 'zs:block': isMoreOpen(), 'zs:hidden': !isMoreOpen() }\"\n class=\"zs:absolute zs:bg-white zs:dark:bg-[#18202F] shadow-md-all shadow-md-all-night zs:rounded-md zs:mt-1 zs:py-1 zs:min-w-48 zs:z-200\"\n role=\"menu\"\n >\n @for (item of moreNavItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'navItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n </div>\n </div>\n }\n </div>\n\n <!-- ========================= Right Controls ========================= -->\n <div class=\"zs:flex zs:items-center zs:gap-3\">\n\n <!-- Search Bar (Desktop) -->\n @if (showSearchBar()) {\n <div class=\"zs:hidden zs:lg:block\" role=\"search\">\n <div class=\"zs:relative\">\n <label for=\"desktop-search\" class=\"sr-only\">Search</label>\n <input\n id=\"desktop-search\"\n type=\"text\"\n [value]=\"searchValue()\"\n (input)=\"searchValue.set($any($event.target).value)\"\n (keyup.enter)=\"onSearchSubmit()\"\n [placeholder]=\"searchPlaceholder()\"\n class=\"zs:bg-gray-100 zs:dark:bg-gray-700 zs:text-gray-800 zs:dark:text-gray-200 zs:rounded-full zs:py-2 zs:px-4 zs:w-64\n zs:transition-all zs:duration-200 zs:focus:outline-hidden zs:focus:ring-2 zs:focus:ring-blue-500\n zs:focus:bg-white zs:dark:focus:bg-gray-600 zs:shadow-sm zs:dark:shadow-gray-500/40\n zs:hover:shadow-md zs:dark:hover:shadow-gray-500/50\"\n />\n <button\n (click)=\"onSearchSubmit()\"\n class=\"zs:absolute zs:py-1 zs:px-2 zs:right-2 zs:top-1/2 zs:-translate-y-1/2 zs:text-gray-500 zs:dark:text-gray-400\n zs:hover:text-gray-700 zs:dark:hover:text-gray-300 zs:transition-colors zs:duration-200\"\n aria-label=\"Submit search\"\n >\n <i class=\"fas fa-search\"></i>\n </button>\n </div>\n </div>\n }\n\n <!-- User Profile Dropdown -->\n @if (isLoggedIn() && userProfile() && showUserSection()) {\n <div class=\"zs:relative\">\n <button\n (click)=\"toggleUserMenu()\"\n class=\"zs:flex zs:items-center zs:gap-2 zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-blue-500\"\n aria-haspopup=\"true\"\n [attr.aria-expanded]=\"isUserMenuOpen()\"\n aria-controls=\"user-menu\"\n aria-label=\"User menu\"\n >\n @if (userProfile()?.imageUrl) {\n <img\n [src]=\"userProfile()?.imageUrl\"\n alt=\"{{ userProfile()?.name ?? 'User profile image' }}\"\n class=\"zs:h-8 zs:w-8 zs:rounded-full zs:object-cover\"\n />\n } @else {\n <div\n class=\"zs:h-8 zs:w-8 zs:rounded-full zs:bg-blue-500 zs:flex zs:items-center zs:justify-center zs:text-white zs:font-semibold\"\n aria-hidden=\"true\"\n >\n {{ userProfile()?.name?.charAt(0) || 'U' }}\n </div>\n }\n <i class=\"fas fa-chevron-down zs:text-xs zs:text-gray-600 zs:dark:text-gray-400\n zs:hover:text-gray-700 zs:dark:hover:text-gray-300\"></i>\n </button>\n\n @if (isUserMenuOpen() && userMenuItems().length > 0) {\n <div\n id=\"user-menu\"\n class=\"zs:absolute zs:right-0 zs:mt-2.5 zs:min-w-56 zs:bg-white zs:dark:bg-gray-800 zs:rounded-md\n shadow-md-all shadow-md-all-night zs:pt-2 zs:z-400\"\n role=\"menu\"\n >\n <!-- User Info Section -->\n <div class=\"zs:px-4 zs:py-2 zs:border-b zs:border-gray-200 zs:dark:border-gray-700\">\n @if (userProfile()?.name) {\n <div class=\"zs:font-semibold zs:text-gray-900 zs:dark:text-gray-100\">\n {{ userProfile()?.name }}\n </div>\n }\n @if (userProfile()?.username) {\n <div class=\"zs:text-sm zs:text-gray-600 zs:dark:text-gray-400\">\n @{{ userProfile()?.username }}\n </div>\n }\n @if (userProfile()?.email) {\n <div class=\"zs:text-sm zs:text-gray-500 zs:dark:text-gray-400\">\n {{ userProfile()?.email }}\n </div>\n }\n </div>\n\n <!-- Menu Items -->\n @if (userMenuItems().length > 0) {\n <div class=\"zs:py-1\">\n @for (item of getUserMenuItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'MenuItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Auth Buttons -->\n @else if (authButtons().showAuthButtons && !isLoggedIn()) {\n <div class=\"zs:hidden zs:lg:flex zs:items-center zs:gap-3\" role=\"group\" aria-label=\"Authentication\">\n <ZS-button\n [btnStyle]=\"authButtons().login?.btnStyle ?? 'secondary'\"\n [variant]=\"authButtons().login?.variant ?? 'outline'\"\n [size]=\"authButtons().login?.size ?? 'md'\"\n [icon]=\"authButtons().login?.icon ?? ''\"\n (clickedEv)=\"onLogin()\"\n >\n Login\n </ZS-button>\n\n <ZS-button\n [btnStyle]=\"authButtons().signup?.btnStyle ?? 'primary'\"\n [variant]=\"authButtons().signup?.variant ?? 'solid'\"\n [size]=\"authButtons().signup?.size ?? 'md'\"\n [icon]=\"authButtons().signup?.icon ?? ''\"\n (clickedEv)=\"onSignup()\"\n >\n Sign Up\n </ZS-button>\n </div>\n }\n\n <!-- Mobile Menu Toggle -->\n <div class=\"zs:lg:hidden\">\n <button\n (click)=\"toggleMobileMenu()\"\n class=\"zs:p-2 zs:rounded-md zs:text-gray-600 zs:dark:text-gray-300\n zs:hover:text-gray-900 zs:dark:hover:text-gray-100\n zs:focus:outline-hidden zs:focus:ring-2 zs:focus:ring-inset\n zs:focus:ring-gray-200 zs:dark:focus:ring-gray-700\"\n aria-controls=\"mobile-menu\"\n aria-expanded=\"{{ isMobileMenuOpen() }}\"\n aria-label=\"Toggle mobile menu\"\n >\n <i class=\"fas fa-bars zs:px-1\"></i>\n </button>\n </div>\n </div>\n </div>\n </div>\n\n <!-- ========================= Mobile Menu ========================= -->\n @if (isMobileMenuOpen()) {\n <div\n id=\"mobile-menu\"\n class=\"zs:lg:hidden zs:bg-white zs:dark:bg-[#18202F] \n zs:[box-shadow:0_8px_0_0_#364153] zs:dark:[box-shadow:0_8px_0_0_black]\"\n role=\"menu\"\n aria-label=\"Mobile navigation\"\n >\n <div class=\"zs:px-2 zs:pt-2 zs:pb-3 zs:flex zs:flex-col zs:gap-1 zs:sm:px-3\">\n\n <!-- Navigation Items -->\n <div class=\"zs:max-h-96 zs:overflow-y-auto\">\n @for (item of mobileNavItems(); track $index) {\n <ZS-nav-item\n [item]=\"item\"\n [collectionName]=\"'navItems'\"\n (anyItemClickedEv)=\"itemClicked($event)\"\n role=\"menuitem\"\n />\n }\n </div>\n\n <!-- Search Bar (Mobile) -->\n @if (showSearchBar()) {\n <div class=\"zs:px-3 zs:py-2\" role=\"search\">\n <label for=\"mobile-search\" class=\"sr-only\">Search</label>\n <div class=\"zs:relative\">\n <input\n id=\"mobile-search\"\n type=\"text\"\n [value]=\"searchValue()\"\n (input)=\"searchValue.set($any($event.target).value)\"\n (keyup.enter)=\"onSearchSubmit()\"\n [placeholder]=\"searchPlaceholder()\"\n class=\"zs:w-full zs:bg-gray-100 zs:dark:bg-gray-700 zs:text-gray-800 zs:dark:text-gray-200\n zs:rounded-full zs:py-2 zs:px-4 zs:transition-all zs:duration-200 zs:focus:outline-hidden\n zs:focus:ring-2 zs:focus:ring-blue-500 zs:focus:bg-white zs:dark:focus:bg-gray-600\n zs:shadow-sm zs:dark:shadow-gray-500/40 zs:hover:shadow-md zs:dark:hover:shadow-gray-500/50\"\n />\n <button\n (click)=\"onSearchSubmit()\"\n class=\"zs:absolute zs:py-1 zs:px-2 zs:right-2 zs:top-1/2 zs:-translate-y-1/2 zs:text-gray-500 zs:dark:text-gray-400\n zs:hover:text-gray-700 zs:dark:hover:text-gray-300 zs:transition-colors zs:duration-200\"\n aria-label=\"Submit search\"\n >\n <i class=\"fas fa-search\"></i>\n </button>\n </div>\n </div>\n }\n\n <!-- Auth Buttons (Mobile) -->\n @if (authButtons().showAuthButtons && !isLoggedIn()) {\n <div\n class=\"zs:pt-3 zs:pb-4 zs:border-t zs:border-gray-300 zs:dark:border-gray-500\n zs:flex zs:flex-wrap zs:justify-start zs:items-center zs:gap-2\"\n role=\"group\"\n aria-label=\"Authentication (mobile)\"\n >\n <ZS-button\n [btnStyle]=\"authButtons().login?.btnStyle ?? 'secondary'\"\n [variant]=\"authButtons().login?.variant ?? 'outline'\"\n [size]=\"authButtons().login?.size ?? 'md'\"\n [icon]=\"authButtons().login?.icon ?? ''\"\n (clickedEv)=\"onLogin(); isMobileMenuOpen.set(false)\"\n >\n Login\n </ZS-button>\n\n <ZS-button\n [btnStyle]=\"authButtons().signup?.btnStyle ?? 'primary'\"\n [variant]=\"authButtons().signup?.variant ?? 'solid'\"\n [size]=\"authButtons().signup?.size ?? 'md'\"\n [icon]=\"authButtons().signup?.icon ?? ''\"\n (clickedEv)=\"onSignup(); isMobileMenuOpen.set(false)\"\n >\n Sign Up\n </ZS-button>\n </div>\n }\n </div>\n </div>\n }\n</nav>\n\n<!-- ========================= Spacer for Fixed Navbar ========================= -->\n@if (fixed()) {\n <div class=\"zs:h-16\" aria-hidden=\"true\"></div>\n}\n\n<!-- ========================= Overlay for Menu Closing ========================= -->\n@if (isMobileMenuOpen()) {\n <div\n class=\"zs:fixed zs:inset-0 zs:bg-gray-700 zs:dark:bg-black zs:z-700\"\n (click)=\"closeAllMenus()\"\n aria-hidden=\"true\"\n ></div>\n}\n", styles: [":host{display:block}body{font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif}a,button{transition:all .2s ease-in-out}img{object-fit:cover}.shadow-lg{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -2px #0000000d}@media (max-width: 768px){.rtl\\:space-x-reverse{margin-right:0;margin-left:.75rem}}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: NavItem, selector: "ZS-nav-item", inputs: ["item", "collectionName"], outputs: ["anyItemClickedEv"] }, { kind: "component", type: Button, selector: "ZS-button", inputs: ["Id", "btnStyle", "variant", "size", "disabled", "icon", "type"], outputs: ["clickedEv"] }] });
1614
1614
  }
1615
1615
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Navbar, decorators: [{
1616
1616
  type: Component,
@@ -1650,7 +1650,7 @@ class Page404 {
1650
1650
  // ========================================================================
1651
1651
  onAction = output();
1652
1652
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Page404, deps: [], target: i0.ɵɵFactoryTarget.Component });
1653
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: Page404, isStandalone: true, selector: "ZS-page404", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, pageStyle: { classPropertyName: "pageStyle", publicName: "pageStyle", isSignal: true, isRequired: false, transformFunction: null }, showButton: { classPropertyName: "showButton", publicName: "showButton", isSignal: true, isRequired: false, transformFunction: null }, buttonText: { classPropertyName: "buttonText", publicName: "buttonText", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<!-- ========================= Page 404 Container ========================= -->\n<div class=\"zs:flex zs:flex-col zs:items-center zs:justify-center zs:min-h-[90vh]\n zs:text-center zs:transition-colors zs:duration-500 zs:animate-fadeIn\"\n [ngClass]=\"[style().iconText]\"\n >\n\n <!-- ========================= Icon ========================= --> \n <div class=\"zs:text-[136px] zs:mb-8 animate-float zs:opacity-90 zs:leading-none\">\n <i class=\"fa-solid\" [class]=\"icon()\"></i>\n </div>\n\n <!-- ========================= Title ========================= -->\n <h1 class=\"zs:text-6xl zs:font-black zs:tracking-widest zs:mb-2 \n zs:text-rose-600 zs:dark:text-rose-500 zs:select-none\n zs:drop-shadow-[0_0_8px_rgba(239,68,68,0.5)]\">\n 404\n </h1>\n\n\n <!-- ========================= Message ========================= -->\n <h2 class=\"zs:text-2xl zs:text-rose-600/80 zs:dark:text-rose-800/80 zs:font-semibold zs:mb-4\">\n {{ title() }}\n </h2>\n <p class=\"zs:text-base zs:max-w-md zs:text-gray-600 zs:dark:text-gray-400 zs:mb-8\">\n {{ message() }}\n </p>\n\n <!-- ========================= Button ========================= -->\n @if (showButton()) {\n <a\n [routerLink]=\"routerLink()\"\n (click)=\"onAction.emit()\"\n class=\"zs:px-6 zs:py-2 zs:rounded-full\n zs:text-white zs:font-medium zs:shadow-md\n zs:hover:shadow-lg zs:flex zs:items-center \n zs:justify-center zs:transition-all zs:duration-300 zs:ease-out \n zs:gap-1.5\"\n [ngClass]=\"[style().btnBG, style().btnBGHover]\"\n >\n <i class=\"fa-solid fa-house\"></i>\n {{ buttonText() }}\n </a>\n }\n</div>\n", styles: ["@keyframes float{0%{transform:translateY(0)}50%{transform:translateY(-10px)}to{transform:translateY(0)}}.animate-float{animation:float 3s ease-in-out infinite}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1653
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: Page404, isStandalone: true, selector: "ZS-page404", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, message: { classPropertyName: "message", publicName: "message", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, pageStyle: { classPropertyName: "pageStyle", publicName: "pageStyle", isSignal: true, isRequired: false, transformFunction: null }, showButton: { classPropertyName: "showButton", publicName: "showButton", isSignal: true, isRequired: false, transformFunction: null }, buttonText: { classPropertyName: "buttonText", publicName: "buttonText", isSignal: true, isRequired: false, transformFunction: null }, routerLink: { classPropertyName: "routerLink", publicName: "routerLink", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onAction: "onAction" }, ngImport: i0, template: "<!-- ========================= Page 404 Container ========================= -->\n<div class=\"zs:flex zs:flex-col zs:items-center zs:justify-center zs:min-h-[90vh]\n zs:text-center zs:transition-colors zs:duration-500 zs:animate-fadeIn\"\n [ngClass]=\"[style().iconText]\"\n >\n\n <!-- ========================= Icon ========================= --> \n <div class=\"zs:text-[136px] zs:mb-8 animate-float zs:opacity-90 zs:leading-none\">\n <i class=\"fa-solid\" [class]=\"icon()\"></i>\n </div>\n\n <!-- ========================= Title ========================= -->\n <h1 class=\"zs:text-6xl zs:font-black zs:tracking-widest zs:mb-2 \n zs:text-rose-600 zs:dark:text-rose-500 zs:select-none\n zs:drop-shadow-[0_0_8px_rgba(239,68,68,0.5)]\">\n 404\n </h1>\n\n\n <!-- ========================= Message ========================= -->\n <h2 class=\"zs:text-2xl zs:text-rose-600/80 zs:dark:text-rose-800/80 zs:font-semibold zs:mb-4\">\n {{ title() }}\n </h2>\n <p class=\"zs:text-base zs:max-w-md zs:text-gray-600 zs:dark:text-gray-400 zs:mb-8\">\n {{ message() }}\n </p>\n\n <!-- ========================= Button ========================= -->\n @if (showButton()) {\n <a\n [routerLink]=\"routerLink()\"\n (click)=\"onAction.emit()\"\n class=\"zs:px-6 zs:py-2 zs:rounded-full\n zs:text-white zs:font-medium zs:shadow-md\n zs:hover:shadow-lg zs:flex zs:items-center \n zs:justify-center zs:transition-all zs:duration-300 zs:ease-out \n zs:gap-1.5\"\n [ngClass]=\"[style().btnBG, style().btnBGHover]\"\n >\n <i class=\"fa-solid fa-house\"></i>\n {{ buttonText() }}\n </a>\n }\n</div>\n", styles: ["@keyframes float{0%{transform:translateY(0)}50%{transform:translateY(-10px)}to{transform:translateY(0)}}.animate-float{animation:float 3s ease-in-out infinite}\n"], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1654
1654
  }
1655
1655
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Page404, decorators: [{
1656
1656
  type: Component,
@@ -1906,10 +1906,14 @@ class ThemeToggle {
1906
1906
  currentTheme = signal('light', ...(ngDevMode ? [{ debugName: "currentTheme" }] : []));
1907
1907
  isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
1908
1908
  userSelectedTheme = signal(false, ...(ngDevMode ? [{ debugName: "userSelectedTheme" }] : []));
1909
+ lastEmittedTheme = null;
1910
+ lastManualTheme = null;
1909
1911
  // ==============================================
1910
1912
  // Inputs
1911
1913
  // ==============================================
1912
1914
  bodyClass = input('zs:bg-white zs:dark:bg-gray-900 zs:text-gray-900 zs:dark:text-gray-100', ...(ngDevMode ? [{ debugName: "bodyClass" }] : []));
1915
+ showDefaultUI = input(true, ...(ngDevMode ? [{ debugName: "showDefaultUI" }] : []));
1916
+ setManualTheme = input(null, ...(ngDevMode ? [{ debugName: "setManualTheme" }] : []));
1913
1917
  // ==============================================
1914
1918
  // Outputs
1915
1919
  // ==============================================
@@ -1942,11 +1946,27 @@ class ThemeToggle {
1942
1946
  effect(() => {
1943
1947
  const theme = this.currentTheme();
1944
1948
  document.documentElement.classList.toggle('dark', theme === 'dark');
1945
- document.body.className = this.bodyClass();
1949
+ const classes = this.bodyClass().split(' ');
1950
+ document.body.classList.value = ''; // clear only what YOU set
1951
+ classes.forEach(c => document.body.classList.add(c));
1946
1952
  if (this.userSelectedTheme()) {
1947
1953
  localStorage.setItem('theme', theme);
1948
1954
  }
1949
1955
  });
1956
+ effect(() => {
1957
+ const manual = this.setManualTheme();
1958
+ if (manual && manual !== this.lastManualTheme) {
1959
+ this.lastManualTheme = manual;
1960
+ this.setTheme(manual);
1961
+ }
1962
+ });
1963
+ effect(() => {
1964
+ const theme = this.currentTheme();
1965
+ if (theme !== this.lastEmittedTheme) {
1966
+ this.lastEmittedTheme = theme;
1967
+ this.themeChangeEv.emit(theme);
1968
+ }
1969
+ });
1950
1970
  }
1951
1971
  // ==============================================
1952
1972
  // Component Methods
@@ -1955,10 +1975,11 @@ class ThemeToggle {
1955
1975
  this.isOpen.set(!this.isOpen());
1956
1976
  }
1957
1977
  setTheme(theme) {
1958
- this.currentTheme.set(theme);
1978
+ if (this.currentTheme() !== theme) {
1979
+ this.currentTheme.set(theme);
1980
+ this.userSelectedTheme.set(true);
1981
+ }
1959
1982
  this.isOpen.set(false);
1960
- this.themeChangeEv.emit(theme);
1961
- this.userSelectedTheme.set(true);
1962
1983
  }
1963
1984
  // ==============================================
1964
1985
  // Host Listeners
@@ -1970,12 +1991,12 @@ class ThemeToggle {
1970
1991
  }
1971
1992
  }
1972
1993
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ThemeToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
1973
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ThemeToggle, isStandalone: true, selector: "ZS-theme-toggle", inputs: { bodyClass: { classPropertyName: "bodyClass", publicName: "bodyClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { themeChangeEv: "themeChangeEv" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: "<!-- ========================= Theme Switcher Panel ========================= -->\n<div \n class=\"zs:fixed zs:left-0 zs:top-1/6 {{ zIndices.themeToggle }} zs:transform \n zs:-translate-y-1/2 zs:transition-all zs:duration-300\"\n [ngClass]=\"!isOpen() ? 'zs:-translate-x-24' : ''\"\n role=\"complementary\"\n aria-label=\"Theme switcher panel\"\n>\n <!-- ========================= Theme Selection Buttons ========================= -->\n <div class=\"zs:flex zs:items-center\">\n <div \n class=\"zs:flex zs:overflow-hidden zs:transition-all zs:duration-300\"\n role=\"group\"\n aria-label=\"Theme selection\"\n >\n <!-- Light Theme Button -->\n <button\n (click)=\"setTheme('light')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-l-none zs:border-l-0 zs:border-y \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate light theme\"\n [attr.aria-pressed]=\"currentTheme() === 'light'\"\n >\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n </button>\n\n <!-- Dark Theme Button -->\n <button\n (click)=\"setTheme('dark')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-r-lg zs:border-y zs:border-r \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate dark theme\"\n [attr.aria-pressed]=\"currentTheme() === 'dark'\"\n >\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <!-- ========================= Toggle Button with Connector ========================= -->\n <div \n class=\"zs:relative\"\n [ngClass]=\"isOpen() ? 'zs:hidden' : ''\"\n >\n <!-- Connector Line -->\n <div\n class=\"zs:absolute zs:top-1/2 zs:right-0 zs:h-0.5 zs:w-3 zs:transform zs:-translate-y-1/2\n zs:bg-gray-300 zs:dark:bg-gray-600\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Toggle Button -->\n <button\n (click)=\"toggleOpen()\"\n type=\"button\"\n class=\"zs:relative zs:z-100 zs:w-12 zs:h-12 zs:rounded-full zs:rounded-l-none zs:border-l-0 \n zs:border-2\n zs:transition-all zs:duration-300 zs:flex zs:items-center zs:justify-center\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Toggle theme switcher\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-controls=\"theme-panel\"\n >\n @if (currentTheme() === 'dark') {\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n }\n </button>\n </div>\n </div>\n</div>", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1994
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: ThemeToggle, isStandalone: true, selector: "ZS-theme-toggle", inputs: { bodyClass: { classPropertyName: "bodyClass", publicName: "bodyClass", isSignal: true, isRequired: false, transformFunction: null }, showDefaultUI: { classPropertyName: "showDefaultUI", publicName: "showDefaultUI", isSignal: true, isRequired: false, transformFunction: null }, setManualTheme: { classPropertyName: "setManualTheme", publicName: "setManualTheme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { themeChangeEv: "themeChangeEv" }, host: { listeners: { "document:click": "onDocumentClick($event)" } }, ngImport: i0, template: "<!-- ========================= Theme Switcher Panel ========================= -->\n@if(showDefaultUI()) {\n <div \n class=\"zs:fixed zs:left-0 zs:top-1/6 {{ zIndices.themeToggle }} zs:transform \n zs:-translate-y-1/2 zs:transition-all zs:duration-300\"\n [ngClass]=\"!isOpen() ? 'zs:-translate-x-24' : ''\"\n role=\"complementary\"\n aria-label=\"Theme switcher panel\"\n >\n <!-- ========================= Theme Selection Buttons ========================= -->\n <div class=\"zs:flex zs:items-center\">\n <div \n class=\"zs:flex zs:overflow-hidden zs:transition-all zs:duration-300\"\n role=\"group\"\n aria-label=\"Theme selection\"\n >\n <!-- Light Theme Button -->\n <button\n (click)=\"setTheme('light')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-l-none zs:border-l-0 zs:border-y \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate light theme\"\n [attr.aria-pressed]=\"currentTheme() === 'light'\"\n >\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n </button>\n \n <!-- Dark Theme Button -->\n <button\n (click)=\"setTheme('dark')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-r-lg zs:border-y zs:border-r \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate dark theme\"\n [attr.aria-pressed]=\"currentTheme() === 'dark'\"\n >\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n </button>\n </div>\n \n <!-- ========================= Toggle Button with Connector ========================= -->\n <div \n class=\"zs:relative\"\n [ngClass]=\"isOpen() ? 'zs:hidden' : ''\"\n >\n <!-- Connector Line -->\n <div\n class=\"zs:absolute zs:top-1/2 zs:right-0 zs:h-0.5 zs:w-3 zs:transform zs:-translate-y-1/2\n zs:bg-gray-300 zs:dark:bg-gray-600\"\n aria-hidden=\"true\"\n ></div>\n \n <!-- Toggle Button -->\n <button\n (click)=\"toggleOpen()\"\n type=\"button\"\n class=\"zs:relative zs:z-100 zs:w-12 zs:h-12 zs:rounded-full zs:rounded-l-none zs:border-l-0 \n zs:border-2\n zs:transition-all zs:duration-300 zs:flex zs:items-center zs:justify-center\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Toggle theme switcher\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-controls=\"theme-panel\"\n >\n @if (currentTheme() === 'dark') {\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n }\n </button>\n </div>\n </div>\n </div>\n}", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
1974
1995
  }
1975
1996
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ThemeToggle, decorators: [{
1976
1997
  type: Component,
1977
- args: [{ selector: 'ZS-theme-toggle', imports: [CommonModule], template: "<!-- ========================= Theme Switcher Panel ========================= -->\n<div \n class=\"zs:fixed zs:left-0 zs:top-1/6 {{ zIndices.themeToggle }} zs:transform \n zs:-translate-y-1/2 zs:transition-all zs:duration-300\"\n [ngClass]=\"!isOpen() ? 'zs:-translate-x-24' : ''\"\n role=\"complementary\"\n aria-label=\"Theme switcher panel\"\n>\n <!-- ========================= Theme Selection Buttons ========================= -->\n <div class=\"zs:flex zs:items-center\">\n <div \n class=\"zs:flex zs:overflow-hidden zs:transition-all zs:duration-300\"\n role=\"group\"\n aria-label=\"Theme selection\"\n >\n <!-- Light Theme Button -->\n <button\n (click)=\"setTheme('light')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-l-none zs:border-l-0 zs:border-y \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate light theme\"\n [attr.aria-pressed]=\"currentTheme() === 'light'\"\n >\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n </button>\n\n <!-- Dark Theme Button -->\n <button\n (click)=\"setTheme('dark')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-r-lg zs:border-y zs:border-r \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate dark theme\"\n [attr.aria-pressed]=\"currentTheme() === 'dark'\"\n >\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n </button>\n </div>\n\n <!-- ========================= Toggle Button with Connector ========================= -->\n <div \n class=\"zs:relative\"\n [ngClass]=\"isOpen() ? 'zs:hidden' : ''\"\n >\n <!-- Connector Line -->\n <div\n class=\"zs:absolute zs:top-1/2 zs:right-0 zs:h-0.5 zs:w-3 zs:transform zs:-translate-y-1/2\n zs:bg-gray-300 zs:dark:bg-gray-600\"\n aria-hidden=\"true\"\n ></div>\n\n <!-- Toggle Button -->\n <button\n (click)=\"toggleOpen()\"\n type=\"button\"\n class=\"zs:relative zs:z-100 zs:w-12 zs:h-12 zs:rounded-full zs:rounded-l-none zs:border-l-0 \n zs:border-2\n zs:transition-all zs:duration-300 zs:flex zs:items-center zs:justify-center\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Toggle theme switcher\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-controls=\"theme-panel\"\n >\n @if (currentTheme() === 'dark') {\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n }\n </button>\n </div>\n </div>\n</div>", styles: [":host{display:block}\n"] }]
1978
- }], ctorParameters: () => [], propDecorators: { bodyClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "bodyClass", required: false }] }], themeChangeEv: [{ type: i0.Output, args: ["themeChangeEv"] }], onDocumentClick: [{
1998
+ args: [{ selector: 'ZS-theme-toggle', imports: [CommonModule], template: "<!-- ========================= Theme Switcher Panel ========================= -->\n@if(showDefaultUI()) {\n <div \n class=\"zs:fixed zs:left-0 zs:top-1/6 {{ zIndices.themeToggle }} zs:transform \n zs:-translate-y-1/2 zs:transition-all zs:duration-300\"\n [ngClass]=\"!isOpen() ? 'zs:-translate-x-24' : ''\"\n role=\"complementary\"\n aria-label=\"Theme switcher panel\"\n >\n <!-- ========================= Theme Selection Buttons ========================= -->\n <div class=\"zs:flex zs:items-center\">\n <div \n class=\"zs:flex zs:overflow-hidden zs:transition-all zs:duration-300\"\n role=\"group\"\n aria-label=\"Theme selection\"\n >\n <!-- Light Theme Button -->\n <button\n (click)=\"setTheme('light')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-l-none zs:border-l-0 zs:border-y \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate light theme\"\n [attr.aria-pressed]=\"currentTheme() === 'light'\"\n >\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n </button>\n \n <!-- Dark Theme Button -->\n <button\n (click)=\"setTheme('dark')\"\n type=\"button\"\n class=\"zs:px-3 zs:py-2 zs:rounded-r-lg zs:border-y zs:border-r \n zs:transition-colors zs:shrink-0\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700 zs:w-12\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Activate dark theme\"\n [attr.aria-pressed]=\"currentTheme() === 'dark'\"\n >\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n </button>\n </div>\n \n <!-- ========================= Toggle Button with Connector ========================= -->\n <div \n class=\"zs:relative\"\n [ngClass]=\"isOpen() ? 'zs:hidden' : ''\"\n >\n <!-- Connector Line -->\n <div\n class=\"zs:absolute zs:top-1/2 zs:right-0 zs:h-0.5 zs:w-3 zs:transform zs:-translate-y-1/2\n zs:bg-gray-300 zs:dark:bg-gray-600\"\n aria-hidden=\"true\"\n ></div>\n \n <!-- Toggle Button -->\n <button\n (click)=\"toggleOpen()\"\n type=\"button\"\n class=\"zs:relative zs:z-100 zs:w-12 zs:h-12 zs:rounded-full zs:rounded-l-none zs:border-l-0 \n zs:border-2\n zs:transition-all zs:duration-300 zs:flex zs:items-center zs:justify-center\n zs:bg-white zs:text-gray-900 zs:border-gray-300\n zs:dark:bg-gray-800 zs:dark:text-gray-100 zs:dark:border-gray-600\n zs:hover:bg-gray-100 zs:dark:hover:bg-gray-700\n zs:focus:outline-hidden zs:focus-visible:ring-2 zs:focus-visible:ring-offset-2 \n zs:focus-visible:ring-blue-500\"\n aria-label=\"Toggle theme switcher\"\n [attr.aria-expanded]=\"isOpen()\"\n aria-controls=\"theme-panel\"\n >\n @if (currentTheme() === 'dark') {\n <i class=\"fas fa-moon\" aria-hidden=\"true\"></i>\n } @else {\n <i class=\"fas fa-sun zs:text-yellow-500\" aria-hidden=\"true\"></i>\n }\n </button>\n </div>\n </div>\n </div>\n}", styles: [":host{display:block}\n"] }]
1999
+ }], ctorParameters: () => [], propDecorators: { bodyClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "bodyClass", required: false }] }], showDefaultUI: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDefaultUI", required: false }] }], setManualTheme: [{ type: i0.Input, args: [{ isSignal: true, alias: "setManualTheme", required: false }] }], themeChangeEv: [{ type: i0.Output, args: ["themeChangeEv"] }], onDocumentClick: [{
1979
2000
  type: HostListener,
1980
2001
  args: ['document:click', ['$event']]
1981
2002
  }] } });
@@ -3150,6 +3171,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
3150
3171
  args: [{ selector: 'ZS-toggle', imports: [Label, CommonModule], template: "<div class=\"zs:flex zs:items-center zs:justify-start zs:w-full zs:select-none\">\n <!-- ===================== Checkbox Wrapper ===================== -->\n <div\n class=\"zs:cursor-pointer zs:leading-none\"\n >\n <!-- ===================== Hidden Input (Native for screen readers) ===================== -->\n <input\n type=\"checkbox\"\n class=\"zs:hidden\"\n [id]=\"Id()\"\n [checked]=\"isChecked()\"\n [disabled]=\"disabledOrReadonly()\"\n (change)=\"toggleChecked()\"\n />\n\n <!-- ===================== Custom Accessible Toggle ===================== -->\n <button\n (click)=\"value.set(!value())\"\n class=\"zs:relative zs:rounded-full zs:border-2 zs:flex zs:items-center zs:transition-all zs:duration-500 zs:ease-in-out zs:overflow-hidden\"\n [ngClass]=\"[\n toggleClasses(),\n colorClasses('border'),\n value() ? colorClasses('bg') : '', \n value() ? '' : 'zs:bg-gray-100 zs:dark:bg-gray-700',\n btnSize(),\n ]\"\n >\n <div\n class=\"zs:absolute zs:left-1 zs:top-1/2 zs:-translate-1/2 zs:rounded-full zs:flex zs:items-center zs:justify-center zs:transition-all zs:duration-500 zs:ease-in-out zs:shadow-md\"\n [ngClass]=\"[\n value() ? '' : colorClasses('bg'),\n value() ? colorClasses('text') : 'zs:text-gray-100 zs:dark:text-gray-300',\n value() ? 'zs:bg-gray-100 zs:dark:bg-gray-300' : '',\n wrapperSize(),\n value() ? transSize() : 'zs:translate-x-0',\n ]\"\n >\n <i [class]=\"icon()\"></i>\n </div>\n </button>\n </div>\n\n <!-- ===================== Label (ZS-label component) ===================== -->\n <ZS-label [class]=\"(label() || hint()) ? 'zs:ml-1' : ''\"\n [id]=\"Id() + '-label'\"\n [label]=\"label()\"\n [hint]=\"hint()\"\n [size]=\"size()\"\n [hintId]=\"Id() + '-hint'\"\n [for]=\"Id()\"\n ></ZS-label>\n</div>" }]
3151
3172
  }], propDecorators: { Id: [{ type: i0.Input, args: [{ isSignal: true, alias: "Id", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], isReadonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "isReadonly", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
3152
3173
 
3174
+ class Footer {
3175
+ showDefultContent = input(true, ...(ngDevMode ? [{ debugName: "showDefultContent" }] : []));
3176
+ pages = input([], ...(ngDevMode ? [{ debugName: "pages" }] : []));
3177
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Footer, deps: [], target: i0.ɵɵFactoryTarget.Component });
3178
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.9", type: Footer, isStandalone: true, selector: "ZS-footer", inputs: { showDefultContent: { classPropertyName: "showDefultContent", publicName: "showDefultContent", isSignal: true, isRequired: false, transformFunction: null }, pages: { classPropertyName: "pages", publicName: "pages", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<footer class=\"zs:bg-gray-700 zs:dark:bg-gray-950 zs:dark:text-gray-300 zs:text-white zs:py-8\">\n <div class=\"zs:text-center zs:flex zs:flex-col zs:gap-8\">\n <p class=\"zs:text-xs zs:sm:text-sm zs:px-6\">\n <ng-content select=\"[rights]\"></ng-content>\n\n @if(showDefultContent()) {\n &copy;\n <span class=\"zs:font-semibold\">2026 Ziad Ahmed Shalaby</span>.\n All rights reserved.\n }\n </p>\n\n @if(pages().length) {\n <nav class=\"zs:flex zs:flex-wrap zs:justify-center zs:items-center\n zs:gap-y-6 zs:gap-x-4 zs:sm:gap-x-6 zs:md:gap-x-8 zs:lg:gap-x-10 zs:w-full\">\n @for (page of pages(); track $index) {\n <a class=\"zs:text-[10px] zs:sm:text-xs \n zs:hover:underline zs:text-center zs:min-w-30\" \n [routerLink]=\"page.routerLink\">\n {{ page.label }}\n </a>\n }\n </nav>\n }\n </div>\n</footer>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] });
3179
+ }
3180
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Footer, decorators: [{
3181
+ type: Component,
3182
+ args: [{ selector: 'ZS-footer', imports: [RouterModule], template: "<footer class=\"zs:bg-gray-700 zs:dark:bg-gray-950 zs:dark:text-gray-300 zs:text-white zs:py-8\">\n <div class=\"zs:text-center zs:flex zs:flex-col zs:gap-8\">\n <p class=\"zs:text-xs zs:sm:text-sm zs:px-6\">\n <ng-content select=\"[rights]\"></ng-content>\n\n @if(showDefultContent()) {\n &copy;\n <span class=\"zs:font-semibold\">2026 Ziad Ahmed Shalaby</span>.\n All rights reserved.\n }\n </p>\n\n @if(pages().length) {\n <nav class=\"zs:flex zs:flex-wrap zs:justify-center zs:items-center\n zs:gap-y-6 zs:gap-x-4 zs:sm:gap-x-6 zs:md:gap-x-8 zs:lg:gap-x-10 zs:w-full\">\n @for (page of pages(); track $index) {\n <a class=\"zs:text-[10px] zs:sm:text-xs \n zs:hover:underline zs:text-center zs:min-w-30\" \n [routerLink]=\"page.routerLink\">\n {{ page.label }}\n </a>\n }\n </nav>\n }\n </div>\n</footer>\n" }]
3183
+ }], propDecorators: { showDefultContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDefultContent", required: false }] }], pages: [{ type: i0.Input, args: [{ isSignal: true, alias: "pages", required: false }] }] } });
3184
+
3153
3185
  /*
3154
3186
  * Public API Surface of ngx-zs-component
3155
3187
  */
@@ -3158,5 +3190,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
3158
3190
  * Generated bundle index. Do not edit.
3159
3191
  */
3160
3192
 
3161
- export { ALERT_CONFIG, Alert, AlertService, Button, Card, Carousel, Checkbox, ColorMapping, Connection, ExtractorService, FileInput, Form, Input, InputErrors, Label, Modal, NavItem, NavItemService, Navbar, NgxZsComponent, Page404, Pagination, Range, ScrollToTop, Select, Spinner, ThemeToggle, Toggle, buttonOutlinePaletteMap, buttonSolidPaletteMap, cardPaletteMap, checkboxTextPaletteMap, inputPaletteMap, modalPaletteMap, page404PaletteMap, ringPaletteMap, selectPaletteMap, unifiedPaletteMap };
3193
+ export { ALERT_CONFIG, Alert, AlertService, Button, Card, Carousel, Checkbox, ColorMapping, Connection, ExtractorService, FileInput, Footer, Form, Input, InputErrors, Label, Modal, NavItem, NavItemService, Navbar, NgxZsComponent, Page404, Pagination, Range, ScrollToTop, Select, Spinner, ThemeToggle, Toggle, buttonOutlinePaletteMap, buttonSolidPaletteMap, cardPaletteMap, checkboxTextPaletteMap, inputPaletteMap, modalPaletteMap, page404PaletteMap, ringPaletteMap, selectPaletteMap, unifiedPaletteMap };
3162
3194
  //# sourceMappingURL=ziadshalaby-ngx-zs-component.mjs.map