Skip to content

Commit 67d94c8

Browse files
tyler-daneclaude
andauthored
style(web): refine datepicker, week header, and event-form menu styling (#2185)
* style: fix datepicker and header order/styles * style(datepicker): adjust max height * style(web): give event-form datepicker and actions menu a consistent dark surface The event-form actions menu was a white block in the dark app; the grid datepicker popover shared the app background exactly (0 surface contrast, no border) so it read only as a drop shadow. Give both the app's canonical elevated-dark treatment (bg-secondary + border-primary edge + shadow, light text) so they are consistent with the theme and distinguishable from the background. The datepicker edge is a box-shadow ring rather than a border so it does not consume the height-clamped popover and re-clip 6-row months. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2317490 commit 67d94c8

10 files changed

Lines changed: 59 additions & 45 deletions

File tree

packages/web/src/components/Button/Button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const Btn = forwardRef<
1818
{...props}
1919
type={type}
2020
className={classNames(
21-
"c-focus-ring flex cursor-pointer items-center justify-center rounded-[2px]",
21+
"c-focus-ring flex cursor-pointer items-center justify-center rounded-xs",
2222
className,
2323
)}
2424
ref={ref}
@@ -51,7 +51,7 @@ export const SaveButton = forwardRef<
5151
{...props}
5252
aria-disabled={disabled || undefined}
5353
className={classNames(
54-
"c-button-elevated min-w-[158px] px-2 text-text-dark transition-[background-color,color,box-shadow,transform] duration-500 hover:bg-bg-primary hover:text-(--save-button-hover-color)",
54+
"c-button-elevated min-w-39.5 px-2 text-text-dark transition-[background-color,color,box-shadow,transform] duration-500 hover:bg-bg-primary hover:text-(--save-button-hover-color)",
5555
disabled && "pointer-events-none opacity-50",
5656
className,
5757
)}

packages/web/src/components/CalendarHeader/CalendarHeader.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,14 @@ export const CalendarHeader: FC<Props> = ({
6464
<span className="relative text-xl">{label}</span>
6565
</h1>
6666

67-
<TooltipWrapper shortcut="J">
68-
<ArrowButton direction="left" label={prevLabel} onClick={onPrev} />
69-
</TooltipWrapper>
70-
<TooltipWrapper shortcut="K">
71-
<ArrowButton direction="right" label={nextLabel} onClick={onNext} />
72-
</TooltipWrapper>
73-
7467
<div className="z-2 ml-auto flex items-center gap-3 pr-5">
7568
<TodayButton navigateToToday={onToday} isToday={isToday} />
69+
<TooltipWrapper shortcut="J">
70+
<ArrowButton direction="left" label={prevLabel} onClick={onPrev} />
71+
</TooltipWrapper>
72+
<TooltipWrapper shortcut="K">
73+
<ArrowButton direction="right" label={nextLabel} onClick={onNext} />
74+
</TooltipWrapper>
7675
<SelectView />
7776
</div>
7877
</div>

packages/web/src/components/DatePicker/DatePicker.tsx

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { MonthNavButton } from "@web/components/DatePicker/MonthNavButton";
1111
import { ChevronLeftIcon } from "@web/components/Icons/ChevronLeftIcon";
1212
import { ChevronRightIcon } from "@web/components/Icons/ChevronRightIcon";
1313
import { Focusable, INPUT_RESET_CLASSNAME } from "../Focusable/Focusable";
14+
import { CircleIcon } from "../Icons/CircleIcon";
15+
import { TooltipWrapper } from "../Tooltip/TooltipWrapper";
1416

1517
export interface Props extends Omit<ReactDatePickerProps, "autoFocus"> {
1618
animationOnToggle?: boolean;
@@ -49,7 +51,9 @@ export const DatePicker: React.FC<Props> = (datePickerProps) => {
4951
} = datePickerProps;
5052
const resolvedBgColor = bgColor ?? theme.color.bg.primary;
5153
const datePickerStyle: CSSVariables = {
52-
"--date-picker-bg": bgColor ?? "var(--compass-color-bg-primary)",
54+
// Grid (popover) pickers read as an elevated surface a step above the app
55+
// background; the sidebar picker overrides this to transparent in CSS.
56+
"--date-picker-bg": bgColor ?? "var(--compass-color-bg-secondary)",
5357
};
5458
const isDarkBackground = isDark(resolvedBgColor);
5559
const headerColor =
@@ -112,16 +116,7 @@ export const DatePicker: React.FC<Props> = (datePickerProps) => {
112116
headerClassName,
113117
)}
114118
>
115-
<div
116-
className={classNames(
117-
"min-w-0 items-start",
118-
// Grid pickers grow the label so the arrows sit at the right
119-
// edge. The sidebar keeps the label at intrinsic width so the
120-
// month label and nav arrows read as one group on the left,
121-
// clearly separate from the sidebar-close control.
122-
view !== "sidebar" && "flex-1",
123-
)}
124-
>
119+
<div className={classNames("w-16 items-start")}>
125120
<span
126121
className={classNames("relative", monthTextClassName)}
127122
style={{ color: headerColor }}
@@ -160,20 +155,23 @@ export const DatePicker: React.FC<Props> = (datePickerProps) => {
160155
</MonthNavButton>
161156
</div>
162157
{withTodayButton && (
163-
<button
164-
className={classNames(
165-
"relative mr-10 cursor-pointer border-0 bg-transparent px-1.5 text-l hover:brightness-160 hover:transition-[filter] hover:duration-350 hover:ease-out",
166-
currentMonth === selectedMonth && "opacity-0",
167-
)}
168-
onClick={() => {
169-
headerProps.changeMonth(dayjs().month());
170-
headerProps.changeYear(dayjs().year());
171-
}}
172-
style={{ color: "var(--compass-color-text-light)" }}
173-
type="button"
174-
>
175-
Today
176-
</button>
158+
<TooltipWrapper description={currentMonth}>
159+
<button
160+
type="button"
161+
aria-label="Go to this month"
162+
className={classNames(
163+
"flex h-6 w-6 cursor-pointer items-center justify-center rounded-full transition-colors hover:bg-text-lighter/20 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-primary",
164+
currentMonth === selectedMonth && "invisible",
165+
)}
166+
style={{ color: headerColor }}
167+
onClick={() => {
168+
headerProps.changeMonth(dayjs().month());
169+
headerProps.changeYear(dayjs().year());
170+
}}
171+
>
172+
<CircleIcon />
173+
</button>
174+
</TooltipWrapper>
177175
)}
178176
</div>
179177
)}

packages/web/src/components/PlannerSidebar/PlannerMonthPicker/PlannerMonthPicker.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export const PlannerMonthPicker: FC<Props> = ({
8989
selected={focusedDate.toDate()}
9090
shouldCloseOnSelect={false}
9191
view="sidebar"
92-
withTodayButton={false}
92+
withTodayButton={true}
9393
/>
9494
</fieldset>
9595
);

packages/web/src/index.css

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,19 @@
451451
background-color: transparent;
452452
}
453453

454+
/*
455+
* Grid (popover) pickers float over the app at the same darkness as the
456+
* background, so give them a 1px edge + elevation to read as a distinct
457+
* surface. Drawn as a box-shadow ring rather than a border: the popover is
458+
* height-clamped with overflow:hidden (see .calendar--open), and a border-box
459+
* border would eat into that height and re-clip 6-row months.
460+
*/
461+
&:not([data-view="sidebar"]) {
462+
box-shadow:
463+
0 0 0 1px var(--color-border-primary),
464+
0 8px 24px var(--color-shadow-default);
465+
}
466+
454467
& .react-datepicker__month-container {
455468
display: flex;
456469
width: 100%;
@@ -590,7 +603,9 @@
590603
}
591604

592605
&.calendar--open {
593-
height: 230px;
606+
/* Match the month-container height so 6-row months aren't clipped by the
607+
overflow:hidden on .calendar. The two heights must stay in sync. */
608+
height: 240px;
594609
}
595610

596611
&[data-view="sidebar"].calendar--open {

packages/web/src/views/Forms/ActionsMenu/ActionsMenu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export const ActionsMenu: React.FC<ActionsMenuProps> = ({
138138
returnFocus={false}
139139
>
140140
<div
141-
className="flex flex-col gap-2 rounded-sm bg-(--actions-menu-bg) p-2 shadow-[0_4px_8px_rgb(0_0_0/10%)]"
141+
className="flex flex-col gap-1 rounded-sm border border-border-primary bg-(--actions-menu-bg) p-1 shadow-[0_8px_24px_var(--color-shadow-default)]"
142142
ref={refs.setFloating}
143143
style={{
144144
...context.floatingStyles,

packages/web/src/views/Forms/ActionsMenu/MenuItem.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,11 @@ const MenuItem: React.FC<MenuItemProps> = ({
8787
role="menuitem"
8888
tabIndex={tabIndex}
8989
type={type}
90-
className="c-focus-ring flex w-full cursor-pointer items-center gap-2 border-0 bg-(--actions-menu-item-bg) px-2 py-1 text-left text-m text-text-dark hover:[text-shadow:0_0_0.5px_var(--compass-color-text-dark),0_0_0.5px_var(--compass-color-text-dark)]"
91-
style={{ backgroundColor: bgColor }}
90+
className="c-focus-ring flex w-full cursor-pointer items-center gap-2 rounded-xs border-0 bg-(--actions-menu-item-bg) px-2 py-1.5 text-left text-m text-text-light transition-colors hover:bg-text-lighter/10 focus-visible:bg-text-lighter/10"
91+
// Paint the resting background through a CSS variable (not an inline
92+
// background-color) so the hover/focus utilities above can override it;
93+
// an inline background-color would always win over a class.
94+
style={{ "--actions-menu-item-bg": bgColor } as React.CSSProperties}
9295
>
9396
{children}
9497
</button>

packages/web/src/views/Forms/EventForm/DateControlsSection/DateTimeSection/DatePickers/DatePickers.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ export const DatePickers: FC<Props> = ({
179179
<DatePicker
180180
calendarClassName="startDatePicker"
181181
isOpen={isStartDatePickerOpen}
182-
monthTextClassName="text-base"
182+
monthTextClassName="text-medium"
183183
onCalendarClose={closeStartDatePicker}
184184
onCalendarOpen={() => {
185185
setIsStartDatePickerOpen(true);
@@ -206,7 +206,7 @@ export const DatePickers: FC<Props> = ({
206206
<DatePicker
207207
calendarClassName="endDatePicker"
208208
isOpen={isEndDatePickerOpen}
209-
monthTextClassName="text-base"
209+
monthTextClassName="text-medium"
210210
onCalendarClose={closeEndDatePicker}
211211
onCalendarOpen={() => setIsEndDatePickerOpen(true)}
212212
onChange={() => null}

packages/web/src/views/Forms/EventForm/EventForm.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ export const EventForm: React.FC<GridEventFormProps> = memo(
544544
}
545545
actions={
546546
<EventActionMenu
547-
bgColor="var(--color-menu-bg)"
547+
bgColor="var(--color-bg-secondary)"
548548
isExistingEvent={isExistingEvent}
549549
isReadOnly={isReadOnly}
550550
onDuplicate={onDuplicateEvent}

packages/web/src/views/Forms/EventFormShell.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ interface EventFormShellProps extends ComponentPropsWithoutRef<"form"> {
77

88
/**
99
* Outer `<form>` for the event form. Transparent full-height flex column so
10-
* the sidebar's own background shows through — the form is part of the
11-
* sidebar, not a card floating on it. Children own scrolling and padding
10+
* the sidebar's own background shows through. Children own scrolling and padding
1211
* (EventForm renders a scrollable body plus a pinned footer). The
13-
* (resizable) sidebar width is the single source of the form's size.
12+
* resizable sidebar width is the single source of the form's size.
1413
* Content-agnostic: callers pass their fields as children and any
1514
* form-specific props (`name`, mouse handlers, an extra `className`).
1615
*/

0 commit comments

Comments
 (0)