@dataif/cli 0.1.0

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.
Files changed (183) hide show
  1. package/README.md +16 -0
  2. package/bin/dataif.js +623 -0
  3. package/package.json +26 -0
  4. package/scripts/build-template.mjs +72 -0
  5. package/templates/dataif/README.md +157 -0
  6. package/templates/dataif/infra/.env.example +119 -0
  7. package/templates/dataif/infra/.env.stg.example +119 -0
  8. package/templates/dataif/infra/airflow/Dockerfile +11 -0
  9. package/templates/dataif/infra/airflow/Dockerfile.release +17 -0
  10. package/templates/dataif/infra/airflow/requirements.txt +3 -0
  11. package/templates/dataif/infra/docker-compose.yml +306 -0
  12. package/templates/dataif/infra/init-db/01-init-dataif.sh +129 -0
  13. package/templates/dataif/infra/init-db/pnp-curated-views.sqlinc +444 -0
  14. package/templates/dataif/infra/init-db/pnp-raw-staging-curated.sqlinc +701 -0
  15. package/templates/dataif/infra/keycloak/Dockerfile +4 -0
  16. package/templates/dataif/infra/keycloak/realm-dataif.json +73 -0
  17. package/templates/dataif/infra/ollama/Dockerfile +9 -0
  18. package/templates/dataif/infra/ollama/bootstrap-model.sh +100 -0
  19. package/templates/dataif/infra/ollama/sabia-7b.Modelfile +14 -0
  20. package/templates/dataif/infra/postgres/Dockerfile +4 -0
  21. package/templates/dataif/pipelines/airflow/dags/generated/.gitkeep +1 -0
  22. package/templates/dataif/pipelines/airflow/dags/generated/2020_financeiro_fcc6f1f3_sync.py +9 -0
  23. package/templates/dataif/pipelines/dataif_pipelines/__init__.py +1 -0
  24. package/templates/dataif/pipelines/dataif_pipelines/airflow/__init__.py +1 -0
  25. package/templates/dataif/pipelines/dataif_pipelines/airflow/pnp_pipeline_factory.py +167 -0
  26. package/templates/dataif/pipelines/dataif_pipelines/connectors/__init__.py +1 -0
  27. package/templates/dataif/pipelines/dataif_pipelines/connectors/base/__init__.py +1 -0
  28. package/templates/dataif/pipelines/dataif_pipelines/connectors/base/connector.py +28 -0
  29. package/templates/dataif/pipelines/dataif_pipelines/connectors/base/types.py +14 -0
  30. package/templates/dataif/pipelines/dataif_pipelines/connectors/nilo_pecanha/__init__.py +1 -0
  31. package/templates/dataif/pipelines/dataif_pipelines/connectors/nilo_pecanha/config.py +19 -0
  32. package/templates/dataif/pipelines/dataif_pipelines/connectors/nilo_pecanha/connector.py +558 -0
  33. package/templates/dataif/pipelines/dataif_pipelines/connectors/nilo_pecanha/powerbi_microdados.py +728 -0
  34. package/templates/dataif/pipelines/dataif_pipelines/connectors/nilo_pecanha/transform.py +296 -0
  35. package/templates/dataif/pipelines/dataif_pipelines/jobs/__init__.py +1 -0
  36. package/templates/dataif/pipelines/dataif_pipelines/jobs/nilo_pipeline.py +112 -0
  37. package/templates/dataif/pipelines/dataif_pipelines/orchestration/__init__.py +21 -0
  38. package/templates/dataif/pipelines/dataif_pipelines/orchestration/pnp_workflow.py +783 -0
  39. package/templates/dataif/pipelines/dataif_pipelines/repositories/__init__.py +1 -0
  40. package/templates/dataif/pipelines/dataif_pipelines/repositories/pnp_raw_repository.py +860 -0
  41. package/templates/dataif/pipelines/dataif_pipelines/services/__init__.py +19 -0
  42. package/templates/dataif/pipelines/dataif_pipelines/services/pnp_curated_service.py +66 -0
  43. package/templates/dataif/pipelines/dataif_pipelines/services/pnp_download_service.py +534 -0
  44. package/templates/dataif/pipelines/dataif_pipelines/services/pnp_quality_service.py +9 -0
  45. package/templates/dataif/pipelines/dataif_pipelines/services/pnp_raw_ingestion_service.py +124 -0
  46. package/templates/dataif/pipelines/dataif_pipelines/services/pnp_staging_service.py +271 -0
  47. package/templates/dataif/pipelines/dataif_pipelines/services/powerbi_catalog_service.py +159 -0
  48. package/templates/dataif/pipelines/sql/staging/020_pnp_matriculas.sql +112 -0
  49. package/templates/dataif/pipelines/sql/staging/030_pnp_eficiencia_academica.sql +83 -0
  50. package/templates/dataif/pipelines/sql/staging/040_pnp_servidores.sql +90 -0
  51. package/templates/dataif/pipelines/sql/staging/050_pnp_financeiro.sql +72 -0
  52. package/templates/dataif/pipelines/sql/views_curated/004_mv_pnp_dashboard_fast.sql +204 -0
  53. package/templates/dataif/pipelines/sql/views_curated/010_vw_pnp_admin_ingestao.sql +51 -0
  54. package/templates/dataif/pipelines/sql/views_curated/020_vw_pnp_qualidade_dados.sql +114 -0
  55. package/templates/dataif/pipelines/sql/views_curated/030_vw_pnp_matriculas.sql +67 -0
  56. package/templates/dataif/pipelines/sql/views_curated/040_vw_pnp_eficiencia.sql +33 -0
  57. package/templates/dataif/pipelines/sql/views_curated/050_vw_pnp_servidores.sql +30 -0
  58. package/templates/dataif/pipelines/sql/views_curated/060_vw_pnp_financeiro.sql +22 -0
  59. package/templates/dataif/pipelines/sql/views_curated/070_vw_pnp_vanna.sql +115 -0
  60. package/templates/dataif/scripts/configure-env.sh +149 -0
  61. package/templates/dataif/scripts/create_metabase_pnp_dashboard.py +943 -0
  62. package/templates/dataif/scripts/create_metabase_pnp_matriculas_dashboard.py +580 -0
  63. package/templates/dataif/scripts/deploy.sh +79 -0
  64. package/templates/dataif/scripts/fix_metabase_template_tag_ids.py +91 -0
  65. package/templates/dataif/scripts/pnp_powerbi_microdados_probe.py +14 -0
  66. package/templates/dataif/scripts/pnp_validate_raw_run.py +330 -0
  67. package/templates/dataif/scripts/publish-images.sh +31 -0
  68. package/templates/dataif/scripts/sync_metabase_dashboard_field_filters.py +241 -0
  69. package/templates/dataif/scripts/use-vanna-ollama.sh +139 -0
  70. package/templates/dataif/services/api/.dockerignore +18 -0
  71. package/templates/dataif/services/api/Dockerfile +12 -0
  72. package/templates/dataif/services/api/app/__init__.py +1 -0
  73. package/templates/dataif/services/api/app/auth.py +48 -0
  74. package/templates/dataif/services/api/app/config.py +59 -0
  75. package/templates/dataif/services/api/app/keycloak_admin.py +215 -0
  76. package/templates/dataif/services/api/app/main.py +2432 -0
  77. package/templates/dataif/services/api/app/metabase_admin.py +191 -0
  78. package/templates/dataif/services/api/app/metabase_bootstrap.py +44 -0
  79. package/templates/dataif/services/api/app/metabase_embed.py +15 -0
  80. package/templates/dataif/services/api/app/pnp_dag_provisioner.py +113 -0
  81. package/templates/dataif/services/api/app/pnp_instance_repository.py +951 -0
  82. package/templates/dataif/services/api/app/pnp_powerbi.py +438 -0
  83. package/templates/dataif/services/api/app/vanna_client.py +32 -0
  84. package/templates/dataif/services/api/requirements.txt +9 -0
  85. package/templates/dataif/services/vanna/.dockerignore +18 -0
  86. package/templates/dataif/services/vanna/Dockerfile +12 -0
  87. package/templates/dataif/services/vanna/app/config.py +57 -0
  88. package/templates/dataif/services/vanna/app/main.py +108 -0
  89. package/templates/dataif/services/vanna/app/runtime_config.py +114 -0
  90. package/templates/dataif/services/vanna/app/sql_guard.py +123 -0
  91. package/templates/dataif/services/vanna/app/vanna_engine.py +382 -0
  92. package/templates/dataif/services/vanna/requirements.txt +8 -0
  93. package/templates/dataif/services/web/.dockerignore +13 -0
  94. package/templates/dataif/services/web/Dockerfile +16 -0
  95. package/templates/dataif/services/web/index.html +12 -0
  96. package/templates/dataif/services/web/nginx.conf +74 -0
  97. package/templates/dataif/services/web/package-lock.json +4397 -0
  98. package/templates/dataif/services/web/package.json +32 -0
  99. package/templates/dataif/services/web/postcss.config.mjs +5 -0
  100. package/templates/dataif/services/web/src/App.jsx +2817 -0
  101. package/templates/dataif/services/web/src/adminAuth.js +245 -0
  102. package/templates/dataif/services/web/src/assets/avatar_placeholder.png +0 -0
  103. package/templates/dataif/services/web/src/assets/github_logo_icon_229278.svg +1 -0
  104. package/templates/dataif/services/web/src/assets/if-logo.png +0 -0
  105. package/templates/dataif/services/web/src/assets/if.svg +0 -0
  106. package/templates/dataif/services/web/src/assets/pnp-horizontal.svg +1 -0
  107. package/templates/dataif/services/web/src/components/AppHeader.jsx +233 -0
  108. package/templates/dataif/services/web/src/components/application/app-navigation/base-components/mobile-header.tsx +56 -0
  109. package/templates/dataif/services/web/src/components/application/app-navigation/base-components/nav-account-card.tsx +209 -0
  110. package/templates/dataif/services/web/src/components/application/app-navigation/base-components/nav-item-button.tsx +67 -0
  111. package/templates/dataif/services/web/src/components/application/app-navigation/base-components/nav-item.tsx +108 -0
  112. package/templates/dataif/services/web/src/components/application/app-navigation/base-components/nav-list.tsx +83 -0
  113. package/templates/dataif/services/web/src/components/application/app-navigation/config.ts +23 -0
  114. package/templates/dataif/services/web/src/components/application/app-navigation/header-navigation.tsx +240 -0
  115. package/templates/dataif/services/web/src/components/application/pagination/pagination-base.tsx +376 -0
  116. package/templates/dataif/services/web/src/components/application/pagination/pagination-dot.tsx +52 -0
  117. package/templates/dataif/services/web/src/components/application/pagination/pagination-line.tsx +48 -0
  118. package/templates/dataif/services/web/src/components/application/pagination/pagination.tsx +328 -0
  119. package/templates/dataif/services/web/src/components/application/tabs/tabs.tsx +223 -0
  120. package/templates/dataif/services/web/src/components/base/avatar/avatar-label-group.tsx +28 -0
  121. package/templates/dataif/services/web/src/components/base/avatar/avatar.tsx +129 -0
  122. package/templates/dataif/services/web/src/components/base/avatar/base-components/avatar-add-button.tsx +32 -0
  123. package/templates/dataif/services/web/src/components/base/avatar/base-components/avatar-company-icon.tsx +24 -0
  124. package/templates/dataif/services/web/src/components/base/avatar/base-components/avatar-online-indicator.tsx +29 -0
  125. package/templates/dataif/services/web/src/components/base/avatar/base-components/index.tsx +4 -0
  126. package/templates/dataif/services/web/src/components/base/avatar/base-components/verified-tick.tsx +32 -0
  127. package/templates/dataif/services/web/src/components/base/badges/badge-types.ts +264 -0
  128. package/templates/dataif/services/web/src/components/base/badges/badges.tsx +415 -0
  129. package/templates/dataif/services/web/src/components/base/button-group/button-group.tsx +104 -0
  130. package/templates/dataif/services/web/src/components/base/buttons/button.tsx +267 -0
  131. package/templates/dataif/services/web/src/components/base/input/hint-text.tsx +31 -0
  132. package/templates/dataif/services/web/src/components/base/input/input.tsx +269 -0
  133. package/templates/dataif/services/web/src/components/base/input/label.tsx +48 -0
  134. package/templates/dataif/services/web/src/components/base/radio-buttons/radio-buttons.tsx +127 -0
  135. package/templates/dataif/services/web/src/components/base/select/combobox.tsx +150 -0
  136. package/templates/dataif/services/web/src/components/base/select/multi-select.tsx +361 -0
  137. package/templates/dataif/services/web/src/components/base/select/popover.tsx +32 -0
  138. package/templates/dataif/services/web/src/components/base/select/select-item.tsx +95 -0
  139. package/templates/dataif/services/web/src/components/base/select/select-native.tsx +67 -0
  140. package/templates/dataif/services/web/src/components/base/select/select.tsx +144 -0
  141. package/templates/dataif/services/web/src/components/base/tags/base-components/tag-close-x.tsx +32 -0
  142. package/templates/dataif/services/web/src/components/base/tooltip/tooltip.tsx +107 -0
  143. package/templates/dataif/services/web/src/components/foundations/dot-icon.tsx +22 -0
  144. package/templates/dataif/services/web/src/components/foundations/logo/untitledui-logo-minimal.tsx +170 -0
  145. package/templates/dataif/services/web/src/components/foundations/logo/untitledui-logo.tsx +58 -0
  146. package/templates/dataif/services/web/src/hooks/use-breakpoint.ts +34 -0
  147. package/templates/dataif/services/web/src/hooks/use-resize-observer.ts +67 -0
  148. package/templates/dataif/services/web/src/main.jsx +14 -0
  149. package/templates/dataif/services/web/src/providers/theme-provider.jsx +62 -0
  150. package/templates/dataif/services/web/src/styles/globals.css +60 -0
  151. package/templates/dataif/services/web/src/styles/theme.css +1326 -0
  152. package/templates/dataif/services/web/src/styles/typography.css +430 -0
  153. package/templates/dataif/services/web/src/styles.css +1287 -0
  154. package/templates/dataif/services/web/src/utils/cx.ts +24 -0
  155. package/templates/dataif/services/web/src/utils/is-react-component.ts +33 -0
  156. package/templates/dataif/services/web/vite.config.js +14 -0
  157. package/templates/dataif/sql/ddl/001_schemas.sql +6 -0
  158. package/templates/dataif/sql/ddl/003_pnp_raw_staging_curated.sql +699 -0
  159. package/templates/dataif/sql/migrations/001_pnp_phase1_backfill.sql +3 -0
  160. package/templates/dataif/sql/migrations/002_pnp_phase2_admin_config_backfill.sql +184 -0
  161. package/templates/dataif/sql/migrations/003_pnp_phase3_raw_tabular_backfill.sql +3 -0
  162. package/templates/dataif/sql/migrations/004_pnp_phase3_raw_backfill_support_index.sql +3 -0
  163. package/templates/dataif/sql/migrations/005_pnp_phase7_staging_support_indexes.sql +2 -0
  164. package/templates/dataif/sql/migrations/006_pnp_phase7_staging_autovacuum_tuning.sql +2 -0
  165. package/templates/dataif/sql/migrations/007_pnp_phase7b_run_packages.sql +20 -0
  166. package/templates/dataif/sql/migrations/008_pnp_phase7a_pipeline_endpoints.sql +169 -0
  167. package/templates/dataif/sql/migrations/009_pnp_phase8_curated.sql +35 -0
  168. package/templates/dataif/sql/migrations/010_pnp_phase10_staging_incremental_upsert.sql +3 -0
  169. package/templates/dataif/sql/migrations/010_pnp_pipeline_uuid.sql +51 -0
  170. package/templates/dataif/sql/migrations/011_app_settings.sql +7 -0
  171. package/templates/dataif/sql/staging/020_pnp_matriculas.sql +112 -0
  172. package/templates/dataif/sql/staging/030_pnp_eficiencia_academica.sql +83 -0
  173. package/templates/dataif/sql/staging/040_pnp_servidores.sql +90 -0
  174. package/templates/dataif/sql/staging/050_pnp_financeiro.sql +72 -0
  175. package/templates/dataif/sql/views_curated/003_vw_pnp_microdados_admin.sql +160 -0
  176. package/templates/dataif/sql/views_curated/004_mv_pnp_dashboard_fast.sql +204 -0
  177. package/templates/dataif/sql/views_curated/010_vw_pnp_admin_ingestao.sql +51 -0
  178. package/templates/dataif/sql/views_curated/020_vw_pnp_qualidade_dados.sql +114 -0
  179. package/templates/dataif/sql/views_curated/030_vw_pnp_matriculas.sql +67 -0
  180. package/templates/dataif/sql/views_curated/040_vw_pnp_eficiencia.sql +33 -0
  181. package/templates/dataif/sql/views_curated/050_vw_pnp_servidores.sql +30 -0
  182. package/templates/dataif/sql/views_curated/060_vw_pnp_financeiro.sql +22 -0
  183. package/templates/dataif/sql/views_curated/070_vw_pnp_vanna.sql +115 -0
@@ -0,0 +1,83 @@
1
+ import { useState } from "react";
2
+ import { cx } from "@/utils/cx";
3
+ import type { NavItemDividerType, NavItemType } from "../config";
4
+ import { NavItemBase } from "./nav-item";
5
+
6
+ interface NavListProps {
7
+ /** URL of the currently active item. */
8
+ activeUrl?: string;
9
+ /** Additional CSS classes to apply to the list. */
10
+ className?: string;
11
+ /** List of items to display. */
12
+ items: (NavItemType | NavItemDividerType)[];
13
+ }
14
+
15
+ export const NavList = ({ activeUrl, items, className }: NavListProps) => {
16
+ const [open, setOpen] = useState(false);
17
+ const activeItem = items.find((item) => item.href === activeUrl || item.items?.some((subItem) => subItem.href === activeUrl));
18
+ const [currentItem, setCurrentItem] = useState(activeItem);
19
+
20
+ return (
21
+ <ul className={cx("mt-4 flex flex-col px-2 lg:px-4", className)}>
22
+ {items.map((item, index) => {
23
+ if (item.divider) {
24
+ return (
25
+ <li key={index} className="w-full px-0.5 py-2">
26
+ <hr className="h-px w-full border-none bg-border-secondary" />
27
+ </li>
28
+ );
29
+ }
30
+
31
+ if (item.items?.length) {
32
+ return (
33
+ <details
34
+ key={item.label}
35
+ open={activeItem?.href === item.href}
36
+ className="appearance-none py-0.5"
37
+ onToggle={(e) => {
38
+ setOpen(e.currentTarget.open);
39
+ setCurrentItem(item);
40
+ }}
41
+ >
42
+ <NavItemBase href={item.href} badge={item.badge} icon={item.icon} type="collapsible">
43
+ {item.label}
44
+ </NavItemBase>
45
+
46
+ <dd>
47
+ <ul className="py-0.5">
48
+ {item.items.map((childItem) => (
49
+ <li key={childItem.label} className="py-0.5">
50
+ <NavItemBase
51
+ href={childItem.href}
52
+ badge={childItem.badge}
53
+ type="collapsible-child"
54
+ current={activeUrl === childItem.href}
55
+ >
56
+ {childItem.label}
57
+ </NavItemBase>
58
+ </li>
59
+ ))}
60
+ </ul>
61
+ </dd>
62
+ </details>
63
+ );
64
+ }
65
+
66
+ return (
67
+ <li key={item.label} className="py-0.5">
68
+ <NavItemBase
69
+ type="link"
70
+ badge={item.badge}
71
+ icon={item.icon}
72
+ href={item.href}
73
+ current={currentItem?.href === item.href}
74
+ open={open && currentItem?.href === item.href}
75
+ >
76
+ {item.label}
77
+ </NavItemBase>
78
+ </li>
79
+ );
80
+ })}
81
+ </ul>
82
+ );
83
+ };
@@ -0,0 +1,23 @@
1
+ import type { FC, ReactNode } from "react";
2
+
3
+ export type NavItemType = {
4
+ /** Label text for the nav item. */
5
+ label: string;
6
+ /** URL to navigate to when the nav item is clicked. */
7
+ href?: string;
8
+ /** Icon component to display. */
9
+ icon?: FC<{ className?: string }>;
10
+ /** Badge to display. */
11
+ badge?: ReactNode;
12
+ /** List of sub-items to display. */
13
+ items?: { label: string; href: string; icon?: FC<{ className?: string }>; badge?: ReactNode }[];
14
+ /** Whether this nav item is a divider. */
15
+ divider?: boolean;
16
+ };
17
+
18
+ export type NavItemDividerType = Omit<NavItemType, "icon" | "label" | "divider"> & {
19
+ /** Label text for the divider. */
20
+ label?: string;
21
+ /** Whether this nav item is a divider. */
22
+ divider: true;
23
+ };
@@ -0,0 +1,240 @@
1
+ import type { FC, ReactNode } from "react";
2
+ import { Bell01, LifeBuoy01, SearchLg, Settings01 } from "@untitledui/icons";
3
+ import { Button as AriaButton, DialogTrigger, Popover } from "react-aria-components";
4
+ import { Avatar } from "@/components/base/avatar/avatar";
5
+ import { BadgeWithDot } from "@/components/base/badges/badges";
6
+ import { Input } from "@/components/base/input/input";
7
+ import { UntitledLogo } from "@/components/foundations/logo/untitledui-logo";
8
+ import { cx } from "@/utils/cx";
9
+ import { MobileNavigationHeader } from "./base-components/mobile-header";
10
+ import { NavAccountCard, NavAccountMenu } from "./base-components/nav-account-card";
11
+ import { NavItemBase } from "./base-components/nav-item";
12
+ import { NavItemButton } from "./base-components/nav-item-button";
13
+ import { NavList } from "./base-components/nav-list";
14
+
15
+ type NavItem = {
16
+ /** Label text for the nav item. */
17
+ label: string;
18
+ /** URL to navigate to when the nav item is clicked. */
19
+ href: string;
20
+ /** Whether the nav item is currently active. */
21
+ current?: boolean;
22
+ /** Icon component to display. */
23
+ icon?: FC<{ className?: string }>;
24
+ /** Badge to display. */
25
+ badge?: ReactNode;
26
+ /** List of sub-items to display. */
27
+ items?: NavItem[];
28
+ };
29
+
30
+ interface HeaderNavigationBaseProps {
31
+ /** URL of the currently active item. */
32
+ activeUrl?: string;
33
+ /** List of items to display. */
34
+ items: NavItem[];
35
+ /** List of sub-items to display. */
36
+ subItems?: NavItem[];
37
+ /** Content to display in the trailing position. */
38
+ trailingContent?: ReactNode;
39
+ /** Logo to display in the leading position. */
40
+ logo?: ReactNode;
41
+ /** Logo to display in the mobile header. */
42
+ mobileLogo?: ReactNode;
43
+ /** Whether to show the avatar dropdown. */
44
+ showAvatarDropdown?: boolean;
45
+ /** Whether to show the default utility icon buttons. */
46
+ showDefaultUtilityButtons?: boolean;
47
+ /** Whether to hide the bottom border. */
48
+ hideBorder?: boolean;
49
+ /** Search slot rendered in the mobile drawer. Pass `null` to hide it. */
50
+ mobileSearchSlot?: ReactNode;
51
+ /** Search slot rendered in the secondary nav. Pass `null` to hide it. */
52
+ secondarySearchSlot?: ReactNode;
53
+ /** Content rendered at the bottom of the mobile drawer. */
54
+ mobileFooterContent?: ReactNode;
55
+ /** Custom avatar dropdown element. */
56
+ avatarDropdown?: ReactNode;
57
+ }
58
+
59
+ export const HeaderNavigationBase = ({
60
+ activeUrl,
61
+ items,
62
+ subItems,
63
+ trailingContent,
64
+ logo,
65
+ mobileLogo,
66
+ showAvatarDropdown = true,
67
+ showDefaultUtilityButtons = true,
68
+ hideBorder = false,
69
+ mobileSearchSlot,
70
+ secondarySearchSlot,
71
+ mobileFooterContent,
72
+ avatarDropdown,
73
+ }: HeaderNavigationBaseProps) => {
74
+ const activeSubNavItems = subItems || items.find((item) => item.current && item.items && item.items.length > 0)?.items;
75
+
76
+ const showSecondaryNav = activeSubNavItems && activeSubNavItems.length > 0;
77
+
78
+ return (
79
+ <>
80
+ <MobileNavigationHeader logo={mobileLogo || logo}>
81
+ <aside className="flex h-full max-w-full flex-col justify-between overflow-auto border-r border-secondary bg-primary pt-4 lg:pt-6">
82
+ <div className="flex flex-col gap-5 px-4 lg:px-5">
83
+ {logo || <UntitledLogo className="h-8" />}
84
+ {mobileSearchSlot === undefined ? (
85
+ <Input shortcut size="sm" aria-label="Search" placeholder="Search" icon={SearchLg} />
86
+ ) : (
87
+ mobileSearchSlot
88
+ )}
89
+ </div>
90
+
91
+ <NavList items={items} />
92
+
93
+ {mobileFooterContent === undefined ? (
94
+ <div className="mt-auto flex flex-col gap-4 px-2 py-4 lg:px-4 lg:py-6">
95
+ <div className="flex flex-col gap-1">
96
+ <NavItemBase type="link" href="#" icon={LifeBuoy01}>
97
+ Support
98
+ </NavItemBase>
99
+ <NavItemBase
100
+ type="link"
101
+ href="#"
102
+ icon={Settings01}
103
+ badge={
104
+ <BadgeWithDot color="success" type="modern" size="sm">
105
+ Online
106
+ </BadgeWithDot>
107
+ }
108
+ >
109
+ Settings
110
+ </NavItemBase>
111
+ <NavItemBase type="link" href="https://www.untitledui.com/" icon={Settings01}>
112
+ Open in browser
113
+ </NavItemBase>
114
+ </div>
115
+
116
+ <NavAccountCard />
117
+ </div>
118
+ ) : (
119
+ mobileFooterContent
120
+ )}
121
+ </aside>
122
+ </MobileNavigationHeader>
123
+
124
+ <header className="max-lg:hidden">
125
+ <section
126
+ className={cx(
127
+ "flex h-16 w-full items-center justify-center bg-primary md:h-18",
128
+ (!hideBorder || showSecondaryNav) && "border-b border-secondary",
129
+ )}
130
+ >
131
+ <div className="flex w-full max-w-container justify-between pr-3 pl-4 md:px-8">
132
+ <div className="flex flex-1 items-center gap-4">
133
+ {logo || (
134
+ <a
135
+ aria-label="Go to homepage"
136
+ href="/"
137
+ className="rounded-xs outline-focus-ring focus-visible:outline-2 focus-visible:outline-offset-2"
138
+ >
139
+ <UntitledLogo className="h-8" />
140
+ </a>
141
+ )}
142
+
143
+ <nav>
144
+ <ul className="flex items-center gap-0.5">
145
+ {items.map((item) => (
146
+ <li key={item.label} className="py-0.5">
147
+ <NavItemBase icon={item.icon} href={item.href} current={item.current} badge={item.badge} type="link">
148
+ {item.label}
149
+ </NavItemBase>
150
+ </li>
151
+ ))}
152
+ </ul>
153
+ </nav>
154
+ </div>
155
+
156
+ <div className="flex items-center gap-3">
157
+ {trailingContent}
158
+
159
+ {showDefaultUtilityButtons && (
160
+ <div className="flex gap-0.5">
161
+ <NavItemButton
162
+ current={activeUrl === "/settings-01"}
163
+ size="md"
164
+ icon={Settings01}
165
+ label="Settings"
166
+ href="/settings-01"
167
+ tooltipPlacement="bottom"
168
+ />
169
+ <NavItemButton
170
+ current={activeUrl === "/notifications-01"}
171
+ size="md"
172
+ icon={Bell01}
173
+ label="Notifications"
174
+ href="/notifications-01"
175
+ tooltipPlacement="bottom"
176
+ />
177
+ </div>
178
+ )}
179
+
180
+ {avatarDropdown ||
181
+ (showAvatarDropdown && (
182
+ <DialogTrigger>
183
+ <AriaButton
184
+ className={({ isPressed, isFocused }) =>
185
+ cx(
186
+ "group relative inline-flex cursor-pointer",
187
+ (isPressed || isFocused) && "rounded-full outline-2 outline-offset-2 outline-focus-ring",
188
+ )
189
+ }
190
+ >
191
+ <Avatar alt="Olivia Rhye" src="https://www.untitledui.com/images/avatars/olivia-rhye?bg=%23E0E0E0" size="md" />
192
+ </AriaButton>
193
+ <Popover
194
+ placement="bottom right"
195
+ offset={8}
196
+ className={({ isEntering, isExiting }) =>
197
+ cx(
198
+ "will-change-transform",
199
+ isEntering &&
200
+ "duration-300 ease-out animate-in fade-in placement-right:slide-in-from-left-2 placement-top:slide-in-from-bottom-2 placement-bottom:slide-in-from-top-2",
201
+ isExiting &&
202
+ "duration-150 ease-in animate-out fade-out placement-right:slide-out-to-left-2 placement-top:slide-out-to-bottom-2 placement-bottom:slide-out-to-top-2",
203
+ )
204
+ }
205
+ >
206
+ <NavAccountMenu />
207
+ </Popover>
208
+ </DialogTrigger>
209
+ ))}
210
+ </div>
211
+ </div>
212
+ </section>
213
+
214
+ {showSecondaryNav && (
215
+ <section className={cx("flex h-16 w-full items-center justify-center bg-primary", !hideBorder && "border-b border-secondary")}>
216
+ <div className="flex w-full max-w-container items-center justify-between gap-8 px-8">
217
+ <nav>
218
+ <ul className="flex items-center gap-0.5">
219
+ {activeSubNavItems.map((item) => (
220
+ <li key={item.label} className="py-0.5">
221
+ <NavItemBase icon={item.icon} href={item.href} current={item.current} badge={item.badge} type="link">
222
+ {item.label}
223
+ </NavItemBase>
224
+ </li>
225
+ ))}
226
+ </ul>
227
+ </nav>
228
+
229
+ {secondarySearchSlot === undefined ? (
230
+ <Input shortcut aria-label="Search" placeholder="Search" icon={SearchLg} size="sm" className="max-w-xs" />
231
+ ) : (
232
+ secondarySearchSlot
233
+ )}
234
+ </div>
235
+ </section>
236
+ )}
237
+ </header>
238
+ </>
239
+ );
240
+ };