From 533aad6dd03cb31bcf089bbdfb3f3121a05bede1 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Mon, 9 Dec 2024 20:50:59 +0800 Subject: [PATCH 1/7] [CCUBE-1626][MAHI|RL] Update calendar wrapper --- src/calendar/calendar.tsx | 6 +++--- .../internal-calendar/calendar-dropdown.style.tsx | 4 ++-- .../internal-calendar/calendar-manager.style.tsx | 14 +++++++------- .../internal-calendar/internal-calendar.style.tsx | 10 +++++----- src/shared/internal-calendar/internal-calendar.tsx | 2 +- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/calendar/calendar.tsx b/src/calendar/calendar.tsx index 555ebca6e..b30084e95 100644 --- a/src/calendar/calendar.tsx +++ b/src/calendar/calendar.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import styled, { css } from "styled-components"; -import { V2_Color } from "../v2_color"; import { InternalCalendar } from "../shared/internal-calendar"; +import { Border, Colour, Radius } from "../theme"; import { CalendarProps } from "./types"; export const Calendar = ({ @@ -58,8 +58,8 @@ const Wrapper = styled.div` ${(props) => { if (props.$hasBorder) { return css` - border: 1px solid ${V2_Color.Neutral[5](props)}; - border-radius: 12px; + border: ${Border["width-010"]} ${Border.solid} ${Colour.border}; + border-radius: ${Radius.lg}; overflow: hidden; `; } diff --git a/src/shared/internal-calendar/calendar-dropdown.style.tsx b/src/shared/internal-calendar/calendar-dropdown.style.tsx index f3b517f8f..5131db235 100644 --- a/src/shared/internal-calendar/calendar-dropdown.style.tsx +++ b/src/shared/internal-calendar/calendar-dropdown.style.tsx @@ -1,5 +1,5 @@ import styled from "styled-components"; -import { V2_MediaQuery } from "../../v2_media"; +import { MediaQuery } from "../../theme"; // ============================================================================= // STYLE INTERFACE @@ -16,7 +16,7 @@ export const CalendarWrapper = styled.div` max-width: 41rem; min-width: 21rem; - ${V2_MediaQuery.MaxWidth.mobileL} { + ${MediaQuery.MaxWidth.sm} { min-width: 17.5rem; } `; diff --git a/src/shared/internal-calendar/calendar-manager.style.tsx b/src/shared/internal-calendar/calendar-manager.style.tsx index 680bbd7b3..543b86cca 100644 --- a/src/shared/internal-calendar/calendar-manager.style.tsx +++ b/src/shared/internal-calendar/calendar-manager.style.tsx @@ -3,8 +3,7 @@ import { ChevronLeftIcon } from "@lifesg/react-icons/chevron-left"; import { ChevronRightIcon } from "@lifesg/react-icons/chevron-right"; import styled, { css } from "styled-components"; import { Button } from "../../button"; -import { V2_Color } from "../../v2_color"; -import { V2_TextStyleHelper } from "../../v2_text"; +import { Colour, Font } from "../../theme"; import { ClickableIcon } from "../clickable-icon"; // ============================================================================= @@ -26,7 +25,7 @@ interface OverlayStyleProps { // ICONS // ----------------------------------------------------------------------------- const iconStyle = css` - color: ${V2_Color.Neutral[3]}; + color: ${Colour.icon}; height: 1rem; width: 1rem; `; @@ -72,7 +71,7 @@ export const OptionsOverlay = styled.div` left: 0; height: 100%; width: 100%; - background: ${V2_Color.Neutral[8]}; + background: ${Colour.bg}; ${(props) => { if (!props.$visible) { @@ -118,11 +117,12 @@ export const DropdownButton = styled.button` } `; } - }} + }}; `; -export const DropdownText = styled.p` - ${V2_TextStyleHelper.getTextStyle("H5", "regular")} +export const DropdownText = styled.span` + ${Font["body-md-regular"]} + color: ${Colour["text"]}; `; export const HeaderArrows = styled.div` diff --git a/src/shared/internal-calendar/internal-calendar.style.tsx b/src/shared/internal-calendar/internal-calendar.style.tsx index 14aeb4aa3..ca357c6c9 100644 --- a/src/shared/internal-calendar/internal-calendar.style.tsx +++ b/src/shared/internal-calendar/internal-calendar.style.tsx @@ -1,5 +1,5 @@ import styled, { css } from "styled-components"; -import { V2_Color } from "../../v2_color"; +import { Border, Colour, Radius } from "../../theme"; import { CalendarType } from "./types"; // ============================================================================= @@ -15,17 +15,17 @@ interface GeneralStyleProps { export const Container = styled.div` width: 100%; padding: 1.5rem 2rem; - background: ${V2_Color.Neutral[8]}; + background: ${Colour.bg}; ${(props) => { if (props.$type === "input") { return css` - border: 1px solid ${V2_Color.Neutral[5]}; - border-radius: 8px; + border: ${Border["width-010"]} ${Border.solid} ${Colour.border}; + border-radius: ${Radius["lg"]}; overflow: hidden; padding: 1.5rem 1.25rem; - [data-id="header"] { + [data-id="calendar-header"] { margin: 0 0 0.25rem 0; } `; diff --git a/src/shared/internal-calendar/internal-calendar.tsx b/src/shared/internal-calendar/internal-calendar.tsx index e31a39439..c5a25e8bb 100644 --- a/src/shared/internal-calendar/internal-calendar.tsx +++ b/src/shared/internal-calendar/internal-calendar.tsx @@ -1,7 +1,7 @@ import { Dayjs } from "dayjs"; import React, { useImperativeHandle, useRef } from "react"; import { CalendarManager } from "./calendar-manager"; -import { FixedRangeCalendarDayView } from "./fixed-range/fixed-range-calendar-day-view"; +import { FixedRangeCalendarDayView } from "./fixed-range"; import { Container } from "./internal-calendar.style"; import { StandardCalendarDayView } from "./standard"; import { From 1d91386f8a6ee4702ba8111bcdfdddfd4c709ec9 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Mon, 9 Dec 2024 21:55:40 +0800 Subject: [PATCH 2/7] [CCUBE-1626][MAHI|RL] Update month and year styles --- .../internal-calendar-month.style.tsx | 103 +++++++++------ .../internal-calendar-month.tsx | 10 +- .../internal-calendar-year.style.tsx | 121 +++++++++++------- .../internal-calendar-year.tsx | 11 +- 4 files changed, 140 insertions(+), 105 deletions(-) diff --git a/src/shared/internal-calendar/internal-calendar-month.style.tsx b/src/shared/internal-calendar/internal-calendar-month.style.tsx index bd7cda5d2..1ab7052a8 100644 --- a/src/shared/internal-calendar/internal-calendar-month.style.tsx +++ b/src/shared/internal-calendar/internal-calendar-month.style.tsx @@ -1,7 +1,5 @@ import styled, { css } from "styled-components"; -import { V2_Color } from "../../v2_color"; -import { V2_TextStyleHelper } from "../../v2_text/helper"; -import { V2_Text } from "../../v2_text/text"; +import { Border, Colour, Font, FontSpec, Motion, Radius } from "../../theme"; import { MonthVariant } from "./internal-calendar-month"; import { CalendarType } from "./types"; @@ -49,18 +47,23 @@ export const MonthCell = styled.div` display: flex; align-items: center; justify-content: center; - cursor: default; - border-radius: 5rem; + border-radius: ${Radius.md}; margin: 0 0.5rem; + transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; + + // default styles + ${Font["body-md-regular"]} + border-radius: ${Radius.md}; + border: ${Border["width-010"]} ${Border.solid} transparent; + background-clip: border-box; + color: ${Colour["text"]}; + cursor: default; + // cursor style ${(props) => { if (props.$interactive) { return css` cursor: pointer; - &:hover { - box-shadow: 0px 0px 4px 1px ${V2_Color.Shadow.Accent}; - border: 1px solid ${V2_Color.Accent.Light[1]}; - } `; } if (props.$disabledDisplay) { @@ -70,43 +73,63 @@ export const MonthCell = styled.div` } }} - ${(props) => { - switch (props.$variant) { - case "current-month": - return css` - background-color: ${V2_Color.Accent.Light[6](props)}; - `; - case "selected-month": - return css` - background-color: ${V2_Color.Accent.Light[5](props)}; - border: 1px solid ${V2_Color.Primary(props)}; - `; - case "default": - break; + // background, border and text styles + ${({ $variant, $interactive, $disabledDisplay }) => { + if ($variant === "selected-month") { + return css` + background: ${Colour["bg-selected"]}; + border-color: ${Colour["border-selected"]}; + color: ${Colour["text-selected"]}; + font-weight: ${FontSpec["weight-semibold"]}; + + ${$interactive && + css` + &:hover { + background: ${Colour["bg-selected-hover"]}; + border-color: ${Colour["border-selected-hover"]}; + color: ${Colour["text-selected-hover"]}; + } + `} + `; } - }} -`; -export const CellLabel = styled(V2_Text.H5)` - ${(props) => { - if (props.$disabledDisplay) { + if ($variant === "current-month") { return css` - color: ${V2_Color.Neutral[4]}; + color: ${Colour["text-primary"]}; + font-weight: ${FontSpec["weight-semibold"]}; `; } - switch (props.$variant) { - case "current-month": - return css` - color: ${V2_Color.Neutral[3](props)}; - `; - case "selected-month": - return css` - ${V2_TextStyleHelper.getTextStyle("H5", "semibold")} - color: ${V2_Color.Primary(props)}; - `; - case "default": - break; + if ($disabledDisplay) { + return css` + color: ${Colour["text-disabled-subtlest"]}; + `; + } + }} + + // hover styles + ${({ $variant, $interactive }) => { + if (!$interactive) { + return; + } + + if ($variant === "selected-month") { + return css` + &:hover { + background: ${Colour["bg-selected-hover"]}; + border-color: ${Colour["border-selected-hover"]}; + color: ${Colour["text-selected-hover"]}; + font-weight: ${FontSpec["weight-semibold"]}; + } + `; } + + return css` + &:hover { + background: ${Colour["bg-hover"]}; + color: ${Colour["text-hover"]}; + font-weight: ${FontSpec["weight-semibold"]}; + } + `; }} `; diff --git a/src/shared/internal-calendar/internal-calendar-month.tsx b/src/shared/internal-calendar/internal-calendar-month.tsx index 23bbda720..d336db13e 100644 --- a/src/shared/internal-calendar/internal-calendar-month.tsx +++ b/src/shared/internal-calendar/internal-calendar-month.tsx @@ -1,7 +1,7 @@ import dayjs, { Dayjs } from "dayjs"; import { useMemo } from "react"; import { CalendarHelper } from "../../util/calendar-helper"; -import { CellLabel, MonthCell, Wrapper } from "./internal-calendar-month.style"; +import { MonthCell, Wrapper } from "./internal-calendar-month.style"; import { FocusType, InternalCalendarProps } from "./types"; export type MonthVariant = "default" | "current-month" | "selected-month"; @@ -117,13 +117,7 @@ export const InternalCalendarMonth = ({ $interactive={interactive} onClick={() => handleMonthClick(date, !interactive)} > - - {month} - + {month} ); })} diff --git a/src/shared/internal-calendar/internal-calendar-year.style.tsx b/src/shared/internal-calendar/internal-calendar-year.style.tsx index 2a0cd25ca..e468e7230 100644 --- a/src/shared/internal-calendar/internal-calendar-year.style.tsx +++ b/src/shared/internal-calendar/internal-calendar-year.style.tsx @@ -1,7 +1,5 @@ import styled, { css } from "styled-components"; -import { V2_Color } from "../../v2_color"; -import { V2_TextStyleHelper } from "../../v2_text/helper"; -import { V2_Text } from "../../v2_text/text"; +import { Border, Colour, Font, FontSpec, Motion, Radius } from "../../theme"; import { YearVariant } from "./internal-calendar-year"; import { CalendarType } from "./types"; @@ -27,6 +25,7 @@ export const Wrapper = styled.div` height: 100%; display: grid; align-content: center; + align-items: center; grid-template-columns: repeat(3, 1fr); ${(props) => { @@ -49,70 +48,96 @@ export const YearCell = styled.div` display: flex; justify-content: center; align-items: center; - cursor: default; - border-radius: 0.5rem; margin: 0 0.5rem; + transition: ${Motion["duration-150"]} ${Motion["ease-default"]}; + padding: 0.5rem; - ${(props) => { - if (props.$interactive) { + // default styles + ${Font["body-md-regular"]} + border-radius: ${Radius.md}; + border: ${Border["width-010"]} ${Border.solid} transparent; + background-clip: border-box; + color: ${Colour["text"]}; + cursor: default; + + // cursor style + ${({ $interactive, $disabledDisplay }) => { + if ($interactive) { return css` cursor: pointer; - &:hover { - box-shadow: 0px 0px 4px 1px ${V2_Color.Shadow.Accent}; - border: 1px solid ${V2_Color.Accent.Light[1]}; - } `; } - if (props.$disabledDisplay) { + if ($disabledDisplay) { return css` cursor: not-allowed; `; } }} - ${(props) => { - switch (props.$variant) { - case "current-year": - return css` - background: ${V2_Color.Accent.Light[6](props)}; - `; - case "selected-year": - return css` - background: ${V2_Color.Accent.Light[5](props)}; - border: 1px solid ${V2_Color.Primary(props)}; - `; - case "other-decade": - case "default": - break; + // background, border and text styles + ${({ $variant, $interactive, $disabledDisplay }) => { + if ($variant === "selected-year") { + return css` + background: ${Colour["bg-selected"]}; + border-color: ${Colour["border-selected"]}; + color: ${Colour["text-selected"]}; + font-weight: ${FontSpec["weight-semibold"]}; + + ${$interactive && + css` + &:hover { + background: ${Colour["bg-selected-hover"]}; + border-color: ${Colour["border-selected-hover"]}; + color: ${Colour["text-selected-hover"]}; + } + `} + `; } - }}; -`; -export const CellLabel = styled(V2_Text.H5)` - ${(props) => { - if (props.$disabledDisplay) { + if ($variant === "current-year") { return css` - color: ${V2_Color.Neutral[4]}; + color: ${Colour["text-primary"]}; + font-weight: ${FontSpec["weight-semibold"]}; `; } - switch (props.$variant) { - case "current-year": - return css` - color: ${V2_Color.Neutral[3](props)}; - `; - case "selected-year": - return css` - ${V2_TextStyleHelper.getTextStyle("H5", "semibold")} - color: ${V2_Color.Primary(props)}; - `; - case "other-decade": - return css` - color: ${V2_Color.Neutral[4](props)}; - `; - case "default": - break; + if ($variant === "other-decade") { + return css` + color: ${Colour["text-disabled-subtlest"]}; + `; } + + if ($disabledDisplay) { + return css` + color: ${Colour["text-disabled-subtlest"]}; + `; + } + }} + + // hover styles + ${({ $variant, $interactive }) => { + if (!$interactive) { + return; + } + + if ($variant === "selected-year") { + return css` + &:hover { + background: ${Colour["bg-selected-hover"]}; + border-color: ${Colour["border-selected-hover"]}; + color: ${Colour["text-selected-hover"]}; + font-weight: ${FontSpec["weight-semibold"]}; + } + `; + } + + return css` + &:hover { + background: ${Colour["bg-hover"]}; + color: ${Colour["text-hover"]}; + font-weight: ${FontSpec["weight-semibold"]}; + } + `; }} `; diff --git a/src/shared/internal-calendar/internal-calendar-year.tsx b/src/shared/internal-calendar/internal-calendar-year.tsx index d4daa0aae..91fe7f7bc 100644 --- a/src/shared/internal-calendar/internal-calendar-year.tsx +++ b/src/shared/internal-calendar/internal-calendar-year.tsx @@ -1,7 +1,7 @@ import dayjs, { Dayjs } from "dayjs"; import { useMemo } from "react"; import { CalendarHelper } from "../../util/calendar-helper"; -import { CellLabel, Wrapper, YearCell } from "./internal-calendar-year.style"; +import { Wrapper, YearCell } from "./internal-calendar-year.style"; import { FocusType, InternalCalendarProps } from "./types"; export type YearVariant = @@ -126,14 +126,7 @@ export const InternalCalendarYear = ({ $interactive={interactive} onClick={() => handleYearClick(date, !interactive)} > - - {year} - + {year} ); })} From eb095c3c70c88ca40d3edec89b673de7e54fe35c Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Mon, 9 Dec 2024 22:01:21 +0800 Subject: [PATCH 3/7] [CCUBE-1626][MAHI|RL] Remove shadows from calendar day cell --- .../day-cell/day-cell.style.tsx | 38 ------------------- .../internal-calendar/day-cell/day-cell.tsx | 20 ++-------- .../internal-calendar/day-cell/types.tsx | 2 - .../fixed-range/fixed-range-cell.tsx | 1 - .../standard/standard-cell.tsx | 2 - .../internal-calendar/week/week-day-cell.tsx | 2 - .../time-slot-bar-week-days.tsx | 1 - 7 files changed, 4 insertions(+), 62 deletions(-) diff --git a/src/shared/internal-calendar/day-cell/day-cell.style.tsx b/src/shared/internal-calendar/day-cell/day-cell.style.tsx index eb22ae187..c84971abb 100644 --- a/src/shared/internal-calendar/day-cell/day-cell.style.tsx +++ b/src/shared/internal-calendar/day-cell/day-cell.style.tsx @@ -8,7 +8,6 @@ import { CellType, LabelType } from "./types"; // ============================================================================= interface StyleProps { $type?: CellType; - $shadow?: boolean; } interface LabelStyleProps { @@ -96,25 +95,6 @@ export const RightHalf = styled(Half)` right: 0; `; -const HalfShadow = styled.div` - z-index: -1; - box-shadow: 0 0 4px 1px ${V2_Color.Shadow.Accent}; - position: absolute; - height: 100%; - width: 50%; - display: none; - - ${(props) => props.$shadow && "display: block;"} -`; - -export const LeftHalfShadow = styled(HalfShadow)` - left: 0; -`; - -export const RightHalfShadow = styled(HalfShadow)` - right: 0; -`; - export const Circle = styled.div` position: absolute; z-index: 1; @@ -138,34 +118,16 @@ export const Circle = styled.div` `; } }} - - ${(props) => - props.$shadow && - css` - &:before { - content: ""; - border-radius: 50%; - position: absolute; - height: 100%; - width: 100%; - } - `} `; export const LeftCircle = styled(Circle)` right: calc(50% - 1.25rem); clip-path: inset(-3px 1.25rem -3px -3px); - &:before { - box-shadow: -1px 0 4px 1px ${V2_Color.Shadow.Accent}; - } `; export const RightCircle = styled(Circle)` left: calc(50% - 1.25rem); clip-path: inset(-3px -3px -3px 1.25rem); - &:before { - box-shadow: 1px 0 4px 1px ${V2_Color.Shadow.Accent}; - } `; export const Label = styled(V2_Text.H5)` diff --git a/src/shared/internal-calendar/day-cell/day-cell.tsx b/src/shared/internal-calendar/day-cell/day-cell.tsx index 9bc1f1dad..be386ee90 100644 --- a/src/shared/internal-calendar/day-cell/day-cell.tsx +++ b/src/shared/internal-calendar/day-cell/day-cell.tsx @@ -3,10 +3,8 @@ import { Label, LeftCircle, LeftHalf, - LeftHalfShadow, RightCircle, RightHalf, - RightHalfShadow, } from "./day-cell.style"; import { DayCellProps } from "./types"; @@ -15,8 +13,6 @@ export const DayCell = ({ bgRight, circleLeft, circleRight, - shadow, - circleShadow, labelType, disabled, interactive, @@ -45,18 +41,10 @@ export const DayCell = ({ // ========================================================================= return ( - - - - - - + + + + ); diff --git a/src/shared/internal-calendar/day-cell/types.tsx b/src/shared/internal-calendar/day-cell/types.tsx index 537847754..fbc86ea60 100644 --- a/src/shared/internal-calendar/day-cell/types.tsx +++ b/src/shared/internal-calendar/day-cell/types.tsx @@ -1,19 +1,21 @@ import { Dayjs } from "dayjs"; export type CellType = - | "current" - | "selected" + | "hover-subtle" + | "hover" + | "hover-outline" | "selected-outline" - | "overlap" - | "overlap-outline" - | "hover-dash" - | "hover-current"; + | "selected-outline-subtle" + | "selected-hover" + | "selected-hover-outline"; export type LabelType = | "available" | "unavailable" | "current" + | "hover" | "selected" + | "selected-hover" | "hidden"; export interface CellStyleProps { @@ -24,6 +26,7 @@ export interface CellStyleProps { labelType?: LabelType | undefined; disabled?: boolean | undefined; interactive?: boolean | null | undefined; + currentDateIndicator?: boolean | undefined; } export interface DayCellProps extends CellStyleProps { diff --git a/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx b/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx index dc8dd18c4..b8b135ba5 100644 --- a/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx +++ b/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx @@ -1,6 +1,6 @@ import dayjs, { Dayjs } from "dayjs"; import { useMemo, useState } from "react"; -import { V2_Text } from "../../../v2_text/text"; +import { Typography } from "../../../typography"; import { CalendarHelper } from "../../../util/calendar-helper"; import { HeaderCell, RowDayCell, Wrapper } from "../standard"; import { CommonCalendarProps } from "../types"; @@ -64,9 +64,9 @@ export const FixedRangeCalendarDayView = ({ const renderHeader = () => { return weeksOfTheMonth[0].map((day, index) => ( - + {dayjs(day).format("ddd")} - + )); }; diff --git a/src/shared/internal-calendar/fixed-range/fixed-range-cell.tsx b/src/shared/internal-calendar/fixed-range/fixed-range-cell.tsx index b17583839..ef46d73f4 100644 --- a/src/shared/internal-calendar/fixed-range/fixed-range-cell.tsx +++ b/src/shared/internal-calendar/fixed-range/fixed-range-cell.tsx @@ -104,7 +104,7 @@ export const FixedRangeDayCell = ({ if (isHover) { applyRange( props, - "hover-dash", + "hover", formattedDate === hoverStart, formattedDate === hoverEnd ); @@ -112,31 +112,16 @@ export const FixedRangeDayCell = ({ if (isSelected) { applyRange( props, - "selected", + "selected-outline", formattedDate === rangeStart, formattedDate === rangeEnd ); } if (isSelected && isHover) { - applyRange(props, "overlap", isStart, isEnd); - } - - if (formattedDate === rangeStart) { - if (isHover) { - props.circleLeft = "overlap-outline"; - props.circleRight = "overlap-outline"; - } else { - props.circleRight = "selected-outline"; - props.circleLeft = "selected-outline"; - } - } + applyRange(props, "selected-hover-outline", isStart, isEnd); - if (formattedDate === hoverStart) { - props.circleLeft = "hover-current"; - props.circleRight = "hover-current"; - if (hoverStart >= rangeStart && hoverStart < rangeEnd) { - props.circleLeft = "overlap-outline"; - props.circleRight = "overlap-outline"; + if (formattedDate === hoverStart && formattedDate !== rangeStart) { + props.circleLeft = "selected-hover"; } } @@ -152,8 +137,6 @@ export const FixedRangeDayCell = ({ props.labelType = "unavailable"; } else if (dayjs().isSame(date, "day") && !disabled) { props.labelType = "current"; - props.circleLeft = "current"; - props.circleRight = "current"; } return props; @@ -168,6 +151,7 @@ export const FixedRangeDayCell = ({ calendarDate, disabled, interactive, + currentDateIndicator: true, onSelect: handleSelect, onHover: handleHover, }; diff --git a/src/shared/internal-calendar/internal-calendar.tsx b/src/shared/internal-calendar/internal-calendar.tsx index c5a25e8bb..5aba93cfc 100644 --- a/src/shared/internal-calendar/internal-calendar.tsx +++ b/src/shared/internal-calendar/internal-calendar.tsx @@ -3,6 +3,7 @@ import React, { useImperativeHandle, useRef } from "react"; import { CalendarManager } from "./calendar-manager"; import { FixedRangeCalendarDayView } from "./fixed-range"; import { Container } from "./internal-calendar.style"; +import { SingleCalendarDayView } from "./single"; import { StandardCalendarDayView } from "./standard"; import { CalendarManagerRef, @@ -159,6 +160,19 @@ export const Component = ( /> ); case "single": + return ( + + ); case "range": default: // standalone type return ( diff --git a/src/shared/internal-calendar/single/index.ts b/src/shared/internal-calendar/single/index.ts new file mode 100644 index 000000000..adcf1df79 --- /dev/null +++ b/src/shared/internal-calendar/single/index.ts @@ -0,0 +1,2 @@ +export * from "./single-calendar-day-view"; +export * from "./single-calendar-day-view.style"; diff --git a/src/shared/internal-calendar/single/single-calendar-day-view.style.tsx b/src/shared/internal-calendar/single/single-calendar-day-view.style.tsx new file mode 100644 index 000000000..8081d620b --- /dev/null +++ b/src/shared/internal-calendar/single/single-calendar-day-view.style.tsx @@ -0,0 +1,22 @@ +import styled from "styled-components"; + +export const Wrapper = styled.div` + width: 100%; + display: grid; + grid-template-columns: repeat(7, 1fr); + row-gap: 0.25rem; +`; + +export const HeaderCell = styled.div` + display: flex; + align-items: center; + justify-content: center; + height: 2.5rem; + pointer-events: none; + user-select: none; +`; + +export const RowDayCell = styled.div` + grid-column: 1 / -1; + display: flex; +`; diff --git a/src/shared/internal-calendar/single/single-calendar-day-view.tsx b/src/shared/internal-calendar/single/single-calendar-day-view.tsx new file mode 100644 index 000000000..fab6f558e --- /dev/null +++ b/src/shared/internal-calendar/single/single-calendar-day-view.tsx @@ -0,0 +1,115 @@ +import dayjs, { Dayjs } from "dayjs"; +import isBetween from "dayjs/plugin/isBetween"; +import { useMemo, useState } from "react"; +import { Typography } from "../../../typography"; +import { CalendarHelper } from "../../../util/calendar-helper"; +import { CommonCalendarProps } from "../types"; +import { + HeaderCell, + RowDayCell, + Wrapper, +} from "./single-calendar-day-view.style"; +import { SingleCell } from "./single-cell"; + +dayjs.extend(isBetween); + +// TODO: to remove after all references have been cleaned up +export type DayVariant = "default" | "other-month" | "today"; + +interface CalendarDayViewProps extends CommonCalendarProps { + selectedDate: string; + calendarDate: Dayjs; + onSelect: (value: Dayjs) => void; + onHover: (value: string) => void; +} + +export const SingleCalendarDayView = ({ + calendarDate, + disabledDates, + selectedDate, + onSelect, + onHover, + minDate, + maxDate, + allowDisabledSelection, + showActiveMonthDaysOnly, +}: CalendarDayViewProps) => { + // ============================================================================= + // CONST, STATE, REF + // ============================================================================= + const weeksOfTheMonth = useMemo( + (): Dayjs[][] => CalendarHelper.generateDays(calendarDate), + [calendarDate] + ); + const [hoverValue, setHoverValue] = useState(""); + + // ============================================================================= + // EVENT HANDLERS + // ============================================================================= + const handleDayClick = (value: Dayjs, isDisabled: boolean) => { + if (isDisabled && !allowDisabledSelection) return; + + onSelect(value); + }; + + const handleHoverCell = (value: string, isDisabled: boolean) => { + if (isDisabled && !allowDisabledSelection) return; + + setHoverValue(value); + onHover(value); + }; + + const handleMouseLeaveCell = () => { + setHoverValue(""); + onHover(""); + }; + + // ============================================================================= + // RENDER FUNCTIONS + // ============================================================================= + const renderHeader = () => { + return weeksOfTheMonth[0].map((day, index) => ( + + + {dayjs(day).format("ddd")} + + + )); + }; + + const renderDayCells = () => { + return weeksOfTheMonth.map((week, weekIndex) => { + return ( + + {week.map((day, dayIndex) => { + return ( + + ); + })} + + ); + }); + }; + + return ( + + {renderHeader()} + {renderDayCells()} + + ); +}; diff --git a/src/shared/internal-calendar/single/single-cell.tsx b/src/shared/internal-calendar/single/single-cell.tsx new file mode 100644 index 000000000..7dfdbd1a0 --- /dev/null +++ b/src/shared/internal-calendar/single/single-cell.tsx @@ -0,0 +1,103 @@ +import dayjs, { Dayjs } from "dayjs"; +import { CalendarHelper } from "../../../util"; +import { CellStyleProps, DayCell, DayCellProps } from "../day-cell"; + +interface Props { + date: Dayjs; + calendarDate: Dayjs; + selectedDate: string; + hoverDate: string; + minDate?: string | undefined; + maxDate?: string | undefined; + disabledDates?: string[] | undefined; + allowDisabledSelection?: boolean | undefined; + showActiveMonthDaysOnly?: boolean | undefined; + onSelect: (value: Dayjs, disabled: boolean) => void; + onHover: (value: string, disabled: boolean) => void; +} + +export const SingleCell = ({ + date, + calendarDate, + selectedDate, + hoverDate, + minDate, + maxDate, + disabledDates, + allowDisabledSelection, + showActiveMonthDaysOnly, + onSelect, + onHover, +}: Props) => { + // ========================================================================= + // CONSTS + // ========================================================================= + const disabled = CalendarHelper.isDisabledDay( + date, + disabledDates, + minDate, + maxDate + ); + const interactive = !disabled || allowDisabledSelection; + + // ========================================================================= + // EVENT HANDLERS + // ========================================================================= + const handleSelect = () => { + onSelect(date, !interactive); + }; + + const handleHover = () => { + onHover(date.format("YYYY-MM-DD"), !interactive); + }; + + // ========================================================================= + // HELPERS + // ========================================================================= + const getCellStyle = () => { + const props: CellStyleProps = {}; + + if (calendarDate.month() !== date.month()) { + props.labelType = showActiveMonthDaysOnly + ? "hidden" + : "unavailable"; + } else if (dayjs().isSame(date, "day") && !disabled) { + props.labelType = "current"; + } + + const isSelected = date.isSame(selectedDate, "day"); + const isHover = date.isSame(hoverDate, "day"); + + if (isSelected && isHover) { + props.labelType = "selected-hover"; + props.circleLeft = "selected-hover-outline"; + props.circleRight = "selected-hover-outline"; + } else if (isSelected) { + props.labelType = "selected"; + props.circleLeft = "selected-outline"; + props.circleRight = "selected-outline"; + } else if (isHover) { + props.labelType = "hover"; + props.circleLeft = "hover-subtle"; + props.circleRight = "hover-subtle"; + } + + return props; + }; + + // ============================================================================= + // RENDER FUNCTION + // ============================================================================= + + const commonProps: DayCellProps = { + date, + calendarDate, + disabled, + interactive, + currentDateIndicator: true, + onSelect: handleSelect, + onHover: handleHover, + }; + + return ; +}; diff --git a/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx b/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx index c05d80b95..be07cc719 100644 --- a/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx +++ b/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx @@ -1,7 +1,7 @@ import dayjs, { Dayjs } from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; import { useMemo, useState } from "react"; -import { V2_Text } from "../../../v2_text/text"; +import { Typography } from "../../../typography"; import { CalendarHelper } from "../../../util/calendar-helper"; import { CommonCalendarProps, FocusType } from "../types"; import { @@ -76,9 +76,9 @@ export const StandardCalendarDayView = ({ const renderHeader = () => { return weeksOfTheMonth[0].map((day, index) => ( - + {dayjs(day).format("ddd")} - + )); }; diff --git a/src/shared/internal-calendar/standard/standard-cell.tsx b/src/shared/internal-calendar/standard/standard-cell.tsx index 2020f3b63..ff08bebcf 100644 --- a/src/shared/internal-calendar/standard/standard-cell.tsx +++ b/src/shared/internal-calendar/standard/standard-cell.tsx @@ -71,8 +71,6 @@ export const StandardCell = ({ : "unavailable"; } else if (dayjs().isSame(date, "day") && !disabled) { props.labelType = "current"; - props.circleLeft = "current"; - props.circleRight = "current"; } else if (isNewSelection) { const beforeStart = currentFocus === "end" && startDate && date.isBefore(startDate); @@ -112,10 +110,10 @@ export const StandardCell = ({ props.labelType = "selected"; if (!isStart) { - props.bgLeft = "selected"; + props.bgLeft = "selected-outline-subtle"; } if (!isEnd) { - props.bgRight = "selected"; + props.bgRight = "selected-outline-subtle"; } } @@ -131,26 +129,35 @@ export const StandardCell = ({ const isHover = date.isSame(hoverDate, "day"); - if (isHover) { - props.circleLeft = "hover-current"; - props.circleRight = "hover-current"; - } - const { hoverStart, hoverEnd, overlapStart, overlapEnd } = getHoverRange(); + if (isHover) { + const isStart = date.isSame(startDate, "day"); + const isEnd = date.isSame(endDate, "day"); + if (isStart || isEnd) { + props.labelType = "selected-hover"; + props.circleLeft = "selected-hover-outline"; + props.circleRight = "selected-hover-outline"; + } else { + props.labelType = "hover"; + props.circleLeft = "hover"; + props.circleRight = "hover"; + } + } + if (hoverStart && hoverEnd) { if (date.isBetween(hoverStart, hoverEnd, "day", "[]")) { const isStart = date.isSame(hoverStart, "day"); const isEnd = date.isSame(hoverEnd, "day"); - props.labelType = "selected"; - if (!isStart) { - props.bgLeft = "hover-dash"; + props.labelType = "hover"; + props.bgLeft = "hover-outline"; } if (!isEnd) { - props.bgRight = "hover-dash"; + props.labelType = "hover"; + props.bgRight = "hover-outline"; } } @@ -159,21 +166,10 @@ export const StandardCell = ({ if (overlapStart && overlapEnd) { if (date.isBetween(overlapStart, overlapEnd, "day", "[]")) { - const isStart = date.isSame(overlapStart, "day"); - const isEnd = date.isSame(overlapEnd, "day"); - - props.labelType = "selected"; - - if (isStart || isEnd) { - props.circleLeft = "overlap-outline"; - props.circleRight = "overlap-outline"; - } - - if (!isStart) { - props.bgLeft = "overlap"; - } - if (!isEnd) { - props.bgRight = "overlap"; + if (isHover) { + props.labelType = "selected-hover"; + props.circleLeft = "selected-hover"; + props.circleRight = "selected-hover"; } } @@ -234,6 +230,7 @@ export const StandardCell = ({ calendarDate, disabled, interactive, + currentDateIndicator: true, onSelect: handleSelect, onHover: handleHover, }; diff --git a/src/shared/internal-calendar/week/week-day-cell.tsx b/src/shared/internal-calendar/week/week-day-cell.tsx index ff8682f26..0d357c862 100644 --- a/src/shared/internal-calendar/week/week-day-cell.tsx +++ b/src/shared/internal-calendar/week/week-day-cell.tsx @@ -1,6 +1,12 @@ import dayjs, { Dayjs } from "dayjs"; import { CalendarHelper, DateHelper } from "../../../util"; -import { CellStyleProps, CellType, DayCell, DayCellProps } from "../day-cell"; +import { + CellStyleProps, + CellType, + DayCell, + DayCellProps, + LabelType, +} from "../day-cell"; interface Props { date: Dayjs; @@ -73,15 +79,21 @@ export const WeekDayCell = ({ const props: CellStyleProps = {}; let type: CellType = undefined; + let labelType: LabelType = undefined; if (isSelected && isHover) { - type = "hover-current"; + type = "selected-hover-outline"; + labelType = "selected-hover"; } else if (isSelected) { type = "selected-outline"; + labelType = "selected"; } else if (isHover) { - type = "hover-dash"; + type = "hover"; + labelType = "hover"; } if (type) { + props.labelType = labelType; + if (isStart) { props.circleLeft = type; } else { @@ -101,14 +113,10 @@ export const WeekDayCell = ({ const getCellStyle = () => { const props: CellStyleProps = {}; - if (isSelected || isHover) { - props.labelType = "selected"; - } else if (calendarDate.month() !== date.month()) { + if (calendarDate.month() !== date.month()) { props.labelType = "unavailable"; } else if (dayjs().isSame(date, "day") && !disabled) { props.labelType = "current"; - props.circleLeft = "current"; - props.circleRight = "current"; } return props; @@ -123,6 +131,7 @@ export const WeekDayCell = ({ calendarDate, disabled, interactive, + currentDateIndicator: true, onSelect: handleSelect, onHover: handleHover, }; From 2875534d41ff584e6c8ab95617583815823853dc Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Tue, 10 Dec 2024 15:17:46 +0800 Subject: [PATCH 5/7] [CCUBE-1626][RL] Update TimeSlotBarWeek day cell styling --- .../time-slot-bar-week-days.tsx | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/time-slot-bar-week/time-slot-bar-week-days.tsx b/src/time-slot-bar-week/time-slot-bar-week-days.tsx index df0d6d90f..7fcb90b95 100644 --- a/src/time-slot-bar-week/time-slot-bar-week-days.tsx +++ b/src/time-slot-bar-week/time-slot-bar-week-days.tsx @@ -168,16 +168,22 @@ export const TimeSlotBarWeekDays = ({ ? null : isHoverEnabled; - if (isHoverEnabled && hoverDay && day.isSame(hoverDay, "day")) { - dayCellStyleProps.circleLeft = "hover-current"; - dayCellStyleProps.circleRight = "hover-current"; - } - - // Apply selected styles - if ([selectedDate].includes(dateStartWithYear)) { + const isHover = + isHoverEnabled && hoverDay && day.isSame(hoverDay, "day"); + const isSelected = [selectedDate].includes(dateStartWithYear); + + if (isSelected && isHover) { + dayCellStyleProps.labelType = "selected-hover"; + dayCellStyleProps.circleLeft = "selected-hover-outline"; + dayCellStyleProps.circleRight = "selected-hover-outline"; + } else if (isSelected) { dayCellStyleProps.labelType = "selected"; dayCellStyleProps.circleLeft = "selected-outline"; dayCellStyleProps.circleRight = "selected-outline"; + } else if (isHover) { + dayCellStyleProps.labelType = "hover"; + dayCellStyleProps.circleLeft = "hover-subtle"; + dayCellStyleProps.circleRight = "hover-subtle"; } return dayCellStyleProps; From 4b7ecccde25930d7adf24448f1aed63e1861d6fe Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Tue, 10 Dec 2024 16:01:51 +0800 Subject: [PATCH 6/7] [CCUBE-1626][RL] Update TimeSlotBarWeekView day cellstyling and remove unused components --- .../standard-calendar-day-view.style.tsx | 215 +----------------- .../time-slot-week-days.style.tsx | 36 +-- .../time-slot-week-days.tsx | 134 +++++------ 3 files changed, 84 insertions(+), 301 deletions(-) diff --git a/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx b/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx index 6138066f0..8081d620b 100644 --- a/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx +++ b/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx @@ -1,33 +1,5 @@ -import styled, { css } from "styled-components"; -import { V2_Color } from "../../../v2_color"; -import { V2_Text, V2_TextStyleHelper } from "../../../v2_text"; -import { DayVariant } from "./standard-calendar-day-view"; +import styled from "styled-components"; -// ============================================================================= -// STYLE INTERFACES, transient props are denoted with $ -// See more https://styled-components.com/docs/api#transient-props -// ============================================================================= -export interface StyleProps { - $disabledDisplay?: boolean; - $interactive?: boolean; - $overlap?: boolean; - $hovered?: boolean; - $selected?: boolean; -} - -export interface DayLabelStyleProps extends StyleProps { - $variant: DayVariant; -} - -export interface BaseOverflowDisplayProps extends StyleProps { - $position: "left" | "right"; -} - -export interface BaseInteractiveCircleProps extends DayLabelStyleProps {} - -// ============================================================================= -// COMMON STYLING for DAY CELL -// ============================================================================= export const Wrapper = styled.div` width: 100%; display: grid; @@ -48,188 +20,3 @@ export const RowDayCell = styled.div` grid-column: 1 / -1; display: flex; `; - -export const GrowDayCell = styled.div` - display: flex; - position: relative; - height: 2.5rem; - align-items: center; - justify-content: center; - flex: 1; -`; - -export const BaseOverflowDisplay = styled.div` - position: absolute; - width: 50%; - height: 100%; - - ${(props) => { - switch (props.$position) { - case "left": - return css` - left: 0; - `; - case "right": - return css` - right: 0; - `; - } - }} -`; - -export const BaseInteractiveCircle = styled.div` - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - width: 2.5rem; - height: 2.5rem; - cursor: default; - position: absolute; -`; - -export const DayLabel = styled(V2_Text.H5)` - ${(props) => { - const { $disabledDisplay, $selected, $variant } = props; - - if ($disabledDisplay && $selected) { - return css` - ${V2_TextStyleHelper.getTextStyle("H5", "semibold")}; - color: ${V2_Color.Accent.Light[2]}; - `; - } - - if ($disabledDisplay) { - return css` - color: ${V2_Color.Neutral[4]}; - `; - } - - if ($selected) { - return css` - ${V2_TextStyleHelper.getTextStyle("H5", "semibold")}; - color: ${V2_Color.Primary}; - `; - } - - switch ($variant) { - case "other-month": - return css` - color: ${V2_Color.Neutral[4]}; - `; - case "today": - return css` - color: ${V2_Color.Neutral[3]}; - `; - case "default": - return css` - color: ${V2_Color.Neutral[1]}; - `; - } - }} -`; - -// ============================================================================= -// STYLING for Regular -// ============================================================================= -export const OverflowDisplay = styled(BaseOverflowDisplay)` - ${(props) => { - const { $selected } = props; - - if ($selected) { - return css` - border-top: 1px solid ${V2_Color.Accent.Light[4]}; - border-bottom: 1px solid ${V2_Color.Accent.Light[4]}; - background-color: ${V2_Color.Accent.Light[5]}; - `; - } - }} - - ${(props) => { - const { $hovered, $overlap } = props; - - if ($hovered) { - return css` - border-top: 1px dashed ${V2_Color.Accent.Light[4]}; - border-bottom: 1px dashed ${V2_Color.Accent.Light[4]}; - background-color: ${V2_Color.Accent.Light[6]}; - `; - } - - if ($overlap) { - return css` - background-color: ${V2_Color.Accent.Light[4]}; - `; - } - }} -`; - -export const InteractiveCircle = styled(BaseInteractiveCircle)` - ${(props) => { - const { $hovered, $selected } = props; - - if ($selected) { - return css` - background: ${V2_Color.Accent.Light[5]}; - border: 1px solid ${V2_Color.Primary}; - `; - } - - if ($hovered) { - return css` - box-shadow: 0px 0px 4px 1px ${V2_Color.Shadow.Accent}; - border: 1px solid ${V2_Color.Accent.Light[1]}; - background-color: ${V2_Color.Neutral[8]}; - `; - } - }} - - ${(props) => { - const { $interactive, $disabledDisplay } = props; - - if ($interactive) { - return css` - cursor: pointer; - :hover { - box-shadow: 0px 0px 4px 1px ${V2_Color.Shadow.Accent}; - border: 1px solid ${V2_Color.Accent.Light[1]}; - background-color: ${V2_Color.Neutral[8]}; - } - `; - } else if ($disabledDisplay) { - return css` - cursor: not-allowed; - `; - } - }} - - ${(props) => { - const { $disabledDisplay, $overlap, $variant } = props; - - if ($overlap) { - return css` - border: 1px solid ${V2_Color.Accent.Light[1]}; - background: ${V2_Color.Accent.Light[4]}; - - :hover { - background: ${V2_Color.Accent.Light[4]}; - } - `; - } - - if ($disabledDisplay) { - return css` - color: ${V2_Color.Neutral[4]}; - `; - } - - switch ($variant) { - case "today": - return css` - background: ${V2_Color.Accent.Light[5]}; - `; - default: - break; - } - }} -`; diff --git a/src/time-slot-week-view/time-slot-week-days.style.tsx b/src/time-slot-week-view/time-slot-week-days.style.tsx index bf7a0468e..90ac3383c 100644 --- a/src/time-slot-week-view/time-slot-week-days.style.tsx +++ b/src/time-slot-week-view/time-slot-week-days.style.tsx @@ -1,29 +1,36 @@ import styled, { css } from "styled-components"; -import { DayLabel } from "../shared/internal-calendar/standard"; import { Colour, Font } from "../theme"; -export const DayLabelWeek = styled(DayLabel)` - ${(props) => { - const { $variant } = props; - switch ($variant) { - case "default": - return css` - ${Font["body-md-semibold"]} - color: ${Colour["text-subtler"]}; - `; - } - }} -`; +// ============================================================================= +// STYLE INTERFACES +// ============================================================================= +interface LabelStyleProps { + $disabled: boolean; +} +// ============================================================================= +// STYLING +// ============================================================================= export const HeaderCellWeek = styled.div` display: flex; + flex-direction: column; align-items: center; justify-content: center; - pointer-events: none; user-select: none; margin-bottom: 0.188rem; `; +export const DayLabel = styled.div` + ${Font["body-xs-semibold"]} + color:${Colour["text"]}; + + ${(props) => + props.$disabled && + css` + color: ${Colour["text-disabled-subtlest"]}; + `}; +`; + export const Wrapper = styled.div` width: 100%; display: grid; @@ -35,6 +42,7 @@ export const ColumnWeekCell = styled.div` display: flex; min-height: 7.625rem; `; + export const TimeSlotText = styled.div` ${Font["body-xs-semibold"]} margin: 1rem 0rem; diff --git a/src/time-slot-week-view/time-slot-week-days.tsx b/src/time-slot-week-view/time-slot-week-days.tsx index 7c73190df..002573d3e 100644 --- a/src/time-slot-week-view/time-slot-week-days.tsx +++ b/src/time-slot-week-view/time-slot-week-days.tsx @@ -1,21 +1,15 @@ import dayjs, { Dayjs } from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; -import { Colour } from "../theme"; -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import { InternalCalendarProps } from "../shared/internal-calendar"; -import { - GrowDayCell, - InteractiveCircle, - RowDayCell, - StyleProps, -} from "../shared/internal-calendar/standard"; +import { CellStyleProps, DayCell } from "../shared/internal-calendar/day-cell"; +import { Colour } from "../theme"; import { TimeSlot as TimeSlotComponent } from "../time-slot-bar/time-slot-bar.styles"; import { TimeSlot } from "../time-slot-bar/types"; -import { Typography } from "../typography"; import { CalendarHelper } from "../util/calendar-helper"; import { ColumnWeekCell, - DayLabelWeek, + DayLabel, HeaderCellWeek, TimeSlotText, TimeSlotWrapper, @@ -38,6 +32,8 @@ interface TimeSlotWeekDaysProps onSlotClick?: ((date: string, timeSlot: TimeSlot) => void) | undefined; } +const dateFormat = "YYYY-MM-DD"; + const fallbackSlot = { id: "1", startTime: "", @@ -67,6 +63,7 @@ export const TimeSlotWeekDays = ({ const currentCalendarWeek = useMemo((): Dayjs[] => { return CalendarHelper.generateDaysForCurrentWeek(calendarDate); }, [calendarDate]); + const [hoverDay, setHoverDay] = useState(); // ============================================================================= // EVENT HANDLERS @@ -80,7 +77,14 @@ export const TimeSlotWeekDays = ({ const handleSlotClick = (date: string, slot: TimeSlot) => { onSlotClick(date, slot); }; - const dateFormat = "YYYY-MM-DD"; + + const handleDayHover = (value: Dayjs) => { + setHoverDay(value); + }; + + const handleDayMouseout = () => { + setHoverDay(undefined); + }; // ============================================================================= // HELPER FUNCTIONS @@ -101,78 +105,63 @@ export const TimeSlotWeekDays = ({ const generateStyleProps = (day: Dayjs) => { const dateStartWithYear = day.format(dateFormat); const disabled = isDisabled(day); - - const styleCircleProps: StyleProps = {}, - styleLabelProps: StyleProps = {}; + const isHoverEnabled = enableSelection && !disabled; + const isHover = + isHoverEnabled && hoverDay && day.isSame(hoverDay, "day"); + const isSelected = [selectedDate].includes(dateStartWithYear); + + const dayCellStyleProps: CellStyleProps = { + labelType: "available", + interactive: !enableSelection ? null : isHoverEnabled, + }; if (disabled) { - styleCircleProps.$disabledDisplay = true; - styleLabelProps.$disabledDisplay = true; + dayCellStyleProps.disabled = true; + dayCellStyleProps.labelType = "unavailable"; } - styleCircleProps.$interactive = enableSelection && !disabled; - - // apply selected styles - if ([selectedDate].includes(dateStartWithYear)) { - styleCircleProps.$selected = true; - styleLabelProps.$selected = true; + if (isSelected && isHover) { + dayCellStyleProps.labelType = "selected-hover"; + dayCellStyleProps.circleLeft = "selected-hover-outline"; + dayCellStyleProps.circleRight = "selected-hover-outline"; + } else if (isSelected) { + dayCellStyleProps.labelType = "selected"; + dayCellStyleProps.circleLeft = "selected-outline"; + dayCellStyleProps.circleRight = "selected-outline"; + } else if (isHover) { + dayCellStyleProps.labelType = "hover"; + dayCellStyleProps.circleLeft = "hover-subtle"; + dayCellStyleProps.circleRight = "hover-subtle"; } - return { - styleCircleProps, - styleLabelProps, - }; + return dayCellStyleProps; }; // ============================================================================= // RENDER FUNCTIONS // ============================================================================= - const renderWeek = () => { - return currentCalendarWeek.map((day, index) => ( - - - {dayjs(day).format("ddd")} - - - )); - }; - const renderHeader = () => { - return ( - - {currentCalendarWeek.map((day, dayIndex) => { - const variant = "default"; - const { styleCircleProps, styleLabelProps } = - generateStyleProps(day); - - return ( - - - handleDayClick( - day, - !styleCircleProps.$interactive - ) - } - {...styleCircleProps} - > - - {day.format("D")} - - - - ); - })} - - ); + return currentCalendarWeek.map((day, index) => { + const dayCellStyleProps = generateStyleProps(day); + + return ( + + { + handleDayClick(day, !dayCellStyleProps.interactive); + }} + onHover={handleDayHover} + onHoverEnd={handleDayMouseout} + {...dayCellStyleProps} + /> + + {dayjs(day).format("ddd")} + + + ); + }); }; const renderTimeSlotBarCells = () => { @@ -253,7 +242,6 @@ export const TimeSlotWeekDays = ({ return ( {renderHeader()} - {renderWeek()} {renderTimeSlotBarCells()} ); From 6715511edb8ab5c917eec22499dfad1395c65fe8 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Wed, 11 Dec 2024 14:52:09 +0800 Subject: [PATCH 7/7] [CCUBE-1626][RL] Refactor to used shared text style in HeaderCell --- .../fixed-range-calendar-day-view.tsx | 5 +---- src/shared/internal-calendar/single/index.ts | 1 - .../single/single-calendar-day-view.style.tsx | 22 ------------------- .../single/single-calendar-day-view.tsx | 11 ++-------- .../standard-calendar-day-view.style.tsx | 4 ++++ .../standard/standard-calendar-day-view.tsx | 5 +---- .../week/week-calendar-day-view.tsx | 5 +---- 7 files changed, 9 insertions(+), 44 deletions(-) delete mode 100644 src/shared/internal-calendar/single/single-calendar-day-view.style.tsx diff --git a/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx b/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx index b8b135ba5..628988348 100644 --- a/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx +++ b/src/shared/internal-calendar/fixed-range/fixed-range-calendar-day-view.tsx @@ -1,6 +1,5 @@ import dayjs, { Dayjs } from "dayjs"; import { useMemo, useState } from "react"; -import { Typography } from "../../../typography"; import { CalendarHelper } from "../../../util/calendar-helper"; import { HeaderCell, RowDayCell, Wrapper } from "../standard"; import { CommonCalendarProps } from "../types"; @@ -64,9 +63,7 @@ export const FixedRangeCalendarDayView = ({ const renderHeader = () => { return weeksOfTheMonth[0].map((day, index) => ( - - {dayjs(day).format("ddd")} - + {dayjs(day).format("ddd")} )); }; diff --git a/src/shared/internal-calendar/single/index.ts b/src/shared/internal-calendar/single/index.ts index adcf1df79..c1fde322e 100644 --- a/src/shared/internal-calendar/single/index.ts +++ b/src/shared/internal-calendar/single/index.ts @@ -1,2 +1 @@ export * from "./single-calendar-day-view"; -export * from "./single-calendar-day-view.style"; diff --git a/src/shared/internal-calendar/single/single-calendar-day-view.style.tsx b/src/shared/internal-calendar/single/single-calendar-day-view.style.tsx deleted file mode 100644 index 8081d620b..000000000 --- a/src/shared/internal-calendar/single/single-calendar-day-view.style.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import styled from "styled-components"; - -export const Wrapper = styled.div` - width: 100%; - display: grid; - grid-template-columns: repeat(7, 1fr); - row-gap: 0.25rem; -`; - -export const HeaderCell = styled.div` - display: flex; - align-items: center; - justify-content: center; - height: 2.5rem; - pointer-events: none; - user-select: none; -`; - -export const RowDayCell = styled.div` - grid-column: 1 / -1; - display: flex; -`; diff --git a/src/shared/internal-calendar/single/single-calendar-day-view.tsx b/src/shared/internal-calendar/single/single-calendar-day-view.tsx index fab6f558e..52ac422af 100644 --- a/src/shared/internal-calendar/single/single-calendar-day-view.tsx +++ b/src/shared/internal-calendar/single/single-calendar-day-view.tsx @@ -1,14 +1,9 @@ import dayjs, { Dayjs } from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; import { useMemo, useState } from "react"; -import { Typography } from "../../../typography"; import { CalendarHelper } from "../../../util/calendar-helper"; +import { HeaderCell, RowDayCell, Wrapper } from "../standard"; import { CommonCalendarProps } from "../types"; -import { - HeaderCell, - RowDayCell, - Wrapper, -} from "./single-calendar-day-view.style"; import { SingleCell } from "./single-cell"; dayjs.extend(isBetween); @@ -70,9 +65,7 @@ export const SingleCalendarDayView = ({ const renderHeader = () => { return weeksOfTheMonth[0].map((day, index) => ( - - {dayjs(day).format("ddd")} - + {dayjs(day).format("ddd")} )); }; diff --git a/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx b/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx index 8081d620b..ae90a2ae7 100644 --- a/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx +++ b/src/shared/internal-calendar/standard/standard-calendar-day-view.style.tsx @@ -1,4 +1,5 @@ import styled from "styled-components"; +import { Colour, Font } from "../../../theme"; export const Wrapper = styled.div` width: 100%; @@ -14,6 +15,9 @@ export const HeaderCell = styled.div` height: 2.5rem; pointer-events: none; user-select: none; + + ${Font["body-sm-semibold"]}; + color: ${Colour["text"]}; `; export const RowDayCell = styled.div` diff --git a/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx b/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx index be07cc719..9469b2ff4 100644 --- a/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx +++ b/src/shared/internal-calendar/standard/standard-calendar-day-view.tsx @@ -1,7 +1,6 @@ import dayjs, { Dayjs } from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; import { useMemo, useState } from "react"; -import { Typography } from "../../../typography"; import { CalendarHelper } from "../../../util/calendar-helper"; import { CommonCalendarProps, FocusType } from "../types"; import { @@ -76,9 +75,7 @@ export const StandardCalendarDayView = ({ const renderHeader = () => { return weeksOfTheMonth[0].map((day, index) => ( - - {dayjs(day).format("ddd")} - + {dayjs(day).format("ddd")} )); }; diff --git a/src/shared/internal-calendar/week/week-calendar-day-view.tsx b/src/shared/internal-calendar/week/week-calendar-day-view.tsx index aa5f366ad..d7d8b3f61 100644 --- a/src/shared/internal-calendar/week/week-calendar-day-view.tsx +++ b/src/shared/internal-calendar/week/week-calendar-day-view.tsx @@ -1,6 +1,5 @@ import dayjs, { Dayjs } from "dayjs"; import { useMemo, useState } from "react"; -import { V2_Text } from "../../../v2_text/text"; import { CalendarHelper } from "../../../util/calendar-helper"; import { HeaderCell, RowDayCell, Wrapper } from "../standard"; import { CommonCalendarProps } from "../types"; @@ -64,9 +63,7 @@ export const WeekCalendarDayView = ({ const renderHeader = () => { return weeksOfTheMonth[0].map((day, index) => ( - - {dayjs(day).format("ddd")} - + {dayjs(day).format("ddd")} )); };