@the-portland-company/shell 0.16.3 → 0.16.5

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/native.cjs CHANGED
@@ -1225,8 +1225,11 @@ function NavTopBar({
1225
1225
  actions,
1226
1226
  themeToggle
1227
1227
  }) {
1228
- const initials = (user?.name ?? "Politogy").slice(0, 2).toUpperCase();
1229
- const secondary = user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
1228
+ const rawName = user?.name?.trim() || "";
1229
+ const hasRealName = rawName.length > 0 && !rawName.includes("@");
1230
+ const displayName = hasRealName ? formatFirstLast(rawName) : user?.email ?? "Signed in";
1231
+ const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
1232
+ const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
1230
1233
  return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "sticky top-0 z-20 flex h-20 items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-4 backdrop-blur-xl", children: [
1231
1234
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
1232
1235
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1239,15 +1242,22 @@ function NavTopBar({
1239
1242
  ),
1240
1243
  subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm text-[color:var(--muted)]", children: subtitle }) : null
1241
1244
  ] }),
1242
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
1245
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
1243
1246
  actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsxRuntime.jsx(NavTopBarActionButton, { action }, action.key)) : null,
1244
1247
  actions,
1245
1248
  themeToggle,
1246
1249
  /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "group/acct relative", children: [
1247
1250
  /* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "group/tbtip relative flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden", children: [
1248
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)] items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-xs font-bold text-white", children: user?.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: user.avatarUrl, alt: "", className: "h-full w-full object-cover" }) : initials }),
1251
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)] items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-xs font-bold text-white", children: user?.avatarUrl || user?.memojiUrl ? /* @__PURE__ */ jsxRuntime.jsx(
1252
+ "img",
1253
+ {
1254
+ src: user.avatarUrl || user.memojiUrl,
1255
+ alt: "",
1256
+ className: "h-full w-full object-cover"
1257
+ }
1258
+ ) : initials }),
1249
1259
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "hidden flex-col leading-tight md:flex", children: [
1250
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-[color:var(--foreground)]", children: user?.name ?? "Signed in" }),
1260
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold text-[color:var(--foreground)]", children: displayName }),
1251
1261
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-[color:var(--muted)]", children: secondary })
1252
1262
  ] }),
1253
1263
  /* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {}),
@@ -1256,7 +1266,7 @@ function NavTopBar({
1256
1266
  {
1257
1267
  title: "My Account",
1258
1268
  description: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1259
- user?.name ?? "Signed in",
1269
+ hasRealName ? rawName : user?.email ?? "Signed in",
1260
1270
  user?.email ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1261
1271
  /* @__PURE__ */ jsxRuntime.jsx("br", {}),
1262
1272
  user.email
@@ -1384,10 +1394,64 @@ function NavTopBar({
1384
1394
  }
1385
1395
  ) : null
1386
1396
  ] })
1387
- ] })
1397
+ ] }),
1398
+ !hasRealName && user ? /* @__PURE__ */ jsxRuntime.jsx(NamePromptBubble, { profileHref: userMenu?.myProfileHref }) : null
1388
1399
  ] })
1389
1400
  ] });
1390
1401
  }
1402
+ function NamePromptBubble({ profileHref }) {
1403
+ const KEY = "politogy_name_prompt_dismissed";
1404
+ const [dismissed, setDismissed] = react.useState(true);
1405
+ react.useEffect(() => {
1406
+ try {
1407
+ setDismissed(sessionStorage.getItem(KEY) === "1");
1408
+ } catch {
1409
+ setDismissed(false);
1410
+ }
1411
+ }, []);
1412
+ if (dismissed) return null;
1413
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-4 top-full z-30 mt-2 w-64 rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] p-3 shadow-[var(--shadow-soft)]", children: [
1414
+ /* @__PURE__ */ jsxRuntime.jsx(
1415
+ "span",
1416
+ {
1417
+ "aria-hidden": true,
1418
+ className: "absolute -top-[5px] right-[11px] h-2.5 w-2.5 rotate-45 border-l border-t border-[color:var(--line)] bg-[color:var(--panel-elevated)]"
1419
+ }
1420
+ ),
1421
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-[color:var(--foreground)]", children: "Add your name" }),
1422
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs leading-snug text-[color:var(--muted)]", children: "Set your first and last name so teammates see you \u2014 not your email." }),
1423
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
1424
+ profileHref ? /* @__PURE__ */ jsxRuntime.jsx(
1425
+ "a",
1426
+ {
1427
+ href: safeHref(profileHref),
1428
+ className: "rounded-full bg-[color:var(--color-race-red)] px-3 py-1 text-xs font-semibold text-white hover:opacity-90",
1429
+ children: "Set name"
1430
+ }
1431
+ ) : null,
1432
+ /* @__PURE__ */ jsxRuntime.jsx(
1433
+ "button",
1434
+ {
1435
+ type: "button",
1436
+ onClick: () => {
1437
+ setDismissed(true);
1438
+ try {
1439
+ sessionStorage.setItem(KEY, "1");
1440
+ } catch {
1441
+ }
1442
+ },
1443
+ className: "rounded-full border border-[color:var(--line)] px-3 py-1 text-xs font-semibold text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
1444
+ children: "Dismiss"
1445
+ }
1446
+ )
1447
+ ] })
1448
+ ] });
1449
+ }
1450
+ function formatFirstLast(name) {
1451
+ const parts = name.split(/\s+/).filter(Boolean);
1452
+ if (parts.length === 1) return parts[0];
1453
+ return `${parts[0]} ${parts[parts.length - 1][0].toUpperCase()}.`;
1454
+ }
1391
1455
  function ProfileIcon() {
1392
1456
  return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: 16, height: 16, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [
1393
1457
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),