Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/app/shell/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,9 @@ export function AppShell({
<IconButton
ref={navigationToggle}
data-shell-sidebar-toggle=""
data-highlight-expanded="false"
type="button"
variant="chrome"
variant="ghost"
shape="round"
aria-label={toggleLabel}
aria-expanded={visibleSidebar}
Expand Down
6 changes: 3 additions & 3 deletions src/app/shell/NavigationControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ export function NavigationControls({ navigation }: { navigation: Navigation }) {
const state = useSyncExternalStore(navigation.subscribe, navigation.snapshot);
return (
<nav
className="flex shrink-0 items-center gap-1"
className="flex shrink-0 items-center gap-2"
aria-label="Navigation history"
>
<IconButton
type="button"
variant="chrome"
variant="ghost"
shape="round"
aria-label="Go back"
title="Go back"
Expand All @@ -24,7 +24,7 @@ export function NavigationControls({ navigation }: { navigation: Navigation }) {
/>
<IconButton
type="button"
variant="chrome"
variant="ghost"
shape="round"
aria-label="Go forward"
title="Go forward"
Expand Down
2 changes: 1 addition & 1 deletion src/app/shell/PageSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export function PageSearch({
<>
<IconButton
ref={trigger}
variant="chrome"
variant="ghost"
shape="round"
aria-label="Search Buzz"
title={`Search Buzz (${shortcut})`}
Expand Down
4 changes: 2 additions & 2 deletions src/app/shell/PanelLaunchers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ export function PanelLaunchers({
launch(panel: RegisteredPanel, trigger: HTMLButtonElement): void;
}) {
return panels
.filter((panel) => panel.launcher)
.filter((panel) => panel.launcher && panel.pluginId !== "buzz.bestie")
.map((panel) => (
<IconButton
type="button"
key={`${panel.key}:${panel.revision}`}
variant="chrome"
variant="ghost"
shape="round"
aria-label={panel.title}
title={panel.title}
Expand Down
82 changes: 74 additions & 8 deletions src/app/shell/ProfileButton.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,26 @@
.triggerAvatar :global(.buzz-avatar) {
background: transparent;
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: Give only the top-bar fallback a visible circular fill. */
.triggerAvatar :global(.buzz-avatar):not(:has(img[data-loaded="true"])) {
background: white;
color: var(--text-avatar-fallback);
}

.profileHeader {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2);
min-width: 15rem;
gap: var(--space-3);
padding: var(--space-2) var(--space-1);
min-width: 0;
max-width: min(20rem, calc(100vw - 3rem));
}
.profileAvatar {
position: relative;
display: flex;
width: 2.75rem;
height: 2.75rem;
flex: 0 0 2.75rem;
width: calc(var(--space-5) * 2);
height: calc(var(--space-5) * 2);
flex: 0 0 calc(var(--space-5) * 2);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: CSS Modules global selector sizes the shared avatar button to this header. */
.profileAvatar :global(.buzz-button) {
Expand All @@ -38,18 +43,79 @@
}
.profileDetails {
display: grid;
gap: var(--space-1);
justify-items: start;
min-width: 0;
}
.profileDetails > p {
max-width: 100%;
}
.availability {
@apply interaction-availability;
@apply interaction-profile-availability;
--radius-capsule: var(--radius-chip);
--text-caption: var(--type-size-12);
--text-caption--font-weight: var(--weight-profile-status);
}
.availability[data-status="online"] {
--text-standard: var(--text-success);
--interaction-fill: color-mix(
in srgb,
var(--availability-color) 6%,
var(--surface-popover)
);
--interaction-hover: color-mix(
in srgb,
var(--availability-color) 10%,
var(--surface-popover)
);
--interaction-pressed: color-mix(
in srgb,
var(--availability-color) 14%,
var(--surface-popover)
);
Comment thread
cynfria marked this conversation as resolved.
}
.statusCard {
--user-status-emoji-offset: -2px;
margin: var(--space-2);
margin: var(--space-3) 0;
background: var(--surface-inset);
border: 1px solid var(--border-standard);
border-radius: var(--radius-control);
}

/* biome-ignore lint/correctness/noUnknownPseudoClass: CSS Modules scopes the profile menu without changing shared menus. */
:global(.buzz-menu-popup[data-profile-menu]) {
--interaction-row-hover: var(--affordance-subtle-hover);
width: 18rem;
padding: var(--space-3);
border-radius: var(--radius-profile-popover);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: Direct profile actions match the compact sidenav rows. */
:global(.buzz-menu-popup[data-profile-menu] > .buzz-menu-item) {
min-height: calc(var(--space-6) + var(--space-1));
gap: var(--space-3);
font-size: var(--text-body);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: The existing status menu item keeps its keyboard behavior. */
.statusCard :global(.buzz-menu-item) {
min-height: calc(var(--space-5) * 2);
padding-inline: var(--space-3);
border-radius: inherit;
color: var(--text-subtle);
font-size: var(--text-body);
}

/* biome-ignore lint/correctness/noUnknownPseudoClass: Scope the portaled availability menu to the profile flow. */
:global(.buzz-menu-popup[data-profile-submenu]) {
--interaction-row-hover: var(--affordance-subtle-hover);
border-radius: var(--radius-profile-popover);
padding: var(--space-2);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: Inset row curves follow the popup corners. */
:global(.buzz-menu-popup[data-profile-submenu] .buzz-menu-item) {
border-radius: var(--radius-control);
padding: var(--space-2) var(--space-3);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: Direct profile rows sit inside the menu's 12px inset. */
:global(.buzz-menu-popup[data-profile-menu] > .buzz-menu-item) {
border-radius: var(--space-2);
}
17 changes: 12 additions & 5 deletions src/app/shell/ProfileButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import {
CircleNotchIcon,
SmileyIcon,
ThumbsUpIcon,
CheckIcon,
GearIcon,
UserIcon,
Expand Down Expand Up @@ -241,6 +242,7 @@ export function ProfileButton({
}
/>
<MenuPopup
data-profile-menu=""
align="end"
sideOffset={8}
aria-labelledby={accountLabel}
Expand Down Expand Up @@ -275,7 +277,7 @@ export function ProfileButton({
)}
</span>
<div className={styles.profileDetails}>
<p className="m-0 truncate text-label-sm">{name}</p>
<p className="m-0 truncate text-body">{name}</p>
{viewer && (
<MenuRoot modal={false}>
<span className={styles.availability} data-status={observed}>
Expand All @@ -300,7 +302,7 @@ export function ProfileButton({
}
/>
</span>
<MenuPopup align="start">
<MenuPopup align="start" data-profile-submenu>
<MenuRadioGroup
value={observed === "unknown" ? "" : observed}
onValueChange={(value) => {
Expand Down Expand Up @@ -388,7 +390,7 @@ export function ProfileButton({
) : (
<>
<MenuIcon>
<SmileyIcon size={17} aria-hidden="true" />
<SmileyIcon size={16} aria-hidden="true" />
</MenuIcon>
{statusEditor.loading
? "Loading status…"
Expand All @@ -415,15 +417,20 @@ export function ProfileButton({
)}
</>
)}
<MenuSeparator />
{actions.map((action) => (
<MenuItem
key={action.key}
onClick={() => setSelectedAction(action)}
>
{action.pluginId === "buzz.feedback" && (
<MenuIcon>
<ThumbsUpIcon size={16} aria-hidden="true" />
</MenuIcon>
)}
{action.title}
</MenuItem>
))}
<MenuSeparator />
<MenuItem
aria-current={settingsSelected ? "page" : undefined}
onClick={() => {
Expand All @@ -432,7 +439,7 @@ export function ProfileButton({
}}
>
<MenuIcon>
<GearIcon aria-hidden="true" size={17} />
<GearIcon aria-hidden="true" size={16} />
</MenuIcon>
Settings
{settingsSelected && (
Expand Down
23 changes: 23 additions & 0 deletions src/features/user-status/Status.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,16 @@
}
.calendarPopup {
@apply floating-surface;
border-radius: var(--radius-profile-popover);
padding: var(--space-2);
}
.timeOptions {
max-height: min(18rem, calc(var(--available-height) - var(--space-4)));
overflow-y: auto;
}
.choices {
display: grid;
padding-block: var(--space-2);
border: 1px solid var(--border-standard);
border-radius: var(--radius-control);
overflow: hidden;
Expand Down Expand Up @@ -102,3 +105,23 @@
max-width: 6rem;
flex-shrink: 0;
}

/* biome-ignore lint/correctness/noUnknownPseudoClass: Status-owned popup portals keep their own scoped geometry. */
:global(.buzz-menu-popup[data-status-menu]) {
--interaction-row-hover: var(--affordance-subtle-hover);
border-radius: var(--radius-profile-popover);
padding: var(--space-2);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: Hover rows fit the popup's inset curve. */
:global(.buzz-menu-popup[data-status-menu] .buzz-menu-item) {
border-radius: var(--radius-control);
}
/* biome-ignore lint/correctness/noUnknownPseudoClass: Identify the status dialog by its owned form. */
:global(.buzz-dialog):has(.fields) {
border-radius: var(--radius-profile-popover);
}

/* biome-ignore lint/correctness/noUnknownPseudoClass: The status editor supplies this ID to its emoji portal. */
:global(.buzz-popover-popup[id^="status-emoji-"]) {
border-radius: var(--radius-profile-popover);
}
4 changes: 2 additions & 2 deletions src/features/user-status/StatusEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function StatusEditor({
const [error, setError] = useState("");
const message = useRef<HTMLInputElement>(null);
const emojiTrigger = useRef<HTMLButtonElement>(null);
const pickerId = useId();
const pickerId = `status-emoji-${useId()}`;
const formId = useId();
const working = useRef(false);
const mounted = useRef(false);
Expand Down Expand Up @@ -203,7 +203,7 @@ export function StatusEditor({
>
{durationLabel}
</MenuTrigger>
<MenuPopup align="end">
<MenuPopup align="end" data-status-menu>
<MenuRadioGroup
value={duration}
onValueChange={(value) => {
Expand Down
2 changes: 1 addition & 1 deletion src/features/user-status/StatusExpiration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export function StatusExpiration({
minute: "2-digit",
})}
</MenuTrigger>
<MenuPopup align="end">
<MenuPopup align="end" data-status-menu>
<div className={styles.timeOptions}>
<MenuRadioGroup
value={time}
Expand Down
3 changes: 3 additions & 0 deletions src/shared/design-system/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,5 +363,8 @@ export const SpeakerSlashIcon = defineIcon(
PhosphorSpeakerSlashIcon,
);

import { ThumbsUpIcon as PhosphorThumbsUpIcon } from "@phosphor-icons/react/dist/csr/ThumbsUp";
export const ThumbsUpIcon = defineIcon("phosphor", PhosphorThumbsUpIcon);

import { ColumnsIcon as PhosphorColumnsIcon } from "@phosphor-icons/react/dist/csr/Columns";
export const ColumnsIcon = defineIcon("phosphor", PhosphorColumnsIcon);
9 changes: 9 additions & 0 deletions src/shared/design-system/styles/materials.css
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,12 @@
@utility interaction-navigation {
--interaction-selected: var(--affordance-selected);
}

/* The profile's compact availability badge retains the shared status colors. */
@utility interaction-profile-availability {
@apply interaction-availability;
&[data-status="online"] .buzz-button {
min-height: var(--space-5);
padding: var(--space-half) var(--space-2);
}
}
5 changes: 5 additions & 0 deletions src/shared/design-system/styles/tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@
--neutral-7: #959595; /* no readers */
--neutral-8: #808080; /* text-disabled */
--neutral-9: #5f5f5f; /* metadata also clears AA on pressed fills */
--neutral-avatar-on-white: #525252; /* Fixed foreground for a fixed white avatar. */
--neutral-10: #525252; /* text-secondary */
--neutral-11: #191919; /* inverse fill, paired with neutral-1 */
--neutral-action-pressed: #525252;
Expand Down Expand Up @@ -713,6 +714,10 @@
/* A chip reads as a chip in running text, so it takes a tighter corner than
a control and gets its own role rather than borrowing one. */
--radius-chip: 0.375rem;
/* Profile refinements: compact popovers and emphasized availability. */
--radius-profile-popover: 1.25rem;
--weight-profile-status: 600;
--text-avatar-fallback: var(--neutral-avatar-on-white);
--duration-fast: var(--time-fast);
--duration-state: var(--time-state);
--duration-panel-enter: var(--time-panel-enter);
Expand Down
Loading
Loading