Skip to content

Commit

Permalink
enh(#224): add support for multi-language on dates
Browse files Browse the repository at this point in the history
  • Loading branch information
eythaann committed Dec 19, 2024
1 parent 6b57fe2 commit 5d16e44
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 110 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [Unreleased]
### features
- add kill process option on context menu for dock items.
- multi-language calendar and date module on toolbar.

### fix
- slu-service was being closed on exit code 1.
Expand Down
4 changes: 4 additions & 0 deletions src/apps/shared/styles/reset.css
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,7 @@
color: inherit !important;
}
}

.ant-picker-cell {
padding: 0 !important;
}
1 change: 1 addition & 0 deletions src/apps/toolbar/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'moment/min/locales';
import i18n from 'i18next';
import yaml from 'js-yaml';
import { initReactI18next } from 'react-i18next';
Expand Down
166 changes: 132 additions & 34 deletions src/apps/toolbar/modules/Date/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Calendar, Popover, Row } from 'antd';
import { CalendarMode } from 'antd/es/calendar/generateCalendar';
import moment, { Moment } from 'moment';
import { CalendarMode, HeaderRender } from 'antd/es/calendar/generateCalendar';
import moment from 'moment';
import momentGenerateConfig from 'rc-picker/es/generate/moment';
import { PropsWithChildren, useCallback, useState, WheelEvent } from 'react';
import { PropsWithChildren, useCallback, useEffect, useState, WheelEvent } from 'react';
import { useTranslation } from 'react-i18next';

import './infra.css';
import { BackgroundByLayersV2 } from '../../../seelenweg/components/BackgroundByLayers/infra';
Expand All @@ -12,12 +13,102 @@ import { useWindowFocusChange } from 'src/apps/shared/hooks';
import { Icon } from '../../../shared/components/Icon';
import { cx } from '../../../shared/styles';

const MomentCalendar = Calendar.generateCalendar<Moment>(momentGenerateConfig);
const short_week_days = {
inner: ['Su', 'Mn', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
};

const MomentCalendar = Calendar.generateCalendar({
...momentGenerateConfig,
locale: {
...momentGenerateConfig.locale,
getShortWeekDays: () => short_week_days.inner,
},
});

const DateCalendarHeader: HeaderRender<moment.Moment> = (props) => {
const { type, value: date, onChange, onTypeChange } = props;

if (type === 'month') {
return (
<Row className="calendar-header">
<span className="calendar-date" onClick={() => onTypeChange('year')}>
{date.format('MMMM YYYY')}
</span>
<div className="calendar-actions">
<button
className="calendar-navigator"
onClick={() => onChange(date.clone().add(-1, 'months'))}
>
<Icon iconName="AiOutlineLeft" />
</button>
<button
className="calendar-navigator"
onClick={() => onChange(moment().locale(date.locale()))}
>
<Icon iconName="AiOutlineHome" />
</button>
<button
className="calendar-navigator"
onClick={() => onChange(date.clone().add(1, 'months'))}
>
<Icon iconName="AiOutlineRight" />
</button>
</div>
</Row>
);
}

return (
<Row className="calendar-header">
<span className="calendar-date" onClick={() => onTypeChange('month')}>
{date.format('YYYY')}
</span>
<div className="calendar-actions">
<div className="calendar-header-placeholder" />
<button
className="calendar-navigator"
onClick={() => onChange(date.clone().add(-1, 'years'))}
>
<Icon iconName="AiOutlineLeft" />
</button>
<button
className="calendar-navigator"
onClick={() => onChange(moment().locale(date.locale()))}
>
<Icon iconName="AiOutlineHome" />
</button>
<button
className="calendar-navigator"
onClick={() => onChange(date.clone().add(1, 'years'))}
>
<Icon iconName="AiOutlineRight" />
</button>
</div>
</Row>
);
};

function DateCalendar() {
const [date, setDate] = useState(moment());
const { i18n } = useTranslation();

const [date, setDate] = useState(moment().locale(i18n.language));
const [viewMode, setViewMode] = useState<CalendarMode | undefined>('month');

useEffect(() => {
setDate(date.locale(i18n.language));
const start = date.clone().startOf('isoWeek');
short_week_days.inner = [
start.day(0).format('dd'),
start.day(1).format('dd'),
start.day(2).format('dd'),
start.day(3).format('dd'),
start.day(4).format('dd'),
start.day(5).format('dd'),
start.day(6).format('dd'),
start.day(7).format('dd'),
];
}, [i18n.language]);

const onWheel = useCallback((e: WheelEvent<HTMLDivElement>) => {
e.preventDefault();
e.stopPropagation();
Expand All @@ -32,42 +123,49 @@ function DateCalendar() {
}, []);

return (
<BackgroundByLayersV2 className="calendar-container" prefix="calendar" onContextMenu={(e) => e.stopPropagation()}>
<BackgroundByLayersV2
className="calendar-container"
prefix="calendar"
onContextMenu={(e) => e.stopPropagation()}
>
<div onWheel={onWheel}>
<MomentCalendar
value={date}
onChange={setDate}
onPanelChange={(_, mode) => setViewMode(mode)}
className="calendar"
fullscreen={false}
mode={viewMode}
headerRender={(props) => props.type == 'month' ? (
<Row className="calendar-header">
<span className="calendar-date" onClick={() => setViewMode('year')}>{date.format('MMMM YYYY')}</span>
<div className="calendar-header-placeholder"/>
<button className="calendar-navigator" onClick={() => setDate(date.clone().startOf('month').add(-1, 'months'))}><Icon iconName="AiOutlineLeft" /></button>
<button className="calendar-navigator" onClick={() => setDate(moment().startOf('month'))}><Icon iconName="AiOutlineHome" /></button>
<button className="calendar-navigator" onClick={() => setDate(date.clone().startOf('month').add(1, 'months'))}><Icon iconName="AiOutlineRight" /></button>
</Row>
) : (
<Row className="calendar-header">
<span className="calendar-date" onClick={() => setViewMode('month')}>{date.format('YYYY')}</span>
<div className="calendar-header-placeholder"/>
<button className="calendar-navigator" onClick={() => setDate(date.clone().startOf('year').add(-1, 'years'))}><Icon iconName="AiOutlineLeft" /></button>
<button className="calendar-navigator" onClick={() => setDate(moment().startOf('month'))}><Icon iconName="AiOutlineHome" /></button>
<button className="calendar-navigator" onClick={() => setDate(date.clone().startOf('year').add(1, 'years'))}><Icon iconName="AiOutlineRight" /></button>
</Row>
)}
fullCellRender={(current, info) => info.type == 'date' ? (
<div className={cx('calendar-cell-value', {
'calendar-cell-today': current.isSame(info.today, 'date'),
'calendar-cell-off-month': current.month() != date.month(),
})}>{Number(current.format('DD'))}</div>
) : (
<div className={cx('calendar-cell-value', 'calendar-cell-month', { 'calendar-cell-today': current.startOf('month').isSame(info.today.startOf('month'), 'date') })} onClick={() => {
setDate(current);
setViewMode('month');
}}>{current.format('MMMM')}</div>
)}/>
headerRender={DateCalendarHeader}
fullCellRender={(current, info) =>
info.type == 'date' ? (
<div
className={cx('calendar-cell-value', {
'calendar-cell-selected': current.isSame(date, 'date'),
'calendar-cell-today': current.isSame(info.today, 'date'),
'calendar-cell-off-month': current.month() != date.month(),
})}
onClick={() => setDate(current)}
>
{Number(current.format('DD'))}
</div>
) : (
<div
className={cx('calendar-cell-value', 'calendar-cell-month', {
'calendar-cell-today': current
.startOf('month')
.isSame(info.today.startOf('month'), 'date'),
})}
onClick={() => {
setDate(current);
setViewMode('month');
}}
>
{current.format('MMMM')}
</div>
)
}
/>
</div>
</BackgroundByLayersV2>
);
Expand Down
9 changes: 6 additions & 3 deletions src/apps/toolbar/modules/Date/infra.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DateToolbarItem } from '@seelen-ui/lib/types';
import moment from 'moment';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';

import { Item } from '../item/infra/infra';
Expand All @@ -17,15 +18,17 @@ interface Props {
export function DateModule({ module }: Props) {
const dateFormat = useSelector(Selectors.dateFormat);

const [date, setDate] = useState(moment().format(dateFormat));
const { i18n } = useTranslation();

const [date, setDate] = useState(moment().locale(i18n.language).format(dateFormat));

let interval = dateFormat.includes('ss') ? 1000 : 1000 * 60;
useInterval(
() => {
setDate(moment().format(dateFormat));
setDate(moment().locale(i18n.language).format(dateFormat));
},
interval,
[dateFormat],
[dateFormat, i18n.language],
);

return (
Expand Down
Loading

0 comments on commit 5d16e44

Please sign in to comment.