@campfire-interactive/shell-header 0.6.5 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -44,6 +44,45 @@ interface CurrencyOption {
44
44
  /** Human-readable label shown in the dropdown, e.g. "US Dollar", "Euro". */
45
45
  label: string;
46
46
  }
47
+ /**
48
+ * Build/deploy metadata for one side of the stack (webapp or API).
49
+ *
50
+ * `rolloutDate` is optional: the webapp side always has one (written
51
+ * by each deploy step to `rollout.json`); the backend side currently
52
+ * does not (the Lambda env-var update needed to inject one is a known
53
+ * footgun and isn't worth the risk for "when was this last deployed").
54
+ * The modal conditionally renders the "Deployed" row when present.
55
+ */
56
+ interface VersionInfo {
57
+ /** Short git SHA of the commit the build came from, e.g. "a4b1c8d". */
58
+ revisionId: string;
59
+ /** ISO 8601 commit date of that SHA. */
60
+ revisionDate: string;
61
+ /**
62
+ * ISO 8601 timestamp of when this artifact was deployed to the current
63
+ * environment. Written separately from the build artifact so promotions
64
+ * (e.g. dev → prod) reflect the destination deploy time, not the build time.
65
+ */
66
+ rolloutDate?: string;
67
+ }
68
+ /**
69
+ * Build/deploy metadata surfaced by the hidden About modal (Ctrl+Alt+A).
70
+ * All fields are host-supplied; the package never fetches anything itself.
71
+ *
72
+ * `webapp` is always shown; `api` is optional and renders as a second
73
+ * section when present. This lets apps adopt the webapp side before
74
+ * their API has the matching `/v1/version` endpoint wired up.
75
+ */
76
+ interface AboutInfo {
77
+ /** Display name of the app, e.g. "OMSF". */
78
+ productTitle: string;
79
+ /** Environment label, e.g. "dev", "prod", "pr-42". */
80
+ environment: string;
81
+ /** Webapp build + deploy metadata (always rendered). */
82
+ webapp: VersionInfo;
83
+ /** API build + deploy metadata (rendered as a second section when present). */
84
+ api?: VersionInfo;
85
+ }
47
86
  /**
48
87
  * Subset of the platform-notifications `Notification` shape that the bell UI
49
88
  * actually renders. Hosts typically map their fetched items (e.g., from
@@ -147,13 +186,20 @@ interface ShellHeaderProps {
147
186
  * endpoint) and for propagating it through the rest of the UI.
148
187
  */
149
188
  onCurrencyChange?: (currency: string) => void | Promise<void>;
189
+ /**
190
+ * Optional build/deploy metadata. When provided, enables a hidden
191
+ * Ctrl+Alt+A (Cmd+Opt+A on Mac) shortcut that opens an About modal
192
+ * showing this metadata with a copy-to-clipboard button. Omitting this
193
+ * prop disables the shortcut and renders nothing extra.
194
+ */
195
+ about?: AboutInfo;
150
196
  /** Fixed width for the app brand area (e.g., to align with a sidebar below). */
151
197
  brandWidth?: number;
152
198
  /** Optional content in the left/center area (filters, search, breadcrumbs, etc.) */
153
199
  children?: React.ReactNode;
154
200
  }
155
201
 
156
- declare function ShellHeader({ appId, user, authorizedApps, currentTenantRole, notificationCount, onNotificationClick, notifications, onMarkRead, onMarkAllRead, onNotificationItemClick, onLogout, locale, supportedLocales, onLocaleChange, currency, supportedCurrencies, onCurrencyChange, tenant, tenants, onTenantSwitch, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
202
+ declare function ShellHeader({ appId, user, authorizedApps, currentTenantRole, notificationCount, onNotificationClick, notifications, onMarkRead, onMarkAllRead, onNotificationItemClick, onLogout, locale, supportedLocales, onLocaleChange, currency, supportedCurrencies, onCurrencyChange, tenant, tenants, onTenantSwitch, about, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
157
203
 
158
204
  interface LocaleSwitcherProps {
159
205
  currentLocale: string;
@@ -171,4 +217,4 @@ declare const appCatalog: AppDefinition[];
171
217
  */
172
218
  declare function getAppUrl(app: AppDefinition): string;
173
219
 
174
- export { type AppDefinition, type LocaleOption, LocaleSwitcher, type NotificationItem, ShellHeader, type ShellHeaderProps, type ShellUser, appCatalog, getAppUrl };
220
+ export { type AboutInfo, type AppDefinition, type CurrencyOption, type LocaleOption, LocaleSwitcher, type NotificationItem, ShellHeader, type ShellHeaderProps, type ShellUser, type VersionInfo, appCatalog, getAppUrl };
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ function styleInject(css, { insertAt } = {}) {
24
24
  }
25
25
 
26
26
  // src/styles.css
27
- styleInject(".cfi-sh-header {\n display: flex;\n align-items: center;\n height: var(--cfi-shell-header-height, 48px);\n padding: 0 var(--cfi-spacing-md, 1rem);\n background: white;\n color: var(--cfi-color-gray-900, #111827);\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n position: relative;\n z-index: 1000;\n}\n.cfi-sh-left {\n display: flex;\n align-items: center;\n flex: 1;\n gap: var(--cfi-spacing-md, 1rem);\n overflow: hidden;\n}\n.cfi-sh-app-brand {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-badge {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: white;\n font-size: 14px;\n font-weight: 700;\n font-family: inherit;\n border-radius: var(--cfi-radius-md, 0.375rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-title {\n font-weight: 600;\n font-size: var(--cfi-font-size-base, 1rem);\n color: var(--cfi-color-gray-900, #111827);\n white-space: nowrap;\n}\n.cfi-sh-right {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n flex-shrink: 0;\n}\n.cfi-sh-icon-btn {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: transparent;\n border: none;\n border-radius: 50%;\n color: var(--cfi-color-gray-600, #4b5563);\n cursor: pointer;\n transition: background 150ms;\n}\n.cfi-sh-icon-btn:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--cfi-color-error, #ef4444);\n color: white;\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n border-radius: 99px;\n}\n.cfi-sh-app-switcher {\n position: relative;\n}\n.cfi-sh-app-grid {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: var(--cfi-spacing-xs, 0.25rem);\n padding: var(--cfi-spacing-sm, 0.5rem);\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n min-width: 280px;\n}\n.cfi-sh-app-grid-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-xs, 0.25rem);\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-700, #374151);\n text-decoration: none;\n cursor: pointer;\n transition: background 100ms;\n font-family: inherit;\n}\n.cfi-sh-app-grid-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-app-grid-item-active {\n background: var(--cfi-color-primary-50, #fff7ed);\n color: var(--cfi-color-primary-700, #c2410c);\n}\n.cfi-sh-app-grid-item-active:hover {\n background: var(--cfi-color-primary-100, #ffedd5);\n}\n.cfi-sh-app-grid-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n}\n.cfi-sh-app-grid-label {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n text-align: center;\n line-height: 1.2;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-sh-user-menu {\n position: relative;\n}\n.cfi-sh-avatar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: var(--cfi-color-primary-600, #ea580c);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: opacity 150ms;\n}\n.cfi-sh-avatar-btn:hover {\n opacity: 0.85;\n}\n.cfi-sh-avatar-img {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n object-fit: cover;\n}\n.cfi-sh-avatar-initials {\n color: white;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n font-family: inherit;\n}\n.cfi-sh-user-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n min-width: 200px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n}\n.cfi-sh-user-header {\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n display: flex;\n flex-direction: column;\n}\n.cfi-sh-user-name {\n font-weight: 500;\n color: var(--cfi-color-gray-900, #111827);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-user-email {\n color: var(--cfi-color-gray-500, #6b7280);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n}\n.cfi-sh-divider {\n height: 1px;\n background: var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-menu-item {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n width: 100%;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n background: none;\n border: none;\n color: var(--cfi-color-gray-700, #374151);\n cursor: pointer;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-menu-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-menu-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.cfi-sh-locale-switcher {\n position: relative;\n}\n.cfi-sh-locale-btn {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n height: 32px;\n padding: 0 var(--cfi-spacing-sm, 0.5rem);\n background: transparent;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-700, #374151);\n cursor: pointer;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-locale-btn:hover:not(:disabled) {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-locale-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.cfi-sh-locale-label {\n letter-spacing: 0.02em;\n}\n.cfi-sh-locale-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n min-width: 180px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n padding: var(--cfi-spacing-xs, 0.25rem) 0;\n}\n.cfi-sh-locale-dropdown .cfi-sh-menu-item {\n justify-content: space-between;\n}\n.cfi-sh-locale-item-active {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-locale-item-label {\n flex: 1;\n text-align: left;\n}\n.cfi-sh-locale-item-code {\n color: var(--cfi-color-gray-400, #9ca3af);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n.cfi-sh-locale-row {\n justify-content: flex-start;\n}\n.cfi-sh-locale-row-label {\n flex: 1;\n text-align: left;\n}\n.cfi-sh-locale-row-current {\n color: var(--cfi-color-gray-500, #6b7280);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n margin-right: var(--cfi-spacing-xs, 0.25rem);\n}\n.cfi-sh-locale-chevron {\n transition: transform 150ms ease;\n flex-shrink: 0;\n}\n.cfi-sh-locale-chevron-open {\n transform: rotate(180deg);\n}\n.cfi-sh-locale-sublist {\n border-top: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-sh-locale-sub-item {\n padding-left: calc(var(--cfi-spacing-md, 1rem) + var(--cfi-spacing-md, 1rem));\n justify-content: space-between;\n}\n.cfi-sh-tenant-static {\n cursor: default;\n pointer-events: none;\n}\n.cfi-sh-tenant-check {\n color: var(--cfi-color-violet-600, #7c3aed);\n}\n.cfi-sh-notif {\n position: relative;\n}\n.cfi-sh-notif-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: 360px;\n max-height: 480px;\n display: flex;\n flex-direction: column;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n overflow: hidden;\n}\n.cfi-sh-notif-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n flex-shrink: 0;\n}\n.cfi-sh-notif-title {\n font-weight: 600;\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-sh-notif-mark-all {\n background: none;\n border: none;\n color: var(--cfi-color-primary-600, #ea580c);\n cursor: pointer;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-family: inherit;\n padding: 0;\n}\n.cfi-sh-notif-mark-all:hover {\n text-decoration: underline;\n}\n.cfi-sh-notif-list {\n overflow-y: auto;\n flex: 1;\n}\n.cfi-sh-notif-empty {\n padding: var(--cfi-spacing-lg, 1.5rem) var(--cfi-spacing-md, 1rem);\n color: var(--cfi-color-gray-500, #6b7280);\n text-align: center;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-notif-item {\n display: flex;\n align-items: flex-start;\n gap: var(--cfi-spacing-sm, 0.5rem);\n width: 100%;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n background: none;\n border: none;\n border-bottom: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n text-align: left;\n cursor: pointer;\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-notif-item:hover {\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-sh-notif-item:last-child {\n border-bottom: none;\n}\n.cfi-sh-notif-dot {\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 6px;\n background: var(--cfi-color-primary-600, #ea580c);\n border-radius: 50%;\n}\n.cfi-sh-notif-dot-placeholder {\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 6px;\n}\n.cfi-sh-notif-content {\n flex: 1;\n min-width: 0;\n}\n.cfi-sh-notif-item-title {\n font-weight: 500;\n color: var(--cfi-color-gray-900, #111827);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n margin-bottom: 2px;\n}\n.cfi-sh-notif-item-unread .cfi-sh-notif-item-title {\n font-weight: 600;\n}\n.cfi-sh-notif-item-body {\n color: var(--cfi-color-gray-600, #4b5563);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.cfi-sh-notif-item-time {\n color: var(--cfi-color-gray-400, #9ca3af);\n font-size: 11px;\n margin-top: 4px;\n}\n");
27
+ styleInject(".cfi-sh-header {\n display: flex;\n align-items: center;\n height: var(--cfi-shell-header-height, 48px);\n padding: 0 var(--cfi-spacing-md, 1rem);\n background: white;\n color: var(--cfi-color-gray-900, #111827);\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n position: relative;\n z-index: 1000;\n}\n.cfi-sh-left {\n display: flex;\n align-items: center;\n flex: 1;\n gap: var(--cfi-spacing-md, 1rem);\n overflow: hidden;\n}\n.cfi-sh-app-brand {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-badge {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: white;\n font-size: 14px;\n font-weight: 700;\n font-family: inherit;\n border-radius: var(--cfi-radius-md, 0.375rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-title {\n font-weight: 600;\n font-size: var(--cfi-font-size-base, 1rem);\n color: var(--cfi-color-gray-900, #111827);\n white-space: nowrap;\n}\n.cfi-sh-right {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n flex-shrink: 0;\n}\n.cfi-sh-icon-btn {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: transparent;\n border: none;\n border-radius: 50%;\n color: var(--cfi-color-gray-600, #4b5563);\n cursor: pointer;\n transition: background 150ms;\n}\n.cfi-sh-icon-btn:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--cfi-color-error, #ef4444);\n color: white;\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n border-radius: 99px;\n}\n.cfi-sh-app-switcher {\n position: relative;\n}\n.cfi-sh-app-grid {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: var(--cfi-spacing-xs, 0.25rem);\n padding: var(--cfi-spacing-sm, 0.5rem);\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n min-width: 280px;\n}\n.cfi-sh-app-grid-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-xs, 0.25rem);\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-700, #374151);\n text-decoration: none;\n cursor: pointer;\n transition: background 100ms;\n font-family: inherit;\n}\n.cfi-sh-app-grid-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-app-grid-item-active {\n background: var(--cfi-color-primary-50, #fff7ed);\n color: var(--cfi-color-primary-700, #c2410c);\n}\n.cfi-sh-app-grid-item-active:hover {\n background: var(--cfi-color-primary-100, #ffedd5);\n}\n.cfi-sh-app-grid-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n}\n.cfi-sh-app-grid-label {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n text-align: center;\n line-height: 1.2;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-sh-user-menu {\n position: relative;\n}\n.cfi-sh-avatar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: var(--cfi-color-primary-600, #ea580c);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: opacity 150ms;\n}\n.cfi-sh-avatar-btn:hover {\n opacity: 0.85;\n}\n.cfi-sh-avatar-img {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n object-fit: cover;\n}\n.cfi-sh-avatar-initials {\n color: white;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n font-family: inherit;\n}\n.cfi-sh-user-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n min-width: 200px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n}\n.cfi-sh-user-header {\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n display: flex;\n flex-direction: column;\n}\n.cfi-sh-user-name {\n font-weight: 500;\n color: var(--cfi-color-gray-900, #111827);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-user-email {\n color: var(--cfi-color-gray-500, #6b7280);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n}\n.cfi-sh-divider {\n height: 1px;\n background: var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-menu-item {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n width: 100%;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n background: none;\n border: none;\n color: var(--cfi-color-gray-700, #374151);\n cursor: pointer;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-menu-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-menu-item:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.cfi-sh-locale-switcher {\n position: relative;\n}\n.cfi-sh-locale-btn {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n height: 32px;\n padding: 0 var(--cfi-spacing-sm, 0.5rem);\n background: transparent;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-700, #374151);\n cursor: pointer;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-locale-btn:hover:not(:disabled) {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-locale-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n.cfi-sh-locale-label {\n letter-spacing: 0.02em;\n}\n.cfi-sh-locale-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n min-width: 180px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n padding: var(--cfi-spacing-xs, 0.25rem) 0;\n}\n.cfi-sh-locale-dropdown .cfi-sh-menu-item {\n justify-content: space-between;\n}\n.cfi-sh-locale-item-active {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-locale-item-label {\n flex: 1;\n text-align: left;\n}\n.cfi-sh-locale-item-code {\n color: var(--cfi-color-gray-400, #9ca3af);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n letter-spacing: 0.02em;\n}\n.cfi-sh-locale-row {\n justify-content: flex-start;\n}\n.cfi-sh-locale-row-label {\n flex: 1;\n text-align: left;\n}\n.cfi-sh-locale-row-current {\n color: var(--cfi-color-gray-500, #6b7280);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n margin-right: var(--cfi-spacing-xs, 0.25rem);\n}\n.cfi-sh-locale-chevron {\n transition: transform 150ms ease;\n flex-shrink: 0;\n}\n.cfi-sh-locale-chevron-open {\n transform: rotate(180deg);\n}\n.cfi-sh-locale-sublist {\n border-top: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-sh-locale-sub-item {\n padding-left: calc(var(--cfi-spacing-md, 1rem) + var(--cfi-spacing-md, 1rem));\n justify-content: space-between;\n}\n.cfi-sh-tenant-static {\n cursor: default;\n pointer-events: none;\n}\n.cfi-sh-tenant-check {\n color: var(--cfi-color-violet-600, #7c3aed);\n}\n.cfi-sh-notif {\n position: relative;\n}\n.cfi-sh-notif-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: 360px;\n max-height: 480px;\n display: flex;\n flex-direction: column;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n overflow: hidden;\n}\n.cfi-sh-notif-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n flex-shrink: 0;\n}\n.cfi-sh-notif-title {\n font-weight: 600;\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-sh-notif-mark-all {\n background: none;\n border: none;\n color: var(--cfi-color-primary-600, #ea580c);\n cursor: pointer;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-family: inherit;\n padding: 0;\n}\n.cfi-sh-notif-mark-all:hover {\n text-decoration: underline;\n}\n.cfi-sh-notif-list {\n overflow-y: auto;\n flex: 1;\n}\n.cfi-sh-notif-empty {\n padding: var(--cfi-spacing-lg, 1.5rem) var(--cfi-spacing-md, 1rem);\n color: var(--cfi-color-gray-500, #6b7280);\n text-align: center;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-notif-item {\n display: flex;\n align-items: flex-start;\n gap: var(--cfi-spacing-sm, 0.5rem);\n width: 100%;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n background: none;\n border: none;\n border-bottom: 1px solid var(--cfi-color-gray-100, #f3f4f6);\n text-align: left;\n cursor: pointer;\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-notif-item:hover {\n background: var(--cfi-color-gray-50, #f9fafb);\n}\n.cfi-sh-notif-item:last-child {\n border-bottom: none;\n}\n.cfi-sh-notif-dot {\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 6px;\n background: var(--cfi-color-primary-600, #ea580c);\n border-radius: 50%;\n}\n.cfi-sh-notif-dot-placeholder {\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 6px;\n}\n.cfi-sh-notif-content {\n flex: 1;\n min-width: 0;\n}\n.cfi-sh-notif-item-title {\n font-weight: 500;\n color: var(--cfi-color-gray-900, #111827);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n margin-bottom: 2px;\n}\n.cfi-sh-notif-item-unread .cfi-sh-notif-item-title {\n font-weight: 600;\n}\n.cfi-sh-notif-item-body {\n color: var(--cfi-color-gray-600, #4b5563);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n.cfi-sh-notif-item-time {\n color: var(--cfi-color-gray-400, #9ca3af);\n font-size: 11px;\n margin-top: 4px;\n}\n.cfi-sh-about-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.4);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1100;\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n}\n.cfi-sh-about-card {\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);\n min-width: 360px;\n max-width: 500px;\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-sh-about-header {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n padding: var(--cfi-spacing-md, 1rem);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-about-title {\n font-weight: 600;\n font-size: var(--cfi-font-size-lg, 1.125rem);\n flex: 1;\n}\n.cfi-sh-about-env {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n background: var(--cfi-color-gray-100, #f3f4f6);\n color: var(--cfi-color-gray-700, #374151);\n padding: 2px 8px;\n border-radius: var(--cfi-radius-sm, 0.25rem);\n font-weight: 600;\n}\n.cfi-sh-about-close {\n background: none;\n border: none;\n font-size: 1.5rem;\n line-height: 1;\n cursor: pointer;\n color: var(--cfi-color-gray-500, #6b7280);\n padding: 0 4px;\n font-family: inherit;\n}\n.cfi-sh-about-close:hover {\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-sh-about-body {\n padding: var(--cfi-spacing-md, 1rem);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-md, 1rem);\n}\n.cfi-sh-about-section-title {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n font-weight: 600;\n color: var(--cfi-color-gray-500, #6b7280);\n margin-bottom: var(--cfi-spacing-xs, 0.25rem);\n}\n.cfi-sh-about-list {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: var(--cfi-spacing-xs, 0.25rem) var(--cfi-spacing-md, 1rem);\n margin: 0;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-about-list dt {\n color: var(--cfi-color-gray-600, #4b5563);\n font-weight: 500;\n}\n.cfi-sh-about-list dd {\n margin: 0;\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-sh-about-list code {\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Consolas,\n monospace;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n background: var(--cfi-color-gray-100, #f3f4f6);\n padding: 1px 6px;\n border-radius: var(--cfi-radius-sm, 0.25rem);\n}\n.cfi-sh-about-date {\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-sh-about-footer {\n display: flex;\n justify-content: flex-end;\n padding: var(--cfi-spacing-md, 1rem);\n border-top: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-about-copy {\n background: var(--cfi-color-gray-100, #f3f4f6);\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n color: var(--cfi-color-gray-900, #111827);\n padding: 6px 12px;\n border-radius: var(--cfi-radius-md, 0.375rem);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-weight: 500;\n cursor: pointer;\n font-family: inherit;\n transition: background 150ms;\n}\n.cfi-sh-about-copy:hover {\n background: var(--cfi-color-gray-200, #e5e7eb);\n}\n");
28
28
 
29
29
  // src/appCatalog.ts
30
30
  var appCatalog = [
@@ -496,8 +496,149 @@ function UserMenu({
496
496
  ] });
497
497
  }
498
498
 
499
+ // src/AboutModal.tsx
500
+ import { useEffect as useEffect4, useState as useState4 } from "react";
501
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
502
+ function AboutModal({ about, onClose }) {
503
+ const [copied, setCopied] = useState4(false);
504
+ useEffect4(() => {
505
+ function handleEsc(e) {
506
+ if (e.key === "Escape") onClose();
507
+ }
508
+ document.addEventListener("keydown", handleEsc);
509
+ return () => document.removeEventListener("keydown", handleEsc);
510
+ }, [onClose]);
511
+ async function handleCopy() {
512
+ const text = formatClipboardPayload(about);
513
+ try {
514
+ await navigator.clipboard.writeText(text);
515
+ setCopied(true);
516
+ window.setTimeout(() => setCopied(false), 2e3);
517
+ } catch {
518
+ }
519
+ }
520
+ const hasApi = about.api !== void 0;
521
+ return /* @__PURE__ */ jsx5(
522
+ "div",
523
+ {
524
+ className: "cfi-sh-about-overlay",
525
+ role: "dialog",
526
+ "aria-modal": "true",
527
+ "aria-label": "About this app",
528
+ onClick: (e) => {
529
+ if (e.target === e.currentTarget) onClose();
530
+ },
531
+ children: /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-about-card", children: [
532
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-about-header", children: [
533
+ /* @__PURE__ */ jsx5("span", { className: "cfi-sh-about-title", children: about.productTitle }),
534
+ /* @__PURE__ */ jsx5("span", { className: "cfi-sh-about-env", children: about.environment }),
535
+ /* @__PURE__ */ jsx5(
536
+ "button",
537
+ {
538
+ className: "cfi-sh-about-close",
539
+ type: "button",
540
+ onClick: onClose,
541
+ "aria-label": "Close",
542
+ children: "\xD7"
543
+ }
544
+ )
545
+ ] }),
546
+ /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-about-body", children: [
547
+ /* @__PURE__ */ jsx5(VersionSection, { title: hasApi ? "Webapp" : null, version: about.webapp }),
548
+ about.api && /* @__PURE__ */ jsx5(VersionSection, { title: "API", version: about.api })
549
+ ] }),
550
+ /* @__PURE__ */ jsx5("div", { className: "cfi-sh-about-footer", children: /* @__PURE__ */ jsx5(
551
+ "button",
552
+ {
553
+ className: "cfi-sh-about-copy",
554
+ type: "button",
555
+ onClick: handleCopy,
556
+ children: copied ? "Copied!" : "Copy"
557
+ }
558
+ ) })
559
+ ] })
560
+ }
561
+ );
562
+ }
563
+ function VersionSection({ title, version }) {
564
+ return /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-about-section", children: [
565
+ title && /* @__PURE__ */ jsx5("div", { className: "cfi-sh-about-section-title", children: title }),
566
+ /* @__PURE__ */ jsxs5("dl", { className: "cfi-sh-about-list", children: [
567
+ /* @__PURE__ */ jsx5("dt", { children: "Revision" }),
568
+ /* @__PURE__ */ jsxs5("dd", { children: [
569
+ /* @__PURE__ */ jsx5("code", { children: version.revisionId }),
570
+ /* @__PURE__ */ jsxs5("span", { className: "cfi-sh-about-date", children: [
571
+ " (",
572
+ formatDate(version.revisionDate),
573
+ ")"
574
+ ] })
575
+ ] }),
576
+ version.rolloutDate && /* @__PURE__ */ jsxs5(Fragment2, { children: [
577
+ /* @__PURE__ */ jsx5("dt", { children: "Deployed" }),
578
+ /* @__PURE__ */ jsx5("dd", { children: formatDateTime(version.rolloutDate) })
579
+ ] })
580
+ ] })
581
+ ] });
582
+ }
583
+ function formatClipboardPayload(about) {
584
+ const header = `**${about.productTitle}** (${about.environment})`;
585
+ const webappLines = formatLines(about.webapp);
586
+ if (!about.api) {
587
+ return [header, ...webappLines].join("\n");
588
+ }
589
+ const apiLines = formatLines(about.api);
590
+ return [
591
+ header,
592
+ "",
593
+ "Webapp:",
594
+ ...webappLines,
595
+ "",
596
+ "API:",
597
+ ...apiLines
598
+ ].join("\n");
599
+ }
600
+ function formatLines(v) {
601
+ const lines = [`Revision: ${v.revisionId} (${formatDate(v.revisionDate)})`];
602
+ if (v.rolloutDate) lines.push(`Deployed: ${formatDateTime(v.rolloutDate)}`);
603
+ return lines;
604
+ }
605
+ function formatDate(iso) {
606
+ const d = new Date(iso);
607
+ if (Number.isNaN(d.getTime())) return iso;
608
+ return d.toISOString().slice(0, 10);
609
+ }
610
+ function formatDateTime(iso) {
611
+ const d = new Date(iso);
612
+ if (Number.isNaN(d.getTime())) return iso;
613
+ return d.toISOString().replace("T", " ").slice(0, 19) + " UTC";
614
+ }
615
+
616
+ // src/useAboutShortcut.ts
617
+ import { useEffect as useEffect5, useState as useState5 } from "react";
618
+ function useAboutShortcut(enabled) {
619
+ const [isOpen, setIsOpen] = useState5(false);
620
+ useEffect5(() => {
621
+ if (!enabled) return;
622
+ function handleKeyDown(e) {
623
+ const platformMod = e.ctrlKey || e.metaKey;
624
+ if (!platformMod || !e.altKey || e.shiftKey) return;
625
+ if (e.key.toLowerCase() !== "a") return;
626
+ const target = e.target;
627
+ if (target) {
628
+ const tag = target.tagName;
629
+ if (tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable) return;
630
+ }
631
+ e.preventDefault();
632
+ setIsOpen((open) => !open);
633
+ }
634
+ document.addEventListener("keydown", handleKeyDown);
635
+ return () => document.removeEventListener("keydown", handleKeyDown);
636
+ }, [enabled]);
637
+ return [isOpen, setIsOpen];
638
+ }
639
+
499
640
  // src/ShellHeader.tsx
500
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
641
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
501
642
  function ShellHeader({
502
643
  appId,
503
644
  user,
@@ -519,61 +660,66 @@ function ShellHeader({
519
660
  tenant,
520
661
  tenants,
521
662
  onTenantSwitch,
663
+ about,
522
664
  brandWidth,
523
665
  children
524
666
  }) {
525
667
  const currentApp = appCatalog.find((a) => a.id === appId);
668
+ const [aboutOpen, setAboutOpen] = useAboutShortcut(about !== void 0);
526
669
  const brandStyle = brandWidth ? { width: `${brandWidth}px`, flexShrink: 0, boxSizing: "border-box" } : void 0;
527
- return /* @__PURE__ */ jsxs5("header", { className: "cfi-sh-header", children: [
528
- /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-left", children: [
529
- /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-app-brand", style: brandStyle, children: [
530
- currentApp && /* @__PURE__ */ jsx5("span", { className: "cfi-sh-app-badge", style: { background: currentApp.color }, children: currentApp.letter }),
531
- /* @__PURE__ */ jsx5("span", { className: "cfi-sh-app-title", children: currentApp?.name || appId })
670
+ return /* @__PURE__ */ jsxs6(Fragment3, { children: [
671
+ /* @__PURE__ */ jsxs6("header", { className: "cfi-sh-header", children: [
672
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-left", children: [
673
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-app-brand", style: brandStyle, children: [
674
+ currentApp && /* @__PURE__ */ jsx6("span", { className: "cfi-sh-app-badge", style: { background: currentApp.color }, children: currentApp.letter }),
675
+ /* @__PURE__ */ jsx6("span", { className: "cfi-sh-app-title", children: currentApp?.name || appId })
676
+ ] }),
677
+ children
532
678
  ] }),
533
- children
679
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-right", children: [
680
+ /* @__PURE__ */ jsx6(
681
+ NotificationBell,
682
+ {
683
+ count: notificationCount,
684
+ onClick: onNotificationClick,
685
+ items: notifications,
686
+ onMarkRead,
687
+ onMarkAllRead,
688
+ onItemClick: onNotificationItemClick
689
+ }
690
+ ),
691
+ /* @__PURE__ */ jsx6(AppSwitcher, { currentAppId: appId, authorizedApps, currentTenantRole }),
692
+ /* @__PURE__ */ jsx6(
693
+ UserMenu,
694
+ {
695
+ user,
696
+ onLogout,
697
+ color: currentApp?.color,
698
+ locale,
699
+ supportedLocales,
700
+ onLocaleChange,
701
+ currency,
702
+ supportedCurrencies,
703
+ onCurrencyChange,
704
+ tenant,
705
+ tenants,
706
+ onTenantSwitch
707
+ }
708
+ )
709
+ ] })
534
710
  ] }),
535
- /* @__PURE__ */ jsxs5("div", { className: "cfi-sh-right", children: [
536
- /* @__PURE__ */ jsx5(
537
- NotificationBell,
538
- {
539
- count: notificationCount,
540
- onClick: onNotificationClick,
541
- items: notifications,
542
- onMarkRead,
543
- onMarkAllRead,
544
- onItemClick: onNotificationItemClick
545
- }
546
- ),
547
- /* @__PURE__ */ jsx5(AppSwitcher, { currentAppId: appId, authorizedApps, currentTenantRole }),
548
- /* @__PURE__ */ jsx5(
549
- UserMenu,
550
- {
551
- user,
552
- onLogout,
553
- color: currentApp?.color,
554
- locale,
555
- supportedLocales,
556
- onLocaleChange,
557
- currency,
558
- supportedCurrencies,
559
- onCurrencyChange,
560
- tenant,
561
- tenants,
562
- onTenantSwitch
563
- }
564
- )
565
- ] })
711
+ about && aboutOpen && /* @__PURE__ */ jsx6(AboutModal, { about, onClose: () => setAboutOpen(false) })
566
712
  ] });
567
713
  }
568
714
 
569
715
  // src/LocaleSwitcher.tsx
570
- import { useState as useState4, useRef as useRef4, useEffect as useEffect4 } from "react";
571
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
716
+ import { useState as useState6, useRef as useRef4, useEffect as useEffect6 } from "react";
717
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
572
718
  function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
573
- const [open, setOpen] = useState4(false);
574
- const [updating, setUpdating] = useState4(false);
719
+ const [open, setOpen] = useState6(false);
720
+ const [updating, setUpdating] = useState6(false);
575
721
  const ref = useRef4(null);
576
- useEffect4(() => {
722
+ useEffect6(() => {
577
723
  function handleClickOutside(e) {
578
724
  if (ref.current && !ref.current.contains(e.target)) {
579
725
  setOpen(false);
@@ -597,8 +743,8 @@ function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
597
743
  setOpen(false);
598
744
  }
599
745
  }
600
- return /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-locale-switcher", ref, children: [
601
- /* @__PURE__ */ jsxs6(
746
+ return /* @__PURE__ */ jsxs7("div", { className: "cfi-sh-locale-switcher", ref, children: [
747
+ /* @__PURE__ */ jsxs7(
602
748
  "button",
603
749
  {
604
750
  className: "cfi-sh-locale-btn",
@@ -609,20 +755,20 @@ function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
609
755
  disabled: updating,
610
756
  title: current?.label ?? currentLocale,
611
757
  children: [
612
- /* @__PURE__ */ jsx6(Globe, { size: 16 }),
613
- /* @__PURE__ */ jsx6("span", { className: "cfi-sh-locale-label", children: buttonLabel })
758
+ /* @__PURE__ */ jsx7(Globe, { size: 16 }),
759
+ /* @__PURE__ */ jsx7("span", { className: "cfi-sh-locale-label", children: buttonLabel })
614
760
  ]
615
761
  }
616
762
  ),
617
- open && /* @__PURE__ */ jsx6("div", { className: "cfi-sh-locale-dropdown", children: supportedLocales.map((loc) => /* @__PURE__ */ jsxs6(
763
+ open && /* @__PURE__ */ jsx7("div", { className: "cfi-sh-locale-dropdown", children: supportedLocales.map((loc) => /* @__PURE__ */ jsxs7(
618
764
  "button",
619
765
  {
620
766
  className: loc.code === currentLocale ? "cfi-sh-menu-item cfi-sh-locale-item-active" : "cfi-sh-menu-item",
621
767
  onClick: () => handleSelect(loc.code),
622
768
  disabled: updating,
623
769
  children: [
624
- /* @__PURE__ */ jsx6("span", { className: "cfi-sh-locale-item-label", children: loc.label }),
625
- /* @__PURE__ */ jsx6("span", { className: "cfi-sh-locale-item-code", children: loc.code.toUpperCase() })
770
+ /* @__PURE__ */ jsx7("span", { className: "cfi-sh-locale-item-label", children: loc.label }),
771
+ /* @__PURE__ */ jsx7("span", { className: "cfi-sh-locale-item-code", children: loc.code.toUpperCase() })
626
772
  ]
627
773
  },
628
774
  loc.code
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campfire-interactive/shell-header",
3
- "version": "0.6.5",
3
+ "version": "0.8.1",
4
4
  "description": "Shared shell header with app switcher for Campfire Suite",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",