feat(core): integrate google calendar sync (#14248)

fix #14170 
fix #13893 
fix #13673 
fix #13543 
fix #13308 
fix #7607




#### PR Dependency Tree


* **PR #14247**
  * **PR #14248** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Integrations panel in Account Settings to link/unlink calendar
providers.
  * Collapsible settings wrapper for improved layout.

* **Improvements**
* Calendar system reworked: per-account calendar groups, simplified
toggles with explicit Save, richer event display (multi-dot date
indicators), improved event time/title handling across journal views.

* **Localization**
* Added calendar keys: save-error, no-journal, no-calendar; removed
legacy duplicate-error keys.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-01-13 02:38:16 +08:00
committed by GitHub
parent 89f0430242
commit 279b7bb64f
50 changed files with 1349 additions and 1002 deletions

View File

@@ -18,7 +18,15 @@ export type { DatePickerProps } from './types';
*/
export const DatePicker = (props: DatePickerProps) => {
const finalProps = { ...defaultDatePickerProps, ...props };
const { value, gapX, gapY, cellFontSize, cellSize, onChange } = finalProps;
const {
value,
gapX,
gapY,
cellFontSize,
cellSize,
onChange,
onCursorChange: handleCursorChange,
} = finalProps;
const [mode, setMode] = useState<SelectMode>('day');
const [cursor, setCursor] = useState(dayjs(value));
@@ -41,12 +49,16 @@ export const DatePicker = (props: DatePickerProps) => {
[onChange]
);
const onCursorChange = useCallback((newCursor: dayjs.Dayjs) => {
// validate range
if (newCursor.isBefore(DATE_MIN)) newCursor = dayjs(DATE_MIN);
else if (newCursor.isAfter(DATE_MAX)) newCursor = dayjs(DATE_MAX);
setCursor(newCursor);
}, []);
const onCursorChange = useCallback(
(newCursor: dayjs.Dayjs) => {
// validate range
if (newCursor.isBefore(DATE_MIN)) newCursor = dayjs(DATE_MIN);
else if (newCursor.isAfter(DATE_MAX)) newCursor = dayjs(DATE_MAX);
setCursor(newCursor);
handleCursorChange?.(newCursor);
},
[handleCursorChange]
);
return (
<div

View File

@@ -63,6 +63,11 @@ export interface DatePickerProps {
*/
onChange?: (value: string) => void;
/**
* when cursor date changes (month navigation/keyboard)
*/
onCursorChange?: (cursor: dayjs.Dayjs) => void;
// style customizations
monthHeaderCellClassName?: string;
monthBodyCellClassName?: string;