@ziadshalaby/ngx-zs-component 2.0.0 → 2.0.2

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.
@@ -550,10 +550,41 @@ const ColorMapping = new Map([
550
550
  ['rose', { text: 'zs:text-rose-600 zs:dark:text-rose-400', bg: 'zs:bg-rose-600 zs:dark:bg-rose-400', border: 'zs:border-rose-600 zs:dark:border-rose-400' }],
551
551
  ]);
552
552
 
553
+ class VisibilityObserverService {
554
+ observer;
555
+ constructor() {
556
+ this.observer = new IntersectionObserver((entries) => {
557
+ for (const entry of entries) {
558
+ const target = entry.target;
559
+ if (entry.isIntersecting) {
560
+ // trigger the signal saved on target
561
+ target.__visibleSignal?.set(true);
562
+ // stop observing this element
563
+ this.observer.unobserve(entry.target);
564
+ }
565
+ }
566
+ }, { threshold: 0.2 });
567
+ }
568
+ observe(el, visibleSignal) {
569
+ // attach signal reference to element
570
+ el.__visibleSignal = visibleSignal;
571
+ this.observer.observe(el);
572
+ }
573
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: VisibilityObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
574
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: VisibilityObserverService, providedIn: 'root' });
575
+ }
576
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: VisibilityObserverService, decorators: [{
577
+ type: Injectable,
578
+ args: [{
579
+ providedIn: 'root',
580
+ }]
581
+ }], ctorParameters: () => [] });
582
+
553
583
  // ==============================================================================
554
584
  // Component
555
585
  // ==============================================================================
556
586
  class Card {
587
+ visibility = inject(VisibilityObserverService);
557
588
  // ==========================================================================
558
589
  // Inputs
559
590
  // ==========================================================================
@@ -568,18 +599,10 @@ class Card {
568
599
  cardRef = viewChild('cardRef', ...(ngDevMode ? [{ debugName: "cardRef" }] : []));
569
600
  isVisible = signal(false, ...(ngDevMode ? [{ debugName: "isVisible" }] : []));
570
601
  constructor() {
571
- const observer = new IntersectionObserver((entries) => {
572
- for (const entry of entries) {
573
- if (entry.isIntersecting) {
574
- this.isVisible.set(true);
575
- observer.unobserve(entry.target);
576
- }
577
- }
578
- }, { threshold: 0.2 });
579
602
  queueMicrotask(() => {
580
603
  const el = this.cardRef()?.nativeElement;
581
604
  if (el)
582
- observer.observe(el);
605
+ this.visibility.observe(el, this.isVisible);
583
606
  });
584
607
  }
585
608
  // ==========================================================================
@@ -1277,11 +1300,11 @@ class Navbar {
1277
1300
  this.resizeObserver.disconnect();
1278
1301
  }
1279
1302
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Navbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1280
- 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 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 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 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"] }] });
1303
+ 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"] }] });
1281
1304
  }
1282
1305
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Navbar, decorators: [{
1283
1306
  type: Component,
1284
- args: [{ selector: 'ZS-navbar', imports: [RouterModule, CommonModule, NavItem, Button], 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 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 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 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"] }]
1307
+ args: [{ selector: 'ZS-navbar', imports: [RouterModule, CommonModule, NavItem, Button], 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"] }]
1285
1308
  }], propDecorators: { fixed: [{ type: i0.Input, args: [{ isSignal: true, alias: "fixed", required: false }] }], logoUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "logoUrl", required: false }] }], siteNameConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "siteNameConfig", required: false }] }], authButtons: [{ type: i0.Input, args: [{ isSignal: true, alias: "authButtons", required: false }] }], showUserSection: [{ type: i0.Input, args: [{ isSignal: true, alias: "showUserSection", required: false }] }], showSearchBar: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSearchBar", required: false }] }], navItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "navItems", required: false }] }], isLoggedIn: [{ type: i0.Input, args: [{ isSignal: true, alias: "isLoggedIn", required: false }] }], userProfile: [{ type: i0.Input, args: [{ isSignal: true, alias: "userProfile", required: false }] }], userMenuItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "userMenuItems", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], loginClickedEv: [{ type: i0.Output, args: ["loginClickedEv"] }], signupClickedEv: [{ type: i0.Output, args: ["signupClickedEv"] }], searchSubmittedEv: [{ type: i0.Output, args: ["searchSubmittedEv"] }], anyItemClickedEv: [{ type: i0.Output, args: ["anyItemClickedEv"] }], searchValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchValue", required: false }] }, { type: i0.Output, args: ["searchValueChange"] }], isMobileMenuOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMobileMenuOpen", required: false }] }, { type: i0.Output, args: ["isMobileMenuOpenChange"] }] } });
1286
1309
 
1287
1310
  class Page404 {
@@ -1291,20 +1314,38 @@ class Page404 {
1291
1314
  title = input('Page Not Found', ...(ngDevMode ? [{ debugName: "title" }] : []));
1292
1315
  message = input('Hmm… this page doesn’t seem to exist. Try checking the URL or going back home.', ...(ngDevMode ? [{ debugName: "message" }] : []));
1293
1316
  icon = input('fa-ghost', ...(ngDevMode ? [{ debugName: "icon" }] : []));
1317
+ pageStyle = input('normal', ...(ngDevMode ? [{ debugName: "pageStyle" }] : []));
1294
1318
  showButton = input(true, ...(ngDevMode ? [{ debugName: "showButton" }] : []));
1295
1319
  buttonText = input('Go Home', ...(ngDevMode ? [{ debugName: "buttonText" }] : []));
1296
1320
  routerLink = input('/', ...(ngDevMode ? [{ debugName: "routerLink" }] : []));
1297
1321
  // ========================================================================
1298
1322
  // Outputs
1299
1323
  // ========================================================================
1324
+ style = computed(() => {
1325
+ if (this.pageStyle() === 'normal')
1326
+ return {
1327
+ btnBG: 'zs:bg-sky-500 zs:dark:bg-sky-600',
1328
+ btnBgHover: 'zs:hover:bg-sky-600 zs:dark:hover:bg-sky-500',
1329
+ iconText: 'zs:text-sky-600 zs:dark:text-sky-500'
1330
+ };
1331
+ const pallete = FormPaletteMap.get(this.pageStyle() ?? 'violet');
1332
+ return {
1333
+ btnBG: pallete.btnBG,
1334
+ btnBgHover: pallete.btnBGHover,
1335
+ iconText: pallete.checkBoxText
1336
+ };
1337
+ }, ...(ngDevMode ? [{ debugName: "style" }] : []));
1338
+ // ========================================================================
1339
+ // Outputs
1340
+ // ========================================================================
1300
1341
  onAction = output();
1301
1342
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Page404, deps: [], target: i0.ɵɵFactoryTarget.Component });
1302
- 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 }, 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:text-sky-600 zs:dark:text-sky-500\n zs:transition-colors zs:duration-500 zs:animate-fadeIn\">\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:bg-sky-500 zs:text-white zs:font-medium zs:shadow-md\n zs:hover:bg-sky-600 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 zs:dark:bg-sky-600 zs:dark:hover:bg-sky-500\"\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"] }] });
1343
+ 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"] }] });
1303
1344
  }
1304
1345
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: Page404, decorators: [{
1305
1346
  type: Component,
1306
- args: [{ selector: 'ZS-page404', imports: [RouterModule], 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:text-sky-600 zs:dark:text-sky-500\n zs:transition-colors zs:duration-500 zs:animate-fadeIn\">\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:bg-sky-500 zs:text-white zs:font-medium zs:shadow-md\n zs:hover:bg-sky-600 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 zs:dark:bg-sky-600 zs:dark:hover:bg-sky-500\"\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"] }]
1307
- }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], showButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButton", required: false }] }], buttonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonText", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], onAction: [{ type: i0.Output, args: ["onAction"] }] } });
1347
+ args: [{ selector: 'ZS-page404', imports: [RouterModule, CommonModule], 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"] }]
1348
+ }], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], message: [{ type: i0.Input, args: [{ isSignal: true, alias: "message", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], pageStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageStyle", required: false }] }], showButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showButton", required: false }] }], buttonText: [{ type: i0.Input, args: [{ isSignal: true, alias: "buttonText", required: false }] }], routerLink: [{ type: i0.Input, args: [{ isSignal: true, alias: "routerLink", required: false }] }], onAction: [{ type: i0.Output, args: ["onAction"] }] } });
1308
1349
 
1309
1350
  // ========================================================================
1310
1351
  // Imports