@campfire-interactive/shell-header 0.1.2 → 0.1.4
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 +8 -2
- package/dist/index.js +22 -13
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ interface AppDefinition {
|
|
|
4
4
|
id: string;
|
|
5
5
|
name: string;
|
|
6
6
|
icon: string;
|
|
7
|
+
/** Single letter shown in the branded badge */
|
|
8
|
+
letter: string;
|
|
9
|
+
/** Badge background color */
|
|
10
|
+
color: string;
|
|
7
11
|
/** Local dev port (e.g., 3000). Omit if the app doesn't run locally. */
|
|
8
12
|
localPort?: number;
|
|
9
13
|
}
|
|
@@ -25,11 +29,13 @@ interface ShellHeaderProps {
|
|
|
25
29
|
onNotificationClick?: () => void;
|
|
26
30
|
/** Called when logout is clicked */
|
|
27
31
|
onLogout?: () => void;
|
|
28
|
-
/**
|
|
32
|
+
/** Fixed width for the app brand area (e.g., to align with a sidebar below). */
|
|
33
|
+
brandWidth?: number;
|
|
34
|
+
/** Optional content in the left/center area (filters, search, breadcrumbs, etc.) */
|
|
29
35
|
children?: React.ReactNode;
|
|
30
36
|
}
|
|
31
37
|
|
|
32
|
-
declare function ShellHeader({ appId, user, authorizedApps, notificationCount, onNotificationClick, onLogout, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
|
|
38
|
+
declare function ShellHeader({ appId, user, authorizedApps, notificationCount, onNotificationClick, onLogout, brandWidth, children, }: ShellHeaderProps): react_jsx_runtime.JSX.Element;
|
|
33
39
|
|
|
34
40
|
declare const appCatalog: AppDefinition[];
|
|
35
41
|
/**
|
package/dist/index.js
CHANGED
|
@@ -24,20 +24,17 @@ 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 overflow: hidden;\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
|
|
28
|
-
|
|
29
|
-
// src/AppSwitcher.tsx
|
|
30
|
-
import { useState, useRef, useEffect } from "react";
|
|
27
|
+
styleInject(".cfi-sh-header {\n display: flex;\n align-items: center;\n height: var(--cfi-shell-header-height, 48px);\n padding: 0 var(--cfi-spacing-md, 1rem);\n background: white;\n color: var(--cfi-color-gray-900, #111827);\n font-family: var(--cfi-font-family, system-ui, sans-serif);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n border-bottom: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n position: relative;\n z-index: 1000;\n}\n.cfi-sh-left {\n display: flex;\n align-items: center;\n flex: 1;\n gap: var(--cfi-spacing-md, 1rem);\n overflow: hidden;\n}\n.cfi-sh-app-brand {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-badge {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n color: white;\n font-size: 14px;\n font-weight: 700;\n font-family: inherit;\n border-radius: var(--cfi-radius-md, 0.375rem);\n flex-shrink: 0;\n}\n.cfi-sh-app-title {\n font-weight: 600;\n font-size: var(--cfi-font-size-base, 1rem);\n color: var(--cfi-color-gray-900, #111827);\n white-space: nowrap;\n}\n.cfi-sh-right {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n flex-shrink: 0;\n}\n.cfi-sh-icon-btn {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n background: transparent;\n border: none;\n border-radius: 50%;\n color: var(--cfi-color-gray-600, #4b5563);\n cursor: pointer;\n transition: background 150ms;\n}\n.cfi-sh-icon-btn:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n background: var(--cfi-color-error, #ef4444);\n color: white;\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n border-radius: 99px;\n}\n.cfi-sh-app-switcher {\n position: relative;\n}\n.cfi-sh-app-grid {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: var(--cfi-spacing-xs, 0.25rem);\n padding: var(--cfi-spacing-sm, 0.5rem);\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n min-width: 280px;\n}\n.cfi-sh-app-grid-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--cfi-spacing-xs, 0.25rem);\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-xs, 0.25rem);\n border-radius: var(--cfi-radius-md, 0.375rem);\n color: var(--cfi-color-gray-700, #374151);\n text-decoration: none;\n cursor: pointer;\n transition: background 100ms;\n font-family: inherit;\n}\n.cfi-sh-app-grid-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n.cfi-sh-app-grid-item-active {\n background: var(--cfi-color-primary-50, #fff7ed);\n color: var(--cfi-color-primary-700, #c2410c);\n}\n.cfi-sh-app-grid-item-active:hover {\n background: var(--cfi-color-primary-100, #ffedd5);\n}\n.cfi-sh-app-grid-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n}\n.cfi-sh-app-grid-label {\n font-size: var(--cfi-font-size-xs, 0.75rem);\n text-align: center;\n line-height: 1.2;\n max-width: 80px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.cfi-sh-user-menu {\n position: relative;\n}\n.cfi-sh-avatar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: var(--cfi-color-primary-600, #ea580c);\n border: none;\n border-radius: 50%;\n cursor: pointer;\n transition: opacity 150ms;\n}\n.cfi-sh-avatar-btn:hover {\n opacity: 0.85;\n}\n.cfi-sh-avatar-img {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n object-fit: cover;\n}\n.cfi-sh-avatar-initials {\n color: white;\n font-size: var(--cfi-font-size-xs, 0.75rem);\n font-weight: 600;\n font-family: inherit;\n}\n.cfi-sh-user-dropdown {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n min-width: 200px;\n background: white;\n border-radius: var(--cfi-radius-lg, 0.5rem);\n box-shadow: var(--cfi-shadow-lg, 0 10px 15px rgba(0, 0, 0, 0.1));\n border: 1px solid var(--cfi-color-gray-200, #e5e7eb);\n z-index: 1001;\n}\n.cfi-sh-user-header {\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n display: flex;\n flex-direction: column;\n}\n.cfi-sh-user-name {\n font-weight: 500;\n color: var(--cfi-color-gray-900, #111827);\n font-size: var(--cfi-font-size-sm, 0.875rem);\n}\n.cfi-sh-user-email {\n color: var(--cfi-color-gray-500, #6b7280);\n font-size: var(--cfi-font-size-xs, 0.75rem);\n}\n.cfi-sh-divider {\n height: 1px;\n background: var(--cfi-color-gray-200, #e5e7eb);\n}\n.cfi-sh-menu-item {\n display: flex;\n align-items: center;\n gap: var(--cfi-spacing-sm, 0.5rem);\n width: 100%;\n padding: var(--cfi-spacing-sm, 0.5rem) var(--cfi-spacing-md, 1rem);\n background: none;\n border: none;\n color: var(--cfi-color-gray-700, #374151);\n cursor: pointer;\n font-size: var(--cfi-font-size-sm, 0.875rem);\n font-family: inherit;\n transition: background 100ms;\n}\n.cfi-sh-menu-item:hover {\n background: var(--cfi-color-gray-100, #f3f4f6);\n}\n");
|
|
31
28
|
|
|
32
29
|
// src/appCatalog.ts
|
|
33
30
|
var appCatalog = [
|
|
34
|
-
{ id: "si", name: "Supplier Intelligence", icon: "Building2", localPort: 3e3 },
|
|
35
|
-
{ id: "masterdata", name: "Master Data", icon: "Database", localPort: 3100 },
|
|
36
|
-
{ id: "forecast", name: "Forecasting", icon: "TrendingUp", localPort: 3200 },
|
|
37
|
-
{ id: "pim", name: "Price Index", icon: "BarChart3", localPort: 3300 },
|
|
38
|
-
{ id: "cpq", name: "CPQ", icon: "Calculator", localPort: 3400 },
|
|
39
|
-
{ id: "omsf", name: "OMSF", icon: "FileText", localPort: 3500 },
|
|
40
|
-
{ id: "identity", name: "Identity", icon: "Shield", localPort: 3600 }
|
|
31
|
+
{ id: "si", name: "Supplier Intelligence", icon: "Building2", letter: "S", color: "#6366f1", localPort: 3e3 },
|
|
32
|
+
{ id: "masterdata", name: "Master Data", icon: "Database", letter: "M", color: "#f97316", localPort: 3100 },
|
|
33
|
+
{ id: "forecast", name: "Forecasting", icon: "TrendingUp", letter: "F", color: "#10b981", localPort: 3200 },
|
|
34
|
+
{ id: "pim", name: "Price Index", icon: "BarChart3", letter: "P", color: "#f97316", localPort: 3300 },
|
|
35
|
+
{ id: "cpq", name: "CPQ", icon: "Calculator", letter: "C", color: "#4f46e5", localPort: 3400 },
|
|
36
|
+
{ id: "omsf", name: "OMSF", icon: "FileText", letter: "O", color: "#0ea5e9", localPort: 3500 },
|
|
37
|
+
{ id: "identity", name: "Identity", icon: "Shield", letter: "I", color: "#8b5cf6", localPort: 3600 }
|
|
41
38
|
];
|
|
42
39
|
function getAppUrl(app) {
|
|
43
40
|
const host = typeof window !== "undefined" ? window.location.hostname : "";
|
|
@@ -51,6 +48,9 @@ function getAppUrl(app) {
|
|
|
51
48
|
return `${protocol}//${app.id}.campfiresuite.com`;
|
|
52
49
|
}
|
|
53
50
|
|
|
51
|
+
// src/AppSwitcher.tsx
|
|
52
|
+
import { useState, useRef, useEffect } from "react";
|
|
53
|
+
|
|
54
54
|
// src/icons.tsx
|
|
55
55
|
import {
|
|
56
56
|
Building2,
|
|
@@ -131,7 +131,7 @@ function AppSwitcher({ currentAppId, authorizedApps }) {
|
|
|
131
131
|
setOpen(false);
|
|
132
132
|
} : void 0,
|
|
133
133
|
children: [
|
|
134
|
-
/* @__PURE__ */ jsx2("div", { className: "cfi-sh-app-grid-icon", children: /* @__PURE__ */ jsx2(Icon, { size: 22 }) }),
|
|
134
|
+
/* @__PURE__ */ jsx2("div", { className: "cfi-sh-app-grid-icon", style: { background: `${app.color}18`, color: app.color }, children: /* @__PURE__ */ jsx2(Icon, { size: 22 }) }),
|
|
135
135
|
/* @__PURE__ */ jsx2("span", { className: "cfi-sh-app-grid-label", children: app.name })
|
|
136
136
|
]
|
|
137
137
|
},
|
|
@@ -210,10 +210,19 @@ function ShellHeader({
|
|
|
210
210
|
notificationCount,
|
|
211
211
|
onNotificationClick,
|
|
212
212
|
onLogout,
|
|
213
|
+
brandWidth,
|
|
213
214
|
children
|
|
214
215
|
}) {
|
|
216
|
+
const currentApp = appCatalog.find((a) => a.id === appId);
|
|
217
|
+
const brandStyle = brandWidth ? { width: `${brandWidth}px`, flexShrink: 0, boxSizing: "border-box" } : void 0;
|
|
215
218
|
return /* @__PURE__ */ jsxs5("header", { className: "cfi-sh-header", children: [
|
|
216
|
-
/* @__PURE__ */
|
|
219
|
+
/* @__PURE__ */ jsxs5("div", { className: "cfi-sh-left", children: [
|
|
220
|
+
/* @__PURE__ */ jsxs5("div", { className: "cfi-sh-app-brand", style: brandStyle, children: [
|
|
221
|
+
currentApp && /* @__PURE__ */ jsx5("span", { className: "cfi-sh-app-badge", style: { background: currentApp.color }, children: currentApp.letter }),
|
|
222
|
+
/* @__PURE__ */ jsx5("span", { className: "cfi-sh-app-title", children: currentApp?.name || appId })
|
|
223
|
+
] }),
|
|
224
|
+
children
|
|
225
|
+
] }),
|
|
217
226
|
/* @__PURE__ */ jsxs5("div", { className: "cfi-sh-right", children: [
|
|
218
227
|
/* @__PURE__ */ jsx5(NotificationBell, { count: notificationCount, onClick: onNotificationClick }),
|
|
219
228
|
/* @__PURE__ */ jsx5(AppSwitcher, { currentAppId: appId, authorizedApps }),
|