diff --git a/packages/frontend/component/src/ui/date-picker/calendar/calendar.css.ts b/packages/frontend/component/src/ui/date-picker/calendar/calendar.css.ts index f7d0a2f328..9b086a4c1f 100644 --- a/packages/frontend/component/src/ui/date-picker/calendar/calendar.css.ts +++ b/packages/frontend/component/src/ui/date-picker/calendar/calendar.css.ts @@ -89,7 +89,9 @@ export const basicCell = style({ }); // roots -export const calendarRoot = style({}); +export const calendarRoot = style({ + minWidth: `calc(28px * 7 + ${vars.gapX} * 6)`, +}); export const calendarWrapper = style({ display: 'flex', flexDirection: 'column', @@ -101,7 +103,7 @@ export const calendarHeader = style({ }); // header -export const headerLayoutCell = style([basicCell]); +export const headerLayoutCell = style([basicCell, { height: 'auto' }]); export const headerLayoutCellOrigin = style({ width: 0, height: 'fit-content', diff --git a/packages/frontend/component/src/ui/date-picker/calendar/day-picker.tsx b/packages/frontend/component/src/ui/date-picker/calendar/day-picker.tsx index a13dd7f794..225f3e3aaa 100644 --- a/packages/frontend/component/src/ui/date-picker/calendar/day-picker.tsx +++ b/packages/frontend/component/src/ui/date-picker/calendar/day-picker.tsx @@ -119,12 +119,17 @@ export const DayPicker = memo(function DayPicker( onClick={openMonthPicker} ref={headerMonthRef} className={styles.calendarHeaderTriggerButton} + data-testid="month-picker-button" + data-month={cursor.month()} + data-year={cursor.year()} > {monthNames.split(',')[cursor.month()]} diff --git a/packages/frontend/component/src/ui/date-picker/calendar/index.ts b/packages/frontend/component/src/ui/date-picker/calendar/index.ts index edaf8f07ab..cdf14f41ff 100644 --- a/packages/frontend/component/src/ui/date-picker/calendar/index.ts +++ b/packages/frontend/component/src/ui/date-picker/calendar/index.ts @@ -1 +1,2 @@ export * from './calendar'; +export type { DateCell } from './types'; diff --git a/packages/frontend/component/src/ui/date-picker/calendar/items.tsx b/packages/frontend/component/src/ui/date-picker/calendar/items.tsx index 133ed9724a..81a5ac325c 100644 --- a/packages/frontend/component/src/ui/date-picker/calendar/items.tsx +++ b/packages/frontend/component/src/ui/date-picker/calendar/items.tsx @@ -19,6 +19,8 @@ interface HeaderLayoutProps extends HTMLAttributes { left: React.ReactNode; right: React.ReactNode; } + +const autoHeight = { height: 'auto' }; /** * The `DatePicker` should work with different width * This is a hack to make header's item align with calendar cell's label, **instead of the cell** @@ -57,6 +59,7 @@ const HeaderLayout = memo(function HeaderLayout({ [styles.yearViewBodyCell]: mode === 'month', [styles.decadeViewBodyCell]: mode === 'year', })} + style={autoHeight} >
{isLeft ? left : isRight ? right : null} @@ -139,6 +142,7 @@ export const NavButtons = memo(function NavButtons({ size="small" className={styles.focusInteractive} disabled={prevDisabled} + data-testid="date-picker-nav-prev" onClick={onPrev} > @@ -151,6 +155,7 @@ export const NavButtons = memo(function NavButtons({ size="small" className={styles.focusInteractive} disabled={nextDisabled} + data-testid="date-picker-nav-next" onClick={onNext} > diff --git a/packages/frontend/component/src/ui/date-picker/calendar/month-picker.tsx b/packages/frontend/component/src/ui/date-picker/calendar/month-picker.tsx index 6502fbf93f..f868016ff7 100644 --- a/packages/frontend/component/src/ui/date-picker/calendar/month-picker.tsx +++ b/packages/frontend/component/src/ui/date-picker/calendar/month-picker.tsx @@ -73,6 +73,8 @@ export const MonthPicker = memo(function MonthPicker( const onKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); closeMonthPicker(); return; } @@ -101,6 +103,7 @@ export const MonthPicker = memo(function MonthPicker( const HeaderLeft = useMemo(() => { return ( diff --git a/packages/frontend/component/src/ui/date-picker/calendar/year-picker.tsx b/packages/frontend/component/src/ui/date-picker/calendar/year-picker.tsx index dc3479c083..6cd29f7c72 100644 --- a/packages/frontend/component/src/ui/date-picker/calendar/year-picker.tsx +++ b/packages/frontend/component/src/ui/date-picker/calendar/year-picker.tsx @@ -84,6 +84,8 @@ export const YearPicker = memo(function YearPicker( const onKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { + e.preventDefault(); + e.stopPropagation(); closeYearPicker(); return; } diff --git a/packages/frontend/core/src/components/page-list/filter/date-select.css.ts b/packages/frontend/core/src/components/page-list/filter/date-select.css.ts new file mode 100644 index 0000000000..279eacda34 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/filter/date-select.css.ts @@ -0,0 +1,17 @@ +import { cssVar } from '@toeverything/theme'; +import { style } from '@vanilla-extract/css'; + +export const datePickerTriggerInput = style({ + fontSize: cssVar('fontXs'), + width: '50px', + fontWeight: '600', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + height: '22px', + textAlign: 'center', + ':hover': { + background: cssVar('hoverColor'), + borderRadius: '4px', + }, +}); diff --git a/packages/frontend/core/src/components/page-list/filter/date-select.tsx b/packages/frontend/core/src/components/page-list/filter/date-select.tsx new file mode 100644 index 0000000000..07a434fa81 --- /dev/null +++ b/packages/frontend/core/src/components/page-list/filter/date-select.tsx @@ -0,0 +1,51 @@ +import { DatePicker, Popover, type PopoverProps } from '@affine/component'; +import { useAFFiNEI18N } from '@affine/i18n/hooks'; +import dayjs from 'dayjs'; +import { useCallback, useState } from 'react'; + +import { datePickerTriggerInput } from './date-select.css'; + +const datePickerPopperContentOptions: PopoverProps['contentOptions'] = { + style: { padding: 20, marginTop: 10 }, +}; + +export const DateSelect = ({ + value, + onChange, +}: { + value: number; + onChange: (value: number) => void; +}) => { + const t = useAFFiNEI18N(); + const [open, setOpen] = useState(false); + + const onDateChange = useCallback( + (e: string) => { + setOpen(false); + onChange(dayjs(e, 'YYYY-MM-DD').valueOf()); + }, + [onChange] + ); + + return ( + + } + > + + + ); +}; diff --git a/packages/frontend/core/src/components/page-list/filter/literal-matcher.tsx b/packages/frontend/core/src/components/page-list/filter/literal-matcher.tsx index fc3e259fec..07b4dacf56 100644 --- a/packages/frontend/core/src/components/page-list/filter/literal-matcher.tsx +++ b/packages/frontend/core/src/components/page-list/filter/literal-matcher.tsx @@ -1,8 +1,8 @@ -import { AFFiNEDatePicker, Input, Menu, MenuItem } from '@affine/component'; +import { Input, Menu, MenuItem } from '@affine/component'; import type { LiteralValue, Tag } from '@affine/env/filter'; -import dayjs from 'dayjs'; import { type ReactNode } from 'react'; +import { DateSelect } from './date-select'; import { FilterTag } from './filter-tag-translation'; import { inputStyle } from './index.css'; import { tBoolean, tDate, tDateRange, tTag } from './logical/custom-type'; @@ -67,12 +67,7 @@ literalMatcher.register(tBoolean.create(), { }); literalMatcher.register(tDate.create(), { render: ({ value, onChange }) => ( - { - onChange(dayjs(e, 'YYYY-MM-DD').valueOf()); - }} - /> + ), }); const getTagsOfArrayTag = (type: TType): Tag[] => { diff --git a/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.css.ts b/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.css.ts index 03b720a1c0..0e8d3783e1 100644 --- a/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.css.ts +++ b/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.css.ts @@ -1,5 +1,6 @@ import { cssVar } from '@toeverything/theme'; -import { globalStyle, style } from '@vanilla-extract/css'; +import { style } from '@vanilla-extract/css'; + const interactive = style({ position: 'relative', cursor: 'pointer', @@ -41,6 +42,7 @@ export const journalPanel = style({ display: 'flex', flexDirection: 'column', alignItems: 'stretch', + overflow: 'hidden', }); export const dailyCount = style({ height: 0, @@ -179,14 +181,47 @@ export const journalConflictMoreTrigger = style([ }, ]); -// TODO: when date-picker's cell is customizable, we should implement by custom cell -// override date-picker's active day when is not journal -globalStyle( - `.${journalPanel}[data-is-journal="false"] .react-datepicker__day[aria-selected="true"]`, +// customize date-picker cell +export const journalDateCell = style([ + interactive, { - backgroundColor: 'transparent', + width: '100%', + height: '100%', + borderRadius: 8, + fontSize: cssVar('fontSm'), color: cssVar('textPrimaryColor'), - fontWeight: 500, - border: `1px solid ${cssVar('primaryColor')}`, - } -); + fontWeight: 400, + position: 'relative', + + selectors: { + '&[data-is-today="true"]': { + fontWeight: 600, + color: cssVar('brandColor'), + }, + '&[data-not-current-month="true"]': { + color: cssVar('black10'), + }, + '&[data-selected="true"]': { + backgroundColor: cssVar('brandColor'), + fontWeight: 500, + color: cssVar('pureWhite'), + }, + '&[data-is-journal="false"][data-selected="true"]': { + backgroundColor: 'transparent', + color: 'var(--affine-text-primary-color)', + fontWeight: 500, + border: `1px solid ${cssVar('primaryColor')}`, + }, + }, + }, +]); +export const journalDateCellDot = style({ + width: 4, + height: 4, + borderRadius: '50%', + backgroundColor: cssVar('primaryColor'), + position: 'absolute', + bottom: 0, + left: '50%', + transform: 'translateX(-50%)', +}); diff --git a/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.tsx b/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.tsx index b6df10577c..26da3d69aa 100644 --- a/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.tsx +++ b/packages/frontend/core/src/pages/workspace/detail-page/editor-sidebar/extensions/journal.tsx @@ -1,5 +1,6 @@ import { - AFFiNEDatePicker, + type DateCell, + DatePicker, IconButton, Menu, Scrollable, @@ -80,6 +81,7 @@ interface JournalBlockProps extends EditorExtensionProps { const EditorJournalPanel = (props: EditorExtensionProps) => { const { workspace, page } = props; + const t = useAFFiNEI18N(); const { journalDate, isJournal } = useJournalInfoHelper( page.workspace, page.id @@ -99,14 +101,45 @@ const EditorJournalPanel = (props: EditorExtensionProps) => { [journalDate, openJournal] ); + const customDayRenderer = useCallback( + (cell: DateCell) => { + // TODO: add a dot to indicate journal + // has performance issue for now, better to calculate it in advance + // const hasJournal = !!getJournalsByDate(cell.date.format('YYYY-MM-DD'))?.length; + const hasJournal = false; + return ( + + ); + }, + [isJournal] + ); + return (
- +
+ +
diff --git a/tests/affine-local/e2e/all-page.spec.ts b/tests/affine-local/e2e/all-page.spec.ts index cdc6332ff8..38fcf06968 100644 --- a/tests/affine-local/e2e/all-page.spec.ts +++ b/tests/affine-local/e2e/all-page.spec.ts @@ -99,7 +99,6 @@ test('use monthpicker to modify the month of datepicker', async ({ page }) => { await selectMonthFromMonthPicker(page, lastMonth); await checkDatePickerMonth(page, lastMonth); // change month - await clickDatePicker(page); const nextMonth = new Date(); nextMonth.setMonth(nextMonth.getMonth() + 1); await selectMonthFromMonthPicker(page, nextMonth); diff --git a/tests/kit/utils/filter.ts b/tests/kit/utils/filter.ts index 61c336bff5..92e5918cdb 100644 --- a/tests/kit/utils/filter.ts +++ b/tests/kit/utils/filter.ts @@ -78,68 +78,8 @@ export const fillDatePicker = async (page: Page, date: Date) => { .fill(dateFormat(date)); }; -const checkIsLastMonth = (date: Date): boolean => { - const targetMonth = date.getMonth(); - const currentMonth = new Date().getMonth(); - const lastMonth = currentMonth === 0 ? 11 : currentMonth - 1; - return targetMonth === lastMonth; -}; - -const checkIsNextMonth = (date: Date): boolean => { - const targetMonth = date.getMonth(); - const currentMonth = new Date().getMonth(); - const nextMonth = currentMonth === 11 ? 0 : currentMonth + 1; - return targetMonth === nextMonth; -}; - -export const selectDateFromDatePicker = async (page: Page, date: Date) => { - const datePickerPopup = page.locator('.react-datepicker-popper'); - const day = date.getDate(); - const month = date.toLocaleString('en-US', { month: 'long' }); - const weekday = date.toLocaleString('en-US', { weekday: 'long' }); - const year = date.getFullYear().toString(); - const nth = function (d: number) { - if (d > 3 && d < 21) return 'th'; - switch (d % 10) { - case 1: - return 'st'; - case 2: - return 'nd'; - case 3: - return 'rd'; - default: - return 'th'; - } - }; - const daySuffix = nth(day); - // Open the date picker popup - await clickDatePicker(page); - const selectDate = async (): Promise => { - if (checkIsLastMonth(date)) { - const lastMonthButton = page.locator( - '[data-testid="date-picker-prev-button"]' - ); - await lastMonthButton.click(); - } else if (checkIsNextMonth(date)) { - const nextMonthButton = page.locator( - '[data-testid="date-picker-next-button"]' - ); - await nextMonthButton.click(); - } - // Click on the day cell - const dateCell = page.locator( - `[aria-disabled="false"][aria-label="Choose ${weekday}, ${month} ${day}${daySuffix}, ${year}"]` - ); - await dateCell.click(); - }; - await selectDate(); - - // Wait for the date picker popup to close - await datePickerPopup.waitFor({ state: 'hidden' }); -}; - export const selectMonthFromMonthPicker = async (page: Page, date: Date) => { - const month = date.toLocaleString('en-US', { month: 'long' }); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); const year = date.getFullYear(); // Open the month picker popup await clickMonthPicker(page); @@ -148,14 +88,16 @@ export const selectMonthFromMonthPicker = async (page: Page, date: Date) => { .getByTestId('month-picker-current-year') .innerText()); if (selectedYear > year) { - await page.locator('[data-testid="month-picker-prev-button"]').click(); + await page.locator('[data-testid="date-picker-nav-prev"]').click(); return await selectMonth(); } else if (selectedYear < year) { - await page.locator('[data-testid="month-picker-next-button"]').click(); + await page.locator('[data-testid="date-picker-nav-next"]').click(); return await selectMonth(); } // Click on the day cell - const monthCell = page.locator(`[aria-label="Choose ${month} ${year}"]`); + const monthCell = page.locator( + `[data-is-month-cell][aria-label="${year}-${month}"]` + ); await monthCell.click(); }; await selectMonth(); @@ -163,8 +105,8 @@ export const selectMonthFromMonthPicker = async (page: Page, date: Date) => { export const checkDatePickerMonth = async (page: Page, date: Date) => { expect( - await page.locator('[data-testid="date-picker-current-month"]').innerText() - ).toBe(date.toLocaleString('en-US', { month: 'long' })); + await page.getByTestId('month-picker-button').evaluate(e => e.dataset.month) + ).toBe(date.getMonth().toString()); }; const createTag = async (page: Page, name: string) => {