@campfire-interactive/shell-header 0.8.15 → 0.11.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.
package/dist/index.d.ts CHANGED
@@ -126,6 +126,71 @@ interface AboutInfo {
126
126
  /** API build + deploy metadata (rendered as a second section when present). */
127
127
  api?: VersionInfo;
128
128
  }
129
+ /**
130
+ * Host-supplied context stamped onto every bug report (Ctrl+Alt+B modal).
131
+ * Hosts typically derive appVersion/apiVersion from the same data they pass
132
+ * as `about`.
133
+ */
134
+ interface BugReportContext {
135
+ /** Reporting app slug, e.g. "omsf". */
136
+ appId: string;
137
+ /** Environment label, e.g. "dev". Hosts should omit the whole `bugReport`
138
+ * prop in prod until the prod-visibility story exists. */
139
+ environment: string;
140
+ /** Defaults to window.location.href at submit time. */
141
+ url?: string;
142
+ appVersion?: string;
143
+ apiVersion?: string;
144
+ /**
145
+ * URL of the suite issues list (dms webapp `/issues`). When set, the
146
+ * dialog links to it ("View known issues") so reporters can check whether
147
+ * their bug is already filed. Opens in a new tab.
148
+ */
149
+ issuesUrl?: string;
150
+ }
151
+ /**
152
+ * What the modal hands to `onSubmit`. Field names (minus `screenshot`)
153
+ * mirror dms-client's CreateBugReportInput, so a host can:
154
+ *
155
+ * const { screenshot, ...input } = payload;
156
+ * const report = await dms.bugReports.create(input);
157
+ * if (screenshot) {
158
+ * await dms.attachments.upload(screenshot, {
159
+ * entityType: 'bug_report', entityId: report.id,
160
+ * name: 'screenshot.png', app: 'bug-reports',
161
+ * });
162
+ * }
163
+ */
164
+ interface BugReportPayload {
165
+ appId: string;
166
+ environment: string;
167
+ url: string;
168
+ title: string;
169
+ description: string;
170
+ appVersion?: string;
171
+ apiVersion?: string;
172
+ userAgent: string;
173
+ /** e.g. "1920x1080" (window inner size). */
174
+ viewport: string;
175
+ /** Console-error ring-buffer snapshot (installBugReportCapture). */
176
+ console: unknown[];
177
+ /** Failed-request ring-buffer snapshot. */
178
+ network: unknown[];
179
+ /** Edited PNG, or null when the reporter skipped/removed the capture. */
180
+ screenshot: Blob | null;
181
+ }
182
+ /**
183
+ * Enables the hidden Ctrl+Alt+B bug-report modal. Like `about`, the package
184
+ * stays presentational: context comes in via props, and the host owns
185
+ * submission via onSubmit (typically dms-client — see BugReportPayload).
186
+ * The host should also call installBugReportCapture() at app boot so the
187
+ * console/network ring buffers have content by the time a bug is filed.
188
+ */
189
+ interface BugReportConfig {
190
+ context: BugReportContext;
191
+ /** Rejection keeps the modal open and shows the error message. */
192
+ onSubmit: (report: BugReportPayload) => Promise<void>;
193
+ }
129
194
  /**
130
195
  * Subset of the platform-notifications `Notification` shape that the bell UI
131
196
  * actually renders. Hosts typically map their fetched items (e.g., from
@@ -242,6 +307,13 @@ interface ShellHeaderProps {
242
307
  * prop disables the shortcut and renders nothing extra.
243
308
  */
244
309
  about?: AboutInfo;
310
+ /**
311
+ * Optional bug-report wiring. When provided, enables a hidden Ctrl+Alt+B
312
+ * (Cmd+Opt+B on Mac) shortcut that opens a bug-report modal with optional
313
+ * screenshot capture. Omitting this prop disables the shortcut and renders
314
+ * nothing extra. See BugReportConfig for the host contract.
315
+ */
316
+ bugReport?: BugReportConfig;
245
317
  /**
246
318
  * When true, the header's top-left shows the campfire suite wordmark
247
319
  * instead of the current app's badge + title. Used by the /home launcher,
@@ -255,7 +327,7 @@ interface ShellHeaderProps {
255
327
  children?: React.ReactNode;
256
328
  }
257
329
 
258
- declare function ShellHeader({ appId, user, authorizedApps, currentTenantRole, notificationCount, onNotificationClick, notifications, onMarkRead, onMarkAllRead, onNotificationItemClick, onLogout, locale, supportedLocales, onLocaleChange, currency, supportedCurrencies, onCurrencyChange, tenant, tenants, onTenantSwitch, userMenuItems, about, showSuiteLogo, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
330
+ declare function ShellHeader({ appId, user, authorizedApps, currentTenantRole, notificationCount, onNotificationClick, notifications, onMarkRead, onMarkAllRead, onNotificationItemClick, onLogout, locale, supportedLocales, onLocaleChange, currency, supportedCurrencies, onCurrencyChange, tenant, tenants, onTenantSwitch, userMenuItems, about, bugReport, showSuiteLogo, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
259
331
 
260
332
  interface LocaleSwitcherProps {
261
333
  currentLocale: string;
@@ -264,6 +336,13 @@ interface LocaleSwitcherProps {
264
336
  }
265
337
  declare function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }: LocaleSwitcherProps): react_jsx_runtime.JSX.Element;
266
338
 
339
+ /**
340
+ * Install the capture hooks. Idempotent; safe to call in any environment
341
+ * (no-ops outside a browser). Call from the app entry point so the buffers
342
+ * exist before the bug does.
343
+ */
344
+ declare function installBugReportCapture(): void;
345
+
267
346
  declare const appCatalog: AppDefinition[];
268
347
  /**
269
348
  * Derive the app URL from the current hostname, optionally appending the
@@ -274,4 +353,4 @@ declare const appCatalog: AppDefinition[];
274
353
  */
275
354
  declare function getAppUrl(app: AppDefinition): string;
276
355
 
277
- export { type AboutInfo, type AppDefinition, type CurrencyOption, type LocaleOption, LocaleSwitcher, type NotificationItem, ShellHeader, type ShellHeaderProps, type ShellUser, type VersionInfo, appCatalog, getAppUrl };
356
+ export { type AboutInfo, type AppDefinition, type BugReportConfig, type BugReportContext, type BugReportPayload, type CurrencyOption, type LocaleOption, LocaleSwitcher, type NotificationItem, ShellHeader, type ShellHeaderProps, type ShellUser, type VersionInfo, appCatalog, getAppUrl, installBugReportCapture };
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-suite-logo {\n height: 22px;\n width: auto;\n display: block;\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.35;\n max-width: 80px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n white-space: normal;\n overflow: hidden;\n min-height: 2.7em;\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");
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-suite-logo {\n height: 22px;\n width: auto;\n display: block;\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.35;\n max-width: 80px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n white-space: normal;\n overflow: hidden;\n min-height: 2.7em;\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.cfi-sh-bug-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-bug-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 width: 480px;\n max-width: calc(100vw - 32px);\n color: var(--cfi-color-gray-900, #111827);\n display: flex;\n flex-direction: column;\n}\n.cfi-sh-bug-card-wide {\n width: min(1100px, calc(100vw - 64px));\n}\n.cfi-sh-bug-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-bug-title {\n font-weight: 600;\n font-size: var(--cfi-font-size-lg, 1.125rem);\n flex: 1;\n}\n.cfi-sh-bug-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-bug-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-bug-close:hover {\n color: var(--cfi-color-gray-900, #111827);\n}\n.cfi-sh-bug-body {\n padding: var(--cfi-spacing-md, 1rem);\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-sm, 0.5rem);\n}\n.cfi-sh-bug-label {\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}\n.cfi-sh-bug-input,\n.cfi-sh-bug-textarea {\n font-family: inherit;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n color: var(--cfi-color-gray-900, #111827);\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-md, 0.375rem);\n padding: 8px 10px;\n outline: none;\n}\n.cfi-sh-bug-input:focus,\n.cfi-sh-bug-textarea:focus {\n border-color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-sh-bug-textarea {\n resize: vertical;\n min-height: 72px;\n}\n.cfi-sh-bug-shot {\n display: flex;\n align-items: flex-start;\n gap: var(--cfi-spacing-sm, 0.5rem);\n flex-wrap: wrap;\n padding-top: var(--cfi-spacing-xs, 0.25rem);\n}\n.cfi-sh-bug-thumb {\n max-width: 200px;\n max-height: 120px;\n border: 1px solid var(--cfi-color-gray-300, #d1d5db);\n border-radius: var(--cfi-radius-sm, 0.25rem);\n display: block;\n}\n.cfi-sh-bug-shot-actions {\n display: flex;\n flex-direction: column;\n gap: var(--cfi-spacing-xs, 0.25rem);\n}\n.cfi-sh-bug-meta {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-sh-bug-toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--cfi-spacing-sm, 0.5rem);\n}\n.cfi-sh-bug-modes {\n display: flex;\n gap: var(--cfi-spacing-xs, 0.25rem);\n}\n.cfi-sh-bug-hint {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n color: var(--cfi-color-gray-500, #6b7280);\n}\n.cfi-sh-bug-canvas-wrap {\n overflow: auto;\n max-height: 65vh;\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n border-radius: var(--cfi-radius-sm, 0.25rem);\n background: var(--cfi-color-gray-100, #f3f4f6);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.cfi-sh-bug-canvas {\n max-width: 100%;\n max-height: 65vh;\n cursor: crosshair;\n touch-action: none;\n display: block;\n}\n.cfi-sh-bug-footer {\n display: flex;\n justify-content: flex-end;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n padding: var(--cfi-spacing-md, 1rem);\n border-top: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-bug-btn {\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-bug-btn:hover {\n background: var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-bug-btn:disabled {\n opacity: 0.5;\n cursor: default;\n}\n.cfi-sh-bug-btn-primary {\n background: var(--cfi-color-gray-900, #111827);\n border-color: var(--cfi-color-gray-900, #111827);\n color: white;\n}\n.cfi-sh-bug-btn-primary:hover:not(:disabled) {\n background: var(--cfi-color-gray-700, #374151);\n}\n.cfi-sh-bug-btn-active {\n background: var(--cfi-color-gray-900, #111827);\n border-color: var(--cfi-color-gray-900, #111827);\n color: white;\n}\n.cfi-sh-bug-error {\n color: var(--cfi-color-red-600, #dc2626);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n margin-right: auto;\n}\n.cfi-sh-bug-success {\n color: var(--cfi-color-green-600, #16a34a);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-weight: 500;\n}\n.cfi-sh-bug-issues-link {\n color: var(--cfi-color-gray-600, #4b5563);\n text-decoration: underline;\n}\n.cfi-sh-bug-issues-link:hover {\n color: var(--cfi-color-gray-900, #111827);\n}\n");
28
28
 
29
29
  // src/appCatalog.ts
30
30
  var appCatalog = [
@@ -740,11 +740,523 @@ function useAboutShortcut(enabled) {
740
740
  return [isOpen, setIsOpen];
741
741
  }
742
742
 
743
+ // src/BugReportModal.tsx
744
+ import { useCallback, useEffect as useEffect6, useRef as useRef4, useState as useState6 } from "react";
745
+
746
+ // src/captureScreenshot.ts
747
+ async function captureTabScreenshot() {
748
+ if (!navigator.mediaDevices?.getDisplayMedia) {
749
+ throw new Error("Screen capture is not supported in this browser");
750
+ }
751
+ const stream = await navigator.mediaDevices.getDisplayMedia({
752
+ video: true,
753
+ audio: false,
754
+ // Chromium hints, absent from lib.dom's DisplayMediaStreamOptions.
755
+ preferCurrentTab: true,
756
+ selfBrowserSurface: "include"
757
+ });
758
+ const video = document.createElement("video");
759
+ try {
760
+ video.srcObject = stream;
761
+ video.muted = true;
762
+ await video.play();
763
+ await new Promise(requestAnimationFrame);
764
+ await new Promise(requestAnimationFrame);
765
+ const canvas = document.createElement("canvas");
766
+ canvas.width = video.videoWidth;
767
+ canvas.height = video.videoHeight;
768
+ const ctx = canvas.getContext("2d");
769
+ if (!ctx || canvas.width === 0 || canvas.height === 0) {
770
+ throw new Error("Could not read a frame from the screen capture");
771
+ }
772
+ ctx.drawImage(video, 0, 0);
773
+ return await new Promise((resolve, reject) => {
774
+ canvas.toBlob(
775
+ (blob) => blob ? resolve(blob) : reject(new Error("Screenshot encoding failed")),
776
+ "image/png"
777
+ );
778
+ });
779
+ } finally {
780
+ video.srcObject = null;
781
+ stream.getTracks().forEach((t) => t.stop());
782
+ }
783
+ }
784
+
785
+ // src/bugReportCapture.ts
786
+ var MAX_ENTRIES = 50;
787
+ var MAX_MESSAGE_CHARS = 500;
788
+ var consoleBuffer = [];
789
+ var networkBuffer = [];
790
+ var installed = false;
791
+ function push(buffer, entry) {
792
+ buffer.push(entry);
793
+ if (buffer.length > MAX_ENTRIES) buffer.shift();
794
+ }
795
+ function formatArg(arg) {
796
+ if (typeof arg === "string") return arg;
797
+ if (arg instanceof Error) return `${arg.name}: ${arg.message}`;
798
+ try {
799
+ return JSON.stringify(arg);
800
+ } catch {
801
+ return String(arg);
802
+ }
803
+ }
804
+ function formatArgs(args) {
805
+ return args.map(formatArg).join(" ").slice(0, MAX_MESSAGE_CHARS);
806
+ }
807
+ function installBugReportCapture() {
808
+ if (installed || typeof window === "undefined") return;
809
+ installed = true;
810
+ for (const level of ["error", "warn"]) {
811
+ const original = console[level].bind(console);
812
+ console[level] = (...args) => {
813
+ push(consoleBuffer, { at: (/* @__PURE__ */ new Date()).toISOString(), level, message: formatArgs(args) });
814
+ original(...args);
815
+ };
816
+ }
817
+ window.addEventListener("error", (e) => {
818
+ push(consoleBuffer, {
819
+ at: (/* @__PURE__ */ new Date()).toISOString(),
820
+ level: "error",
821
+ message: `uncaught: ${e.message} (${e.filename ?? "?"}:${e.lineno ?? "?"})`.slice(0, MAX_MESSAGE_CHARS)
822
+ });
823
+ });
824
+ window.addEventListener("unhandledrejection", (e) => {
825
+ push(consoleBuffer, {
826
+ at: (/* @__PURE__ */ new Date()).toISOString(),
827
+ level: "error",
828
+ message: `unhandledrejection: ${formatArg(e.reason)}`.slice(0, MAX_MESSAGE_CHARS)
829
+ });
830
+ });
831
+ const originalFetch = window.fetch.bind(window);
832
+ window.fetch = async (input, init) => {
833
+ const started = performance.now();
834
+ const method = init?.method ?? (typeof Request !== "undefined" && input instanceof Request ? input.method : "GET");
835
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
836
+ try {
837
+ const res = await originalFetch(input, init);
838
+ if (!res.ok) {
839
+ push(networkBuffer, {
840
+ at: (/* @__PURE__ */ new Date()).toISOString(),
841
+ method: method.toUpperCase(),
842
+ url,
843
+ status: res.status,
844
+ durationMs: Math.round(performance.now() - started),
845
+ requestId: res.headers.get("x-request-id") ?? void 0
846
+ });
847
+ }
848
+ return res;
849
+ } catch (err) {
850
+ push(networkBuffer, {
851
+ at: (/* @__PURE__ */ new Date()).toISOString(),
852
+ method: method.toUpperCase(),
853
+ url,
854
+ status: 0,
855
+ durationMs: Math.round(performance.now() - started)
856
+ });
857
+ throw err;
858
+ }
859
+ };
860
+ }
861
+ function snapshotBugReportCapture() {
862
+ return { console: [...consoleBuffer], network: [...networkBuffer] };
863
+ }
864
+
865
+ // src/BugReportModal.tsx
866
+ import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
867
+ function normalizeRect(x0, y0, x1, y1) {
868
+ return {
869
+ x: Math.min(x0, x1),
870
+ y: Math.min(y0, y1),
871
+ w: Math.abs(x1 - x0),
872
+ h: Math.abs(y1 - y0)
873
+ };
874
+ }
875
+ function BugReportModal({ config, onClose }) {
876
+ const [view, setView] = useState6("form");
877
+ const [title, setTitle] = useState6("");
878
+ const [description, setDescription] = useState6("");
879
+ const [screenshot, setScreenshot] = useState6(null);
880
+ const [capturing, setCapturing] = useState6(false);
881
+ const [captureError, setCaptureError] = useState6(null);
882
+ const [submitState, setSubmitState] = useState6("idle");
883
+ const [submitError, setSubmitError] = useState6(null);
884
+ const workCanvasRef = useRef4(null);
885
+ const originalRef = useRef4(null);
886
+ const displayCanvasRef = useRef4(null);
887
+ const dragStartRef = useRef4(null);
888
+ const [mode, setMode] = useState6("crop");
889
+ const closeUnlessBusy = useCallback(() => {
890
+ if (submitState === "submitting" || capturing) return;
891
+ if (screenshot) URL.revokeObjectURL(screenshot.previewUrl);
892
+ onClose();
893
+ }, [submitState, capturing, screenshot, onClose]);
894
+ useEffect6(() => {
895
+ function handleEsc(e) {
896
+ if (e.key !== "Escape") return;
897
+ if (view === "editor") {
898
+ setView("form");
899
+ } else {
900
+ closeUnlessBusy();
901
+ }
902
+ }
903
+ document.addEventListener("keydown", handleEsc);
904
+ return () => document.removeEventListener("keydown", handleEsc);
905
+ }, [view, closeUnlessBusy]);
906
+ async function handleCapture() {
907
+ setCaptureError(null);
908
+ setCapturing(true);
909
+ try {
910
+ const blob = await captureTabScreenshot();
911
+ const image = await blobToCanvas(blob);
912
+ originalRef.current = cloneCanvas(image);
913
+ workCanvasRef.current = image;
914
+ setView("editor");
915
+ } catch (err) {
916
+ const message = err instanceof Error ? err.message : String(err);
917
+ setCaptureError(/denied|dismissed|NotAllowed/i.test(message) ? null : message);
918
+ } finally {
919
+ setCapturing(false);
920
+ }
921
+ }
922
+ useEffect6(() => {
923
+ if (view !== "editor") return;
924
+ syncDisplay();
925
+ });
926
+ function syncDisplay(preview) {
927
+ const work = workCanvasRef.current;
928
+ const display = displayCanvasRef.current;
929
+ if (!work || !display) return;
930
+ if (display.width !== work.width || display.height !== work.height) {
931
+ display.width = work.width;
932
+ display.height = work.height;
933
+ }
934
+ const ctx = display.getContext("2d");
935
+ if (!ctx) return;
936
+ ctx.clearRect(0, 0, display.width, display.height);
937
+ ctx.drawImage(work, 0, 0);
938
+ if (preview && preview.w > 0 && preview.h > 0) {
939
+ if (mode === "redact") {
940
+ ctx.fillStyle = "rgba(0, 0, 0, 0.85)";
941
+ ctx.fillRect(preview.x, preview.y, preview.w, preview.h);
942
+ } else {
943
+ ctx.save();
944
+ ctx.fillStyle = "rgba(0, 0, 0, 0.45)";
945
+ ctx.fillRect(0, 0, display.width, display.height);
946
+ ctx.clearRect(preview.x, preview.y, preview.w, preview.h);
947
+ ctx.drawImage(
948
+ work,
949
+ preview.x,
950
+ preview.y,
951
+ preview.w,
952
+ preview.h,
953
+ preview.x,
954
+ preview.y,
955
+ preview.w,
956
+ preview.h
957
+ );
958
+ ctx.strokeStyle = "#fff";
959
+ ctx.setLineDash([6, 4]);
960
+ ctx.lineWidth = 2;
961
+ ctx.strokeRect(preview.x, preview.y, preview.w, preview.h);
962
+ ctx.restore();
963
+ }
964
+ }
965
+ }
966
+ function canvasPoint(e) {
967
+ const display = displayCanvasRef.current;
968
+ const rect = display.getBoundingClientRect();
969
+ return {
970
+ x: Math.max(0, Math.min(display.width, (e.clientX - rect.left) * (display.width / rect.width))),
971
+ y: Math.max(0, Math.min(display.height, (e.clientY - rect.top) * (display.height / rect.height)))
972
+ };
973
+ }
974
+ function handlePointerDown(e) {
975
+ e.currentTarget.setPointerCapture(e.pointerId);
976
+ dragStartRef.current = canvasPoint(e);
977
+ }
978
+ function handlePointerMove(e) {
979
+ const start = dragStartRef.current;
980
+ if (!start) return;
981
+ const now = canvasPoint(e);
982
+ syncDisplay(normalizeRect(start.x, start.y, now.x, now.y));
983
+ }
984
+ function handlePointerUp(e) {
985
+ const start = dragStartRef.current;
986
+ dragStartRef.current = null;
987
+ if (!start) return;
988
+ const end = canvasPoint(e);
989
+ const rect = normalizeRect(start.x, start.y, end.x, end.y);
990
+ const work = workCanvasRef.current;
991
+ if (!work || rect.w < 4 || rect.h < 4) {
992
+ syncDisplay();
993
+ return;
994
+ }
995
+ if (mode === "redact") {
996
+ const ctx = work.getContext("2d");
997
+ ctx.fillStyle = "#000";
998
+ ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
999
+ } else {
1000
+ const cropped = document.createElement("canvas");
1001
+ cropped.width = Math.round(rect.w);
1002
+ cropped.height = Math.round(rect.h);
1003
+ cropped.getContext("2d").drawImage(
1004
+ work,
1005
+ rect.x,
1006
+ rect.y,
1007
+ rect.w,
1008
+ rect.h,
1009
+ 0,
1010
+ 0,
1011
+ rect.w,
1012
+ rect.h
1013
+ );
1014
+ workCanvasRef.current = cropped;
1015
+ }
1016
+ syncDisplay();
1017
+ }
1018
+ function handleEditorReset() {
1019
+ const original = originalRef.current;
1020
+ if (!original) return;
1021
+ workCanvasRef.current = cloneCanvas(original);
1022
+ syncDisplay();
1023
+ }
1024
+ async function handleEditorDone() {
1025
+ const work = workCanvasRef.current;
1026
+ if (!work) return;
1027
+ const blob = await new Promise(
1028
+ (resolve, reject) => work.toBlob((b) => b ? resolve(b) : reject(new Error("Screenshot encoding failed")), "image/png")
1029
+ );
1030
+ if (screenshot) URL.revokeObjectURL(screenshot.previewUrl);
1031
+ setScreenshot({ blob, previewUrl: URL.createObjectURL(blob) });
1032
+ setView("form");
1033
+ }
1034
+ function handleRemoveScreenshot() {
1035
+ if (screenshot) URL.revokeObjectURL(screenshot.previewUrl);
1036
+ setScreenshot(null);
1037
+ }
1038
+ async function handleSubmit() {
1039
+ if (!title.trim() || submitState === "submitting") return;
1040
+ setSubmitState("submitting");
1041
+ setSubmitError(null);
1042
+ const { context } = config;
1043
+ const captured = snapshotBugReportCapture();
1044
+ const payload = {
1045
+ appId: context.appId,
1046
+ environment: context.environment,
1047
+ url: context.url ?? window.location.href,
1048
+ title: title.trim(),
1049
+ description: description.trim(),
1050
+ appVersion: context.appVersion,
1051
+ apiVersion: context.apiVersion,
1052
+ userAgent: navigator.userAgent,
1053
+ viewport: `${window.innerWidth}x${window.innerHeight}`,
1054
+ console: captured.console,
1055
+ network: captured.network,
1056
+ screenshot: screenshot?.blob ?? null
1057
+ };
1058
+ try {
1059
+ await config.onSubmit(payload);
1060
+ setSubmitState("success");
1061
+ window.setTimeout(() => {
1062
+ if (screenshot) URL.revokeObjectURL(screenshot.previewUrl);
1063
+ onClose();
1064
+ }, 1500);
1065
+ } catch (err) {
1066
+ setSubmitState("error");
1067
+ setSubmitError(err instanceof Error ? err.message : "Submitting the report failed");
1068
+ }
1069
+ }
1070
+ if (capturing) return null;
1071
+ return /* @__PURE__ */ jsx6(
1072
+ "div",
1073
+ {
1074
+ className: "cfi-sh-bug-overlay",
1075
+ role: "dialog",
1076
+ "aria-modal": "true",
1077
+ "aria-label": "Report an issue",
1078
+ children: /* @__PURE__ */ jsxs6("div", { className: `cfi-sh-bug-card${view === "editor" ? " cfi-sh-bug-card-wide" : ""}`, children: [
1079
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-header", children: [
1080
+ /* @__PURE__ */ jsx6("span", { className: "cfi-sh-bug-title", children: "Report an issue" }),
1081
+ /* @__PURE__ */ jsx6("span", { className: "cfi-sh-bug-env", children: config.context.environment }),
1082
+ /* @__PURE__ */ jsx6("button", { className: "cfi-sh-bug-close", type: "button", onClick: closeUnlessBusy, "aria-label": "Close", children: "\xD7" })
1083
+ ] }),
1084
+ view === "editor" ? /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-body", children: [
1085
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-toolbar", children: [
1086
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-modes", children: [
1087
+ /* @__PURE__ */ jsx6(
1088
+ "button",
1089
+ {
1090
+ type: "button",
1091
+ className: `cfi-sh-bug-btn${mode === "crop" ? " cfi-sh-bug-btn-active" : ""}`,
1092
+ onClick: () => setMode("crop"),
1093
+ children: "Crop"
1094
+ }
1095
+ ),
1096
+ /* @__PURE__ */ jsx6(
1097
+ "button",
1098
+ {
1099
+ type: "button",
1100
+ className: `cfi-sh-bug-btn${mode === "redact" ? " cfi-sh-bug-btn-active" : ""}`,
1101
+ onClick: () => setMode("redact"),
1102
+ children: "Redact"
1103
+ }
1104
+ )
1105
+ ] }),
1106
+ /* @__PURE__ */ jsx6("span", { className: "cfi-sh-bug-hint", children: mode === "crop" ? "Drag to crop to a region" : "Drag to black out sensitive data" }),
1107
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-modes", children: [
1108
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-sh-bug-btn", onClick: handleEditorReset, children: "Reset" }),
1109
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-sh-bug-btn cfi-sh-bug-btn-primary", onClick: handleEditorDone, children: "Done" })
1110
+ ] })
1111
+ ] }),
1112
+ /* @__PURE__ */ jsx6("div", { className: "cfi-sh-bug-canvas-wrap", children: /* @__PURE__ */ jsx6(
1113
+ "canvas",
1114
+ {
1115
+ ref: displayCanvasRef,
1116
+ className: "cfi-sh-bug-canvas",
1117
+ onPointerDown: handlePointerDown,
1118
+ onPointerMove: handlePointerMove,
1119
+ onPointerUp: handlePointerUp
1120
+ }
1121
+ ) })
1122
+ ] }) : /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-body", children: [
1123
+ /* @__PURE__ */ jsx6("label", { className: "cfi-sh-bug-label", htmlFor: "cfi-sh-bug-title-input", children: "Title" }),
1124
+ /* @__PURE__ */ jsx6(
1125
+ "input",
1126
+ {
1127
+ id: "cfi-sh-bug-title-input",
1128
+ className: "cfi-sh-bug-input",
1129
+ value: title,
1130
+ onChange: (e) => setTitle(e.target.value),
1131
+ placeholder: "What went wrong?",
1132
+ maxLength: 200,
1133
+ autoFocus: true
1134
+ }
1135
+ ),
1136
+ /* @__PURE__ */ jsx6("label", { className: "cfi-sh-bug-label", htmlFor: "cfi-sh-bug-desc-input", children: "Details" }),
1137
+ /* @__PURE__ */ jsx6(
1138
+ "textarea",
1139
+ {
1140
+ id: "cfi-sh-bug-desc-input",
1141
+ className: "cfi-sh-bug-textarea",
1142
+ value: description,
1143
+ onChange: (e) => setDescription(e.target.value),
1144
+ placeholder: "What did you expect? What happened instead? Steps to reproduce\u2026",
1145
+ rows: 4,
1146
+ maxLength: 1e4
1147
+ }
1148
+ ),
1149
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-shot", children: [
1150
+ screenshot ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
1151
+ /* @__PURE__ */ jsx6("img", { className: "cfi-sh-bug-thumb", src: screenshot.previewUrl, alt: "Screenshot preview" }),
1152
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-shot-actions", children: [
1153
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-sh-bug-btn", onClick: handleCapture, children: "Retake" }),
1154
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-sh-bug-btn", onClick: handleRemoveScreenshot, children: "Remove" })
1155
+ ] })
1156
+ ] }) : /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-sh-bug-btn", onClick: handleCapture, children: "Capture screenshot" }),
1157
+ captureError && /* @__PURE__ */ jsx6("div", { className: "cfi-sh-bug-error", children: captureError })
1158
+ ] }),
1159
+ /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-meta", children: [
1160
+ "Includes: URL, app version, recent console errors and failed requests.",
1161
+ config.context.issuesUrl && /* @__PURE__ */ jsxs6(Fragment3, { children: [
1162
+ " ",
1163
+ /* @__PURE__ */ jsx6(
1164
+ "a",
1165
+ {
1166
+ className: "cfi-sh-bug-issues-link",
1167
+ href: config.context.issuesUrl,
1168
+ target: "_blank",
1169
+ rel: "noreferrer",
1170
+ children: "View known issues"
1171
+ }
1172
+ )
1173
+ ] })
1174
+ ] })
1175
+ ] }),
1176
+ view === "form" && /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-bug-footer", children: [
1177
+ submitState === "error" && submitError && /* @__PURE__ */ jsx6("span", { className: "cfi-sh-bug-error", children: submitError }),
1178
+ submitState === "success" ? /* @__PURE__ */ jsxs6("span", { className: "cfi-sh-bug-success", children: [
1179
+ "Report submitted \u2014 thank you!",
1180
+ config.context.issuesUrl && /* @__PURE__ */ jsxs6(Fragment3, { children: [
1181
+ " ",
1182
+ /* @__PURE__ */ jsx6(
1183
+ "a",
1184
+ {
1185
+ className: "cfi-sh-bug-issues-link",
1186
+ href: config.context.issuesUrl,
1187
+ target: "_blank",
1188
+ rel: "noreferrer",
1189
+ children: "View it on the issues page"
1190
+ }
1191
+ )
1192
+ ] })
1193
+ ] }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
1194
+ /* @__PURE__ */ jsx6("button", { type: "button", className: "cfi-sh-bug-btn", onClick: closeUnlessBusy, children: "Cancel" }),
1195
+ /* @__PURE__ */ jsx6(
1196
+ "button",
1197
+ {
1198
+ type: "button",
1199
+ className: "cfi-sh-bug-btn cfi-sh-bug-btn-primary",
1200
+ onClick: handleSubmit,
1201
+ disabled: !title.trim() || submitState === "submitting",
1202
+ children: submitState === "submitting" ? "Submitting\u2026" : "Submit report"
1203
+ }
1204
+ )
1205
+ ] })
1206
+ ] })
1207
+ ] })
1208
+ }
1209
+ );
1210
+ }
1211
+ async function blobToCanvas(blob) {
1212
+ const bitmap = await createImageBitmap(blob);
1213
+ try {
1214
+ const canvas = document.createElement("canvas");
1215
+ canvas.width = bitmap.width;
1216
+ canvas.height = bitmap.height;
1217
+ canvas.getContext("2d").drawImage(bitmap, 0, 0);
1218
+ return canvas;
1219
+ } finally {
1220
+ bitmap.close();
1221
+ }
1222
+ }
1223
+ function cloneCanvas(source) {
1224
+ const copy = document.createElement("canvas");
1225
+ copy.width = source.width;
1226
+ copy.height = source.height;
1227
+ copy.getContext("2d").drawImage(source, 0, 0);
1228
+ return copy;
1229
+ }
1230
+
1231
+ // src/useBugReportShortcut.ts
1232
+ import { useEffect as useEffect7, useState as useState7 } from "react";
1233
+ function useBugReportShortcut(enabled) {
1234
+ const [isOpen, setIsOpen] = useState7(false);
1235
+ useEffect7(() => {
1236
+ if (!enabled) return;
1237
+ function handleKeyDown(e) {
1238
+ const platformMod = e.ctrlKey || e.metaKey;
1239
+ if (!platformMod || !e.altKey || e.shiftKey) return;
1240
+ if (e.code !== "KeyB" && e.key.toLowerCase() !== "b") return;
1241
+ const target = e.target;
1242
+ if (target) {
1243
+ const tag = target.tagName;
1244
+ if (tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable) return;
1245
+ }
1246
+ e.preventDefault();
1247
+ setIsOpen((open) => !open);
1248
+ }
1249
+ document.addEventListener("keydown", handleKeyDown);
1250
+ return () => document.removeEventListener("keydown", handleKeyDown);
1251
+ }, [enabled]);
1252
+ return [isOpen, setIsOpen];
1253
+ }
1254
+
743
1255
  // src/assets/campfire-wordmark.png
744
1256
  var campfire_wordmark_default = "data:image/png;base64,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";
745
1257
 
746
1258
  // src/ShellHeader.tsx
747
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1259
+ import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
748
1260
  function ShellHeader({
749
1261
  appId,
750
1262
  user,
@@ -768,24 +1280,26 @@ function ShellHeader({
768
1280
  onTenantSwitch,
769
1281
  userMenuItems,
770
1282
  about,
1283
+ bugReport,
771
1284
  showSuiteLogo,
772
1285
  brandWidth,
773
1286
  children
774
1287
  }) {
775
1288
  const currentApp = appCatalog.find((a) => a.id === appId);
776
1289
  const [aboutOpen, setAboutOpen] = useAboutShortcut(about !== void 0);
1290
+ const [bugOpen, setBugOpen] = useBugReportShortcut(bugReport !== void 0);
777
1291
  const brandStyle = brandWidth ? { width: `${brandWidth}px`, flexShrink: 0, boxSizing: "border-box" } : void 0;
778
- return /* @__PURE__ */ jsxs6(Fragment3, { children: [
779
- /* @__PURE__ */ jsxs6("header", { className: "cfi-sh-header", children: [
780
- /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-left", children: [
781
- /* @__PURE__ */ jsx6("div", { className: "cfi-sh-app-brand", style: brandStyle, children: showSuiteLogo ? /* @__PURE__ */ jsx6("img", { className: "cfi-sh-suite-logo", src: campfire_wordmark_default, alt: "Campfire" }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
782
- currentApp && /* @__PURE__ */ jsx6("span", { className: "cfi-sh-app-badge", style: { background: currentApp.color }, children: currentApp.letter }),
783
- /* @__PURE__ */ jsx6("span", { className: "cfi-sh-app-title", children: currentApp?.name || appId })
1292
+ return /* @__PURE__ */ jsxs7(Fragment4, { children: [
1293
+ /* @__PURE__ */ jsxs7("header", { className: "cfi-sh-header", children: [
1294
+ /* @__PURE__ */ jsxs7("div", { className: "cfi-sh-left", children: [
1295
+ /* @__PURE__ */ jsx7("div", { className: "cfi-sh-app-brand", style: brandStyle, children: showSuiteLogo ? /* @__PURE__ */ jsx7("img", { className: "cfi-sh-suite-logo", src: campfire_wordmark_default, alt: "Campfire" }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
1296
+ currentApp && /* @__PURE__ */ jsx7("span", { className: "cfi-sh-app-badge", style: { background: currentApp.color }, children: currentApp.letter }),
1297
+ /* @__PURE__ */ jsx7("span", { className: "cfi-sh-app-title", children: currentApp?.name || appId })
784
1298
  ] }) }),
785
1299
  children
786
1300
  ] }),
787
- /* @__PURE__ */ jsxs6("div", { className: "cfi-sh-right", children: [
788
- /* @__PURE__ */ jsx6(
1301
+ /* @__PURE__ */ jsxs7("div", { className: "cfi-sh-right", children: [
1302
+ /* @__PURE__ */ jsx7(
789
1303
  NotificationBell,
790
1304
  {
791
1305
  count: notificationCount,
@@ -796,8 +1310,8 @@ function ShellHeader({
796
1310
  onItemClick: onNotificationItemClick
797
1311
  }
798
1312
  ),
799
- /* @__PURE__ */ jsx6(AppSwitcher, { currentAppId: appId, authorizedApps, currentTenantRole }),
800
- /* @__PURE__ */ jsx6(
1313
+ /* @__PURE__ */ jsx7(AppSwitcher, { currentAppId: appId, authorizedApps, currentTenantRole }),
1314
+ /* @__PURE__ */ jsx7(
801
1315
  UserMenu,
802
1316
  {
803
1317
  user,
@@ -817,18 +1331,19 @@ function ShellHeader({
817
1331
  )
818
1332
  ] })
819
1333
  ] }),
820
- about && aboutOpen && /* @__PURE__ */ jsx6(AboutModal, { about, onClose: () => setAboutOpen(false) })
1334
+ about && aboutOpen && /* @__PURE__ */ jsx7(AboutModal, { about, onClose: () => setAboutOpen(false) }),
1335
+ bugReport && bugOpen && /* @__PURE__ */ jsx7(BugReportModal, { config: bugReport, onClose: () => setBugOpen(false) })
821
1336
  ] });
822
1337
  }
823
1338
 
824
1339
  // src/LocaleSwitcher.tsx
825
- import { useState as useState6, useRef as useRef4, useEffect as useEffect6 } from "react";
826
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1340
+ import { useState as useState8, useRef as useRef5, useEffect as useEffect8 } from "react";
1341
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
827
1342
  function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
828
- const [open, setOpen] = useState6(false);
829
- const [updating, setUpdating] = useState6(false);
830
- const ref = useRef4(null);
831
- useEffect6(() => {
1343
+ const [open, setOpen] = useState8(false);
1344
+ const [updating, setUpdating] = useState8(false);
1345
+ const ref = useRef5(null);
1346
+ useEffect8(() => {
832
1347
  function handleClickOutside(e) {
833
1348
  if (ref.current && !ref.current.contains(e.target)) {
834
1349
  setOpen(false);
@@ -852,8 +1367,8 @@ function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
852
1367
  setOpen(false);
853
1368
  }
854
1369
  }
855
- return /* @__PURE__ */ jsxs7("div", { className: "cfi-sh-locale-switcher", ref, children: [
856
- /* @__PURE__ */ jsxs7(
1370
+ return /* @__PURE__ */ jsxs8("div", { className: "cfi-sh-locale-switcher", ref, children: [
1371
+ /* @__PURE__ */ jsxs8(
857
1372
  "button",
858
1373
  {
859
1374
  className: "cfi-sh-locale-btn",
@@ -864,20 +1379,20 @@ function LocaleSwitcher({ currentLocale, supportedLocales, onLocaleChange }) {
864
1379
  disabled: updating,
865
1380
  title: current?.label ?? currentLocale,
866
1381
  children: [
867
- /* @__PURE__ */ jsx7(Globe, { size: 16 }),
868
- /* @__PURE__ */ jsx7("span", { className: "cfi-sh-locale-label", children: buttonLabel })
1382
+ /* @__PURE__ */ jsx8(Globe, { size: 16 }),
1383
+ /* @__PURE__ */ jsx8("span", { className: "cfi-sh-locale-label", children: buttonLabel })
869
1384
  ]
870
1385
  }
871
1386
  ),
872
- open && /* @__PURE__ */ jsx7("div", { className: "cfi-sh-locale-dropdown", children: supportedLocales.map((loc) => /* @__PURE__ */ jsxs7(
1387
+ open && /* @__PURE__ */ jsx8("div", { className: "cfi-sh-locale-dropdown", children: supportedLocales.map((loc) => /* @__PURE__ */ jsxs8(
873
1388
  "button",
874
1389
  {
875
1390
  className: loc.code === currentLocale ? "cfi-sh-menu-item cfi-sh-locale-item-active" : "cfi-sh-menu-item",
876
1391
  onClick: () => handleSelect(loc.code),
877
1392
  disabled: updating,
878
1393
  children: [
879
- /* @__PURE__ */ jsx7("span", { className: "cfi-sh-locale-item-label", children: loc.label }),
880
- /* @__PURE__ */ jsx7("span", { className: "cfi-sh-locale-item-code", children: loc.code.toUpperCase() })
1394
+ /* @__PURE__ */ jsx8("span", { className: "cfi-sh-locale-item-label", children: loc.label }),
1395
+ /* @__PURE__ */ jsx8("span", { className: "cfi-sh-locale-item-code", children: loc.code.toUpperCase() })
881
1396
  ]
882
1397
  },
883
1398
  loc.code
@@ -888,5 +1403,6 @@ export {
888
1403
  LocaleSwitcher,
889
1404
  ShellHeader,
890
1405
  appCatalog,
891
- getAppUrl
1406
+ getAppUrl,
1407
+ installBugReportCapture
892
1408
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campfire-interactive/shell-header",
3
- "version": "0.8.15",
3
+ "version": "0.11.0",
4
4
  "description": "Shared shell header with app switcher for Campfire Suite",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",