@campfire-interactive/shell-header 0.8.12 → 0.8.14
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 +9 -5
- package/dist/index.js +55 -44
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -21,12 +21,16 @@ interface AppDefinition {
|
|
|
21
21
|
*/
|
|
22
22
|
byline?: string;
|
|
23
23
|
/**
|
|
24
|
-
* Which launcher section the app appears under.
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* the user can see none of them
|
|
24
|
+
* Which launcher section the app appears under, by persona. Product apps use
|
|
25
|
+
* a persona group (`'sales'` / `'sourcing'` / `'planning'` / `'engineering'`);
|
|
26
|
+
* `'admin'` groups admin surfaces (Master Data, User Management) — the
|
|
27
|
+
* launcher hides that section entirely when the user can see none of them, and
|
|
28
|
+
* the AppSwitcher pins admin apps to the end. `'apps'` is the legacy/default
|
|
29
|
+
* bucket for anything untagged. Launcher renders one section per group, in
|
|
30
|
+
* the launcher's defined group order; the AppSwitcher renders in catalog
|
|
31
|
+
* array order (non-admin, then admin).
|
|
28
32
|
*/
|
|
29
|
-
group?: 'apps' | 'admin';
|
|
33
|
+
group?: 'apps' | 'sales' | 'sourcing' | 'planning' | 'engineering' | 'admin';
|
|
30
34
|
/** Local dev port (e.g., 3000). Omit if the app doesn't run locally. */
|
|
31
35
|
localPort?: number;
|
|
32
36
|
/**
|
package/dist/index.js
CHANGED
|
@@ -24,10 +24,33 @@ 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.2;\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.4em;\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");
|
|
28
28
|
|
|
29
29
|
// src/appCatalog.ts
|
|
30
30
|
var appCatalog = [
|
|
31
|
+
// ── Sales & Commercial ──────────────────────────────────────────────────
|
|
32
|
+
{
|
|
33
|
+
id: "omsf",
|
|
34
|
+
name: "Opportunity Management",
|
|
35
|
+
icon: "FileText",
|
|
36
|
+
letter: "O",
|
|
37
|
+
color: "#0ea5e9",
|
|
38
|
+
byline: "Automate RFQ intake, submit to OEMs in one click, & quickly handover awards.",
|
|
39
|
+
group: "sales",
|
|
40
|
+
localPort: 3500
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "cpq",
|
|
44
|
+
name: "CPQ",
|
|
45
|
+
fullName: "Cost, Price, Quote",
|
|
46
|
+
icon: "Calculator",
|
|
47
|
+
letter: "C",
|
|
48
|
+
color: "#4f46e5",
|
|
49
|
+
byline: "Know exactly what products cost & make pricing decisions with confidence.",
|
|
50
|
+
group: "sales",
|
|
51
|
+
localPort: 3400
|
|
52
|
+
},
|
|
53
|
+
// ── Sourcing & Supply ───────────────────────────────────────────────────
|
|
31
54
|
{
|
|
32
55
|
id: "si",
|
|
33
56
|
name: "Supplier Intelligence",
|
|
@@ -35,19 +58,21 @@ var appCatalog = [
|
|
|
35
58
|
letter: "S",
|
|
36
59
|
color: "#6366f1",
|
|
37
60
|
byline: "Monitor supplier performance and risk across your supply base.",
|
|
61
|
+
group: "sourcing",
|
|
38
62
|
localPort: 3e3
|
|
39
63
|
},
|
|
40
64
|
{
|
|
41
|
-
id: "
|
|
42
|
-
name: "
|
|
43
|
-
|
|
44
|
-
|
|
65
|
+
id: "pim",
|
|
66
|
+
name: "Price Index",
|
|
67
|
+
fullName: "Price Index Management",
|
|
68
|
+
icon: "BarChart3",
|
|
69
|
+
letter: "P",
|
|
45
70
|
color: "#f97316",
|
|
46
|
-
byline: "
|
|
47
|
-
group: "
|
|
48
|
-
|
|
49
|
-
localPort: 3100
|
|
71
|
+
byline: "Every escalation, automated & accurate. Monitor commodity and material pricing, recover margin when indices move.",
|
|
72
|
+
group: "sourcing",
|
|
73
|
+
localPort: 3300
|
|
50
74
|
},
|
|
75
|
+
// ── Planning ────────────────────────────────────────────────────────────
|
|
51
76
|
{
|
|
52
77
|
id: "forecast",
|
|
53
78
|
name: "Volume Intelligence",
|
|
@@ -55,36 +80,32 @@ var appCatalog = [
|
|
|
55
80
|
letter: "V",
|
|
56
81
|
color: "#10b981",
|
|
57
82
|
byline: "Know what you'll build before you bid. AI-driven production-volume forecasts you can plan revenue and quotes around.",
|
|
83
|
+
group: "planning",
|
|
58
84
|
localPort: 3200
|
|
59
85
|
},
|
|
86
|
+
// ── Engineering ─────────────────────────────────────────────────────────
|
|
60
87
|
{
|
|
61
|
-
id: "
|
|
62
|
-
name: "
|
|
63
|
-
fullName: "
|
|
64
|
-
icon: "
|
|
65
|
-
letter: "
|
|
66
|
-
color: "#
|
|
67
|
-
byline: "
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
{
|
|
71
|
-
id: "cpq",
|
|
72
|
-
name: "CPQ",
|
|
73
|
-
fullName: "Cost, Price, Quote",
|
|
74
|
-
icon: "Calculator",
|
|
75
|
-
letter: "C",
|
|
76
|
-
color: "#4f46e5",
|
|
77
|
-
byline: "Know exactly what products cost & make pricing decisions with confidence.",
|
|
78
|
-
localPort: 3400
|
|
88
|
+
id: "bom",
|
|
89
|
+
name: "BOM",
|
|
90
|
+
fullName: "BOM Management",
|
|
91
|
+
icon: "Network",
|
|
92
|
+
letter: "B",
|
|
93
|
+
color: "#0d9488",
|
|
94
|
+
byline: "Control bill of materials and costs across the program lifecycle.",
|
|
95
|
+
group: "engineering",
|
|
96
|
+
localPort: 3700
|
|
79
97
|
},
|
|
98
|
+
// ── Admin (role-gated; pinned to the end of both surfaces) ──────────────
|
|
80
99
|
{
|
|
81
|
-
id: "
|
|
82
|
-
name: "
|
|
83
|
-
icon: "
|
|
84
|
-
letter: "
|
|
85
|
-
color: "#
|
|
86
|
-
byline: "
|
|
87
|
-
|
|
100
|
+
id: "masterdata",
|
|
101
|
+
name: "Master Data",
|
|
102
|
+
icon: "Database",
|
|
103
|
+
letter: "M",
|
|
104
|
+
color: "#f97316",
|
|
105
|
+
byline: "Define it once, use it everywhere \u2014 the canonical records every app reads from.",
|
|
106
|
+
group: "admin",
|
|
107
|
+
requiresRole: ["admin", "owner"],
|
|
108
|
+
localPort: 3100
|
|
88
109
|
},
|
|
89
110
|
{
|
|
90
111
|
id: "identity",
|
|
@@ -97,16 +118,6 @@ var appCatalog = [
|
|
|
97
118
|
requiresRole: ["admin", "owner"],
|
|
98
119
|
localPort: 3600,
|
|
99
120
|
path: "/admin/users"
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
id: "bom",
|
|
103
|
-
name: "BOM",
|
|
104
|
-
fullName: "BOM Management",
|
|
105
|
-
icon: "Network",
|
|
106
|
-
letter: "B",
|
|
107
|
-
color: "#0d9488",
|
|
108
|
-
byline: "Control bill of materials and costs across the program lifecycle.",
|
|
109
|
-
localPort: 3700
|
|
110
121
|
}
|
|
111
122
|
];
|
|
112
123
|
function getAppUrl(app) {
|