@xenide-io/the-old-ui-theme 0.6.2 → 0.6.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.
@@ -193,7 +193,9 @@ export function SuiteSidebar({
193
193
  <div
194
194
  className={cn(
195
195
  "flex items-center gap-2",
196
- collapsed ? "flex-col justify-center" : "min-w-0",
196
+ collapsed
197
+ ? "flex-col items-center justify-center [&_[data-test$='-visible-sign-out']]:hidden [&>div]:w-auto"
198
+ : "w-full min-w-0",
197
199
  )}
198
200
  >
199
201
  {renderNode(userMenu, collapsed)}
@@ -38,6 +38,27 @@ function computeInitials(
38
38
  .toUpperCase();
39
39
  }
40
40
 
41
+ /**
42
+ * Deterministic coloured fallback: derives a stable accent from the user's
43
+ * email or name so avatars without a photo get a per-user colour instead of a
44
+ * flat grey. Uses theme `--ph-*` tokens so it adapts to light and dark themes.
45
+ */
46
+ const AVATAR_TOKENS = [
47
+ "bg-ph-brand",
48
+ "bg-ph-violet",
49
+ "bg-ph-info",
50
+ "bg-ph-success",
51
+ "bg-ph-danger",
52
+ ];
53
+
54
+ function avatarColorClass(seed: string): string {
55
+ let hash = 0;
56
+ for (let i = 0; i < seed.length; i += 1) {
57
+ hash = seed.charCodeAt(i) + ((hash << 5) - hash);
58
+ }
59
+ return AVATAR_TOKENS[Math.abs(hash) % AVATAR_TOKENS.length];
60
+ }
61
+
41
62
  /**
42
63
  * Suite account context menu — one tap on the avatar opens a small menu with
43
64
  * profile settings and sign out. Desktop sidebars can also expose the legacy
@@ -58,20 +79,27 @@ export function SuiteUserMenu({
58
79
  }: SuiteUserMenuProps) {
59
80
  const router = useRouter();
60
81
  const initials = fallbackInitials ?? computeInitials(name, email);
82
+ const fallbackColor = avatarColorClass(email || name || "?");
61
83
 
84
+ // Match Tides Avatar `sm` (40px). Colour comes from theme `--ph-*` tokens.
62
85
  const avatar = (
63
- <span className="inline-flex h-11 w-11 items-center justify-center rounded-full ring-2 ring-ph-border ring-offset-1 ring-offset-ph-canvas transition-colors hover:bg-ph-muted">
86
+ <span className="inline-flex h-10 w-10 items-center justify-center overflow-hidden rounded-full border border-ph-border">
64
87
  {image ? (
65
88
  <Image
66
89
  src={image}
67
90
  alt=""
68
91
  width={40}
69
92
  height={40}
70
- className="h-10 w-10 rounded-full object-cover"
93
+ className="h-full w-full object-cover"
71
94
  unoptimized
72
95
  />
73
96
  ) : (
74
- <span className="flex h-10 w-10 items-center justify-center rounded-full bg-ph-muted text-sm font-semibold text-ph-brand">
97
+ <span
98
+ className={cn(
99
+ "flex h-full w-full items-center justify-center text-sm font-semibold text-white",
100
+ fallbackColor,
101
+ )}
102
+ >
75
103
  {initials}
76
104
  </span>
77
105
  )}
@@ -89,7 +117,10 @@ export function SuiteUserMenu({
89
117
  sideOffset={6}
90
118
  collisionPadding={16}
91
119
  modal={false}
92
- className={showSignOutAction ? undefined : className}
120
+ className={cn(
121
+ "[&_.ph-dropdown-trigger]:rounded-full",
122
+ showSignOutAction ? undefined : className,
123
+ )}
93
124
  data-test={dataTest}
94
125
  >
95
126
  <div className="px-2 py-1.5">
@@ -120,14 +151,19 @@ export function SuiteUserMenu({
120
151
  }
121
152
 
122
153
  return (
123
- <div className={cn("flex min-w-0 items-center gap-2", className)}>
124
- {accountMenu}
154
+ <div
155
+ className={cn(
156
+ "flex w-full min-w-0 flex-1 items-center justify-between gap-2",
157
+ className,
158
+ )}
159
+ >
160
+ <div className="shrink-0">{accountMenu}</div>
125
161
  <button
126
162
  type="button"
127
163
  data-test={`${dataTest}-visible-sign-out`}
128
164
  title="Sign out"
129
165
  aria-label="Sign out"
130
- className="inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring"
166
+ className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-ph-mutedtext transition-colors hover:bg-ph-muted hover:text-ph-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ph-focus-ring"
131
167
  onClick={onSignOut}
132
168
  >
133
169
  <LogOut className="h-4 w-4" aria-hidden />
@@ -3,18 +3,17 @@
3
3
  import type { ReactNode } from "react";
4
4
 
5
5
  /**
6
- * Today page content wrapper with a soft themed visual treatment.
7
- * Does not own scrolling — `#main-content` is the scrollport so sticky headers work.
8
- * Glow/clouds are absolute and do not create a nested scrollport.
6
+ * Today page content wrapper. The frame owns scrolling; its decorative layer
7
+ * is sticky so the original glow and clouds stay fixed while content moves.
9
8
  */
10
9
  export function TodayPageFrame({ children }: { children: ReactNode }) {
11
10
  return (
12
11
  <div
13
12
  data-test="today-page"
14
- className="today-page-frame relative flex min-h-0 w-full flex-1 flex-col overflow-x-hidden"
13
+ className="today-page-frame relative flex min-h-0 w-full flex-1 flex-col overflow-x-clip"
15
14
  >
16
15
  <div
17
- className="pointer-events-none absolute inset-0 overflow-hidden"
16
+ className="today-page-frame__backdrop pointer-events-none overflow-hidden"
18
17
  aria-hidden
19
18
  >
20
19
  <div className="today-page-frame__glow absolute inset-0" />