@the-portland-company/shell 0.3.0 → 0.3.2

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { extendTheme, Tooltip, ChakraProvider, useColorModeValue, Flex, Menu, MenuButton, HStack, Avatar, VStack, Text, Box, Portal, MenuList, MenuItem, MenuDivider, Badge, IconButton, Link as Link$1, Collapse, Skeleton, Button, Image, useDisclosure, useToast, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, Textarea, ModalFooter, useClipboard } from '@chakra-ui/react';
1
+ import { extendTheme, Tooltip, ChakraProvider, useColorModeValue, Flex, Menu, MenuButton, HStack, Avatar, VStack, Text, Box, Portal, MenuList, MenuItem, MenuDivider, Badge, IconButton, Link as Link$1, Collapse, Skeleton, Button, useClipboard, Icon, Image, useDisclosure, useToast, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, Textarea, ModalFooter } from '@chakra-ui/react';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
  import clsx2 from 'clsx';
4
4
  import { Link, useLocation, useNavigate, NavLink } from 'react-router-dom';
@@ -1147,7 +1147,8 @@ function ShellProvider({
1147
1147
  linkedAccounts,
1148
1148
  support,
1149
1149
  devNotesMenu,
1150
- myProfileHref
1150
+ myProfileHref,
1151
+ userAvatarUrl
1151
1152
  }) {
1152
1153
  const [status, setStatus] = useState("loading");
1153
1154
  const [session, setSession] = useState(null);
@@ -1189,9 +1190,10 @@ function ShellProvider({
1189
1190
  const chrome = useMemo(
1190
1191
  () => ({
1191
1192
  devNotesMenu: devNotesMenu ?? null,
1192
- myProfileHref: myProfileHref ?? "/my-profile"
1193
+ myProfileHref: myProfileHref ?? "/my-profile",
1194
+ userAvatarUrl
1193
1195
  }),
1194
- [devNotesMenu, myProfileHref]
1196
+ [devNotesMenu, myProfileHref, userAvatarUrl]
1195
1197
  );
1196
1198
  return /* @__PURE__ */ jsx(ShellAuthContext.Provider, { value, children: /* @__PURE__ */ jsx(ShellMetaContext.Provider, { value: meta, children: /* @__PURE__ */ jsx(ShellOrgContext.Provider, { value: organization ?? null, children: /* @__PURE__ */ jsx(ShellLinkedAccountsContext.Provider, { value: linkedAccounts ?? null, children: /* @__PURE__ */ jsx(ShellSupportProviderContext.Provider, { value: support ?? null, children: /* @__PURE__ */ jsx(ShellModeContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ShellNavItemsContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ShellNavigationPreferenceContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ShellRoleContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ShellFooterContext.Provider, { value: null, children: /* @__PURE__ */ jsx(ShellChromeContext.Provider, { value: chrome, children: /* @__PURE__ */ jsx(ChakraProvider, { theme: politogyTheme, children }) }) }) }) }) }) }) }) }) }) }) });
1197
1199
  }
@@ -1278,7 +1280,8 @@ function UserMenu() {
1278
1280
  myProfileHref,
1279
1281
  organizationSettingsHref,
1280
1282
  showContinueOnboarding,
1281
- onContinueOnboarding
1283
+ onContinueOnboarding,
1284
+ userAvatarUrl
1282
1285
  } = useShellChrome();
1283
1286
  const linked = useShellLinkedAccounts();
1284
1287
  const mode = useShellMode();
@@ -1289,7 +1292,7 @@ function UserMenu() {
1289
1292
  const menuListBorderColor = useColorModeValue("gray.200", "gray.700");
1290
1293
  if (status !== "authenticated" || !user) return null;
1291
1294
  const displayName = getUserDisplayName(user.raw);
1292
- const avatarUrl = avatarUrlFromUser(user);
1295
+ const avatarUrl = userAvatarUrl ?? avatarUrlFromUser(user);
1293
1296
  const modeConfig = mode?.getModeConfig() ?? null;
1294
1297
  const currentOrg = org?.currentOrg ?? null;
1295
1298
  const linkedAccounts = linked?.linkedAccounts ?? [];
@@ -1444,8 +1447,7 @@ function Header({ onOpen, id }) {
1444
1447
  breadcrumbs,
1445
1448
  headerActions,
1446
1449
  headerIconsSlot,
1447
- brandLogoSrc,
1448
- devNotesMenu
1450
+ brandLogoSrc
1449
1451
  } = useShellChrome();
1450
1452
  const mobileNavBg = useColorModeValue("white", "gray.900");
1451
1453
  const mobileNavBorderColor = useColorModeValue("gray.200", "gray.700");
@@ -1521,8 +1523,7 @@ function Header({ onOpen, id }) {
1521
1523
  },
1522
1524
  children: [
1523
1525
  headerActions,
1524
- headerIconsSlot,
1525
- devNotesMenu
1526
+ headerIconsSlot
1526
1527
  ]
1527
1528
  }
1528
1529
  ),
@@ -2178,6 +2179,237 @@ function ModePill() {
2178
2179
  ] }) });
2179
2180
  }
2180
2181
  var ModePill_default = ModePill;
2182
+ function ActivityIcon() {
2183
+ return /* @__PURE__ */ jsx(
2184
+ "svg",
2185
+ {
2186
+ width: "12",
2187
+ height: "12",
2188
+ viewBox: "0 0 24 24",
2189
+ fill: "none",
2190
+ stroke: "currentColor",
2191
+ strokeWidth: "2",
2192
+ strokeLinecap: "round",
2193
+ strokeLinejoin: "round",
2194
+ "aria-hidden": "true",
2195
+ children: /* @__PURE__ */ jsx("polyline", { points: "22 12 18 12 15 21 9 3 6 12 2 12" })
2196
+ }
2197
+ );
2198
+ }
2199
+ function defaultEnvChip(label) {
2200
+ if (!label) return null;
2201
+ const lower = label.toLowerCase();
2202
+ if (lower.includes("prod")) {
2203
+ return { color: "#ef4444", bg: "#fee2e2", border: "#fecaca", name: label };
2204
+ }
2205
+ if (lower.includes("stag")) {
2206
+ return { color: "#f97316", bg: "#ffedd5", border: "#fed7aa", name: label };
2207
+ }
2208
+ if (lower.includes("local") || lower.includes("dev")) {
2209
+ return { color: "#22c55e", bg: "#dcfce7", border: "#bbf7d0", name: label };
2210
+ }
2211
+ return { color: "#6b7280", bg: "#f3f4f6", border: "#e5e7eb", name: label };
2212
+ }
2213
+ var PLACEHOLDER_SHA_VALUES = /* @__PURE__ */ new Set(["unknown", "n/a", "null", "undefined", ""]);
2214
+ function isMeaningfulCommit(value) {
2215
+ if (typeof value !== "string") return false;
2216
+ const trimmed = value.trim();
2217
+ if (!trimmed) return false;
2218
+ return !PLACEHOLDER_SHA_VALUES.has(trimmed.toLowerCase());
2219
+ }
2220
+ function isMeaningfulAuthor(value) {
2221
+ if (typeof value !== "string") return false;
2222
+ const trimmed = value.trim();
2223
+ if (!trimmed) return false;
2224
+ return !PLACEHOLDER_SHA_VALUES.has(trimmed.toLowerCase());
2225
+ }
2226
+ function getFirstName(value) {
2227
+ if (!value) return "";
2228
+ const stripped = value.replace(/<[^>]+>/g, "").trim();
2229
+ if (!stripped) return "";
2230
+ const [firstToken] = stripped.split(/\s+/);
2231
+ return firstToken || stripped;
2232
+ }
2233
+ function CommitCopyButton({
2234
+ envNode,
2235
+ environmentLabel,
2236
+ commit,
2237
+ version = "",
2238
+ commitDate = "",
2239
+ commitAuthor = "",
2240
+ commitLog = "",
2241
+ onDiagnosticsClick
2242
+ }) {
2243
+ const safeCommit = isMeaningfulCommit(commit) ? commit.trim() : "";
2244
+ const { hasCopied, onCopy } = useClipboard(safeCommit);
2245
+ const shortCommit = safeCommit ? safeCommit.slice(-4) : "";
2246
+ const copiedAnimation = keyframes`
2247
+ 0% { opacity: 0; transform: translateY(6px); }
2248
+ 20% { opacity: 1; transform: translateY(0); }
2249
+ 100% { opacity: 0; transform: translateY(-8px); }
2250
+ `;
2251
+ const formattedDate = useMemo(() => {
2252
+ if (!commitDate) return "";
2253
+ const parsed = new Date(commitDate);
2254
+ if (Number.isNaN(parsed.getTime())) return commitDate;
2255
+ return parsed.toLocaleDateString(void 0, { month: "short", day: "numeric" });
2256
+ }, [commitDate]);
2257
+ const metaLine = useMemo(() => {
2258
+ const firstName = isMeaningfulAuthor(commitAuthor) ? getFirstName(commitAuthor) : "";
2259
+ return [formattedDate, firstName].filter(Boolean).join(" | ");
2260
+ }, [formattedDate, commitAuthor]);
2261
+ const normalizedCommitLog = useMemo(() => {
2262
+ if (commitLog?.trim()) {
2263
+ return commitLog.replace(/\r\n/g, "\n").replace(/\\n/g, "\n");
2264
+ }
2265
+ return "";
2266
+ }, [commitLog]);
2267
+ const tooltipContent = normalizedCommitLog.length > 0 ? /* @__PURE__ */ jsx(
2268
+ Box,
2269
+ {
2270
+ maxW: "600px",
2271
+ width: "min(600px, 90vw)",
2272
+ maxH: "80vh",
2273
+ whiteSpace: "pre-wrap",
2274
+ overflowY: "auto",
2275
+ overflowX: "auto",
2276
+ fontSize: "xs",
2277
+ fontFamily: "mono",
2278
+ wordBreak: "break-word",
2279
+ children: normalizedCommitLog
2280
+ }
2281
+ ) : void 0;
2282
+ const envChip = useMemo(() => {
2283
+ if (envNode) return envNode;
2284
+ const chip = defaultEnvChip(environmentLabel);
2285
+ if (!chip) return null;
2286
+ return /* @__PURE__ */ jsx(
2287
+ Box,
2288
+ {
2289
+ as: "span",
2290
+ display: "inline-flex",
2291
+ alignItems: "center",
2292
+ px: "1.5",
2293
+ py: "0.5",
2294
+ borderWidth: "1px",
2295
+ borderColor: chip.border,
2296
+ bg: chip.bg,
2297
+ color: chip.color,
2298
+ borderRadius: "md",
2299
+ fontSize: "2xs",
2300
+ fontWeight: "600",
2301
+ lineHeight: "1",
2302
+ textTransform: "capitalize",
2303
+ "aria-label": `Environment: ${chip.name}`,
2304
+ children: chip.name
2305
+ }
2306
+ );
2307
+ }, [envNode, environmentLabel]);
2308
+ const showEnv = Boolean(envChip);
2309
+ return /* @__PURE__ */ jsxs(
2310
+ VStack,
2311
+ {
2312
+ justify: "center",
2313
+ align: "center",
2314
+ borderRadius: "md",
2315
+ py: 0.5,
2316
+ px: 1,
2317
+ position: "relative",
2318
+ spacing: 0,
2319
+ textAlign: "center",
2320
+ w: "full",
2321
+ children: [
2322
+ /* @__PURE__ */ jsxs(Flex, { justify: "center", align: "center", gap: 2, whiteSpace: "nowrap", children: [
2323
+ showEnv ? /* @__PURE__ */ jsxs(Fragment, { children: [
2324
+ /* @__PURE__ */ jsx(Box, { flexShrink: 0, children: /* @__PURE__ */ jsx(
2325
+ Tooltip,
2326
+ {
2327
+ label: tooltipContent,
2328
+ isDisabled: !tooltipContent,
2329
+ hasArrow: true,
2330
+ placement: "top-start",
2331
+ openDelay: 150,
2332
+ closeOnClick: false,
2333
+ shouldWrapChildren: true,
2334
+ modifiers: [
2335
+ { name: "preventOverflow", options: { padding: 16 } },
2336
+ { name: "offset", options: { offset: [0, 12] } }
2337
+ ],
2338
+ children: /* @__PURE__ */ jsx(
2339
+ Button,
2340
+ {
2341
+ variant: "unstyled",
2342
+ minW: "auto",
2343
+ h: "auto",
2344
+ p: 0,
2345
+ lineHeight: "1",
2346
+ color: "inherit",
2347
+ onClick: onCopy,
2348
+ "aria-label": "Copy commit ID",
2349
+ isDisabled: !safeCommit,
2350
+ children: envChip
2351
+ }
2352
+ )
2353
+ }
2354
+ ) }),
2355
+ /* @__PURE__ */ jsx(Text, { fontSize: "2xs", color: "gray.300", flexShrink: 0, children: "|" })
2356
+ ] }) : null,
2357
+ shortCommit ? /* @__PURE__ */ jsx(Text, { fontSize: "2xs", color: hasCopied ? "green.500" : "gray.400", flexShrink: 0, children: shortCommit }) : null,
2358
+ version ? /* @__PURE__ */ jsxs(Fragment, { children: [
2359
+ shortCommit ? /* @__PURE__ */ jsx(Text, { fontSize: "2xs", color: "gray.300", flexShrink: 0, children: "|" }) : null,
2360
+ /* @__PURE__ */ jsxs(Text, { fontSize: "2xs", color: "gray.400", flexShrink: 0, children: [
2361
+ "v",
2362
+ version
2363
+ ] })
2364
+ ] }) : null,
2365
+ onDiagnosticsClick ? /* @__PURE__ */ jsxs(Fragment, { children: [
2366
+ /* @__PURE__ */ jsx(Text, { fontSize: "2xs", color: "gray.300", flexShrink: 0, children: "|" }),
2367
+ /* @__PURE__ */ jsx(Tooltip, { label: "Diagnostics", hasArrow: true, placement: "top", children: /* @__PURE__ */ jsx(
2368
+ Button,
2369
+ {
2370
+ variant: "unstyled",
2371
+ minW: "auto",
2372
+ h: "auto",
2373
+ p: 0,
2374
+ lineHeight: "1",
2375
+ color: "gray.400",
2376
+ _hover: { color: "gray.600" },
2377
+ onClick: (e) => {
2378
+ e.stopPropagation();
2379
+ onDiagnosticsClick();
2380
+ },
2381
+ "aria-label": "Diagnostics",
2382
+ children: /* @__PURE__ */ jsx(Icon, { as: ActivityIcon, boxSize: 3 })
2383
+ }
2384
+ ) })
2385
+ ] }) : null
2386
+ ] }),
2387
+ metaLine ? /* @__PURE__ */ jsxs(Text, { fontSize: "2xs", color: "gray.500", textAlign: "center", whiteSpace: "nowrap", children: [
2388
+ "| ",
2389
+ metaLine,
2390
+ " |"
2391
+ ] }) : null,
2392
+ hasCopied && /* @__PURE__ */ jsx(
2393
+ Box,
2394
+ {
2395
+ position: "absolute",
2396
+ bottom: "100%",
2397
+ mb: "6px",
2398
+ px: "2",
2399
+ py: "1",
2400
+ fontSize: "xs",
2401
+ bg: "gray.700",
2402
+ color: "white",
2403
+ borderRadius: "md",
2404
+ animation: `${copiedAnimation} 0.9s ease-out`,
2405
+ pointerEvents: "none",
2406
+ children: "Copied"
2407
+ }
2408
+ )
2409
+ ]
2410
+ }
2411
+ );
2412
+ }
2181
2413
  function Sidebar({ onClose, id }) {
2182
2414
  const { brandLogoSrc } = useShellChrome();
2183
2415
  const navItems = useShellNavItems()?.items ?? [];
@@ -2310,17 +2542,19 @@ function Sidebar({ onClose, id }) {
2310
2542
  }
2311
2543
  )
2312
2544
  ] }, `${l.label}-${idx}`)) }),
2313
- (footer.version || footer.commit || footer.environmentLabel) && /* @__PURE__ */ jsxs(HStack, { spacing: 2, fontSize: "xs", color: "gray.500", wrap: "wrap", children: [
2314
- footer.environmentLabel ? /* @__PURE__ */ jsx(Text, { fontWeight: "semibold", children: footer.environmentLabel }) : null,
2315
- footer.version ? /* @__PURE__ */ jsxs(Text, { children: [
2316
- "v",
2317
- footer.version
2318
- ] }) : null,
2319
- footer.commit ? /* @__PURE__ */ jsxs(Text, { fontFamily: "mono", children: [
2320
- "#",
2321
- footer.commit.slice(-7)
2322
- ] }) : null
2323
- ] })
2545
+ (footer.version || footer.commit || footer.commitFull || footer.environmentLabel || footer.envNode) && /* @__PURE__ */ jsx(
2546
+ CommitCopyButton,
2547
+ {
2548
+ envNode: footer.envNode,
2549
+ environmentLabel: footer.environmentLabel,
2550
+ commit: footer.commitFull ?? footer.commit,
2551
+ version: footer.version,
2552
+ commitDate: footer.commitDate,
2553
+ commitAuthor: footer.commitAuthor,
2554
+ commitLog: footer.commitLog,
2555
+ onDiagnosticsClick: footer.onDiagnosticsClick
2556
+ }
2557
+ )
2324
2558
  ] })
2325
2559
  }
2326
2560
  )
@@ -2674,7 +2908,8 @@ function ShellChrome({
2674
2908
  onContinueOnboarding,
2675
2909
  pageTitle,
2676
2910
  breadcrumbs,
2677
- headerActions
2911
+ headerActions,
2912
+ userAvatarUrl
2678
2913
  }) {
2679
2914
  const chrome = useMemo(
2680
2915
  () => ({
@@ -2687,7 +2922,8 @@ function ShellChrome({
2687
2922
  onContinueOnboarding,
2688
2923
  pageTitle,
2689
2924
  breadcrumbs,
2690
- headerActions
2925
+ headerActions,
2926
+ userAvatarUrl
2691
2927
  }),
2692
2928
  [
2693
2929
  devNotesMenu,
@@ -2699,7 +2935,8 @@ function ShellChrome({
2699
2935
  onContinueOnboarding,
2700
2936
  pageTitle,
2701
2937
  breadcrumbs,
2702
- headerActions
2938
+ headerActions,
2939
+ userAvatarUrl
2703
2940
  ]
2704
2941
  );
2705
2942
  const navItemsValue = useMemo(
@@ -2739,6 +2976,6 @@ function buildSpeculationRules(currentApp, registry) {
2739
2976
  return JSON.stringify(payload);
2740
2977
  }
2741
2978
 
2742
- export { AppLayout, BrandIcon, BrandLogo, BreadcrumbBar, Card, Footer, GlobalUiIdProvider, Header, HeaderTabBar, ModePill, NavItem, OrgPill, OrgPill as OrgSelector, PageContainer, PageHeader, ShellChrome, ShellChromeContext, ShellFooterContext, ShellLinkedAccountsContext, ShellModeContext, ShellNavItemsContext, ShellNavigationPreferenceContext, ShellOrgContext, ShellProvider, ShellRoleContext, ShellSupportProviderContext, Sidebar, SupportRequestButton, UserMenu, buildSpeculationRules, getOrganizationBadgeLetters, getOrganizationBrandColor, getUserDisplayName, hexToRgba, lightenHexColor, normalizeHexColor, politogyTheme, registerShellPrecache, useAppRegistry, useCurrentApp, useShellAuth, useShellChrome, useShellFooter, useShellLinkedAccounts, useShellMode, useShellNavItems, useShellNavigationPreference, useShellOrganization, useShellRole, useShellSupport };
2979
+ export { AppLayout, BrandIcon, BrandLogo, BreadcrumbBar, Card, CommitCopyButton, Footer, GlobalUiIdProvider, Header, HeaderTabBar, ModePill, NavItem, OrgPill, OrgPill as OrgSelector, PageContainer, PageHeader, ShellChrome, ShellChromeContext, ShellFooterContext, ShellLinkedAccountsContext, ShellModeContext, ShellNavItemsContext, ShellNavigationPreferenceContext, ShellOrgContext, ShellProvider, ShellRoleContext, ShellSupportProviderContext, Sidebar, SupportRequestButton, UserMenu, buildSpeculationRules, getOrganizationBadgeLetters, getOrganizationBrandColor, getUserDisplayName, hexToRgba, lightenHexColor, normalizeHexColor, politogyTheme, registerShellPrecache, useAppRegistry, useCurrentApp, useShellAuth, useShellChrome, useShellFooter, useShellLinkedAccounts, useShellMode, useShellNavItems, useShellNavigationPreference, useShellOrganization, useShellRole, useShellSupport };
2743
2980
  //# sourceMappingURL=index.js.map
2744
2981
  //# sourceMappingURL=index.js.map