Skip to content

Commit f87fcd1

Browse files
committed
fix: resolve DST date mapping and TypeScript config issues
#141
1 parent 15d6698 commit f87fcd1

9 files changed

Lines changed: 106 additions & 21 deletions

File tree

core/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<div markdown="1">
22
<sup>Using <a href="https://wangchujiang.com/#/app" target="_blank">my app</a> is also a way to <a href="https://wangchujiang.com/#/sponsor" target="_blank">support</a> me:</sup>
33
<br>
4+
<a target="_blank" href="https://jaywcjlove.github.io/maslink/?id=6766860898" title="Zipora: Zip/RAR/7Z Unarchiver"><img alt="Zipora: Zip/RAR/7Z Unarchiver" height="52" src="https://wangchujiang.com/appicon/zipora.png"></a>
45
<a target="_blank" href="https://jaywcjlove.github.io/maslink/?id=6758053530" title="Scap: Screenshot & Markup Edit for macOS"><img alt="Scap: Screenshot & Markup Edit" height="52" src="https://wangchujiang.com/appicon/scap.png"></a>
56
<a target="_blank" href="https://jaywcjlove.github.io/maslink/?id=6757317079" title="Screen Test for macOS"><img alt="Screen Test" height="52" src="https://wangchujiang.com/appicon/screen-test.png"></a>
67
<a target="_blank" href="https://jaywcjlove.github.io/maslink/?id=6755948110" title="Deskmark for macOS"><img alt="Deskmark" height="52" src="https://wangchujiang.com/appicon/deskmark.png"></a>

core/src/Day.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { FC, PropsWithChildren, useMemo } from "react"
22
import { Rect, RectProps } from './Rect';
3-
import { formatData, getDateToString, existColor, numberSort, oneDayTime } from './utils';
3+
import { addDays, formatData, getDateToString, existColor, numberSort } from './utils';
44
import { SVGProps } from './SVG';
55

66
type DayProps = {
@@ -28,7 +28,7 @@ export const Day:FC<PropsWithChildren<DayProps>> = (props) => {
2828
return (
2929
<g key={idx} data-column={idx}>
3030
{[...Array(7)].map((_, cidx) => {
31-
const currentDate = new Date(initStartDate.getTime() + oneDayTime * (idx * 7 + cidx));
31+
const currentDate = addDays(initStartDate, idx * 7 + cidx);
3232
const date = getDateToString(currentDate);
3333
const dataProps: RectProps['value'] = {
3434
...data[date],

core/src/LabelsMonth.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Fragment, useMemo } from 'react';
2-
import { oneDayTime } from './utils';
2+
import { addDays } from './utils';
33
import { SVGProps } from './SVG';
44
import { textStyle } from './LabelsWeek';
55

@@ -19,7 +19,7 @@ const generateData = (colNum: number, monthLabels: false | string[], startDate:
1919
return Array.from({ length: colNum * 7 })
2020
.map((_, idx) => {
2121
if ((idx / 7) % 1 === 0) {
22-
const date = new Date(startDate.getTime() + idx * oneDayTime);
22+
const date = addDays(startDate, idx);
2323
const month = date.getMonth();
2424
if (endDate && date > endDate) return null;
2525
return { col: idx / 7, index: idx, month, day: date.getDate(), monthStr: monthLabels[month], date };

core/src/SVG.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { CSSProperties, useEffect, useMemo, useState } from 'react';
22
import { LabelsWeek } from './LabelsWeek';
33
import { LabelsMonth } from './LabelsMonth';
44
import { RectProps } from './Rect';
5-
import { isValidDate, oneDayTime, convertPanelColors } from './utils';
5+
import { isValidDate, convertPanelColors, getStartOfWeek } from './utils';
66
import Legend, { LegendProps } from './Legend';
77
import { Day } from './Day';
88

@@ -77,10 +77,9 @@ export default function SVG(props: SVGProps) {
7777

7878
const initStartDate = useMemo(() => {
7979
if (isValidDate(startDate)) {
80-
return !startDate.getDay() ? startDate : new Date(startDate.getTime() - startDate.getDay() * oneDayTime);
80+
return getStartOfWeek(startDate);
8181
} else {
82-
const newDate = new Date();
83-
return new Date(newDate.getTime() - newDate.getDay() * oneDayTime);
82+
return getStartOfWeek(new Date());
8483
}
8584
}, [startDate]);
8685

core/src/utils.ts

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,57 @@ export function isValidDate(date: Date) {
66
return date instanceof Date && !isNaN(date.getTime());
77
}
88

9+
const DATE_ONLY_PATTERN = /^(\d{4})[/-](\d{1,2})[/-](\d{1,2})$/;
10+
11+
export function parseDate(value: string | Date) {
12+
if (value instanceof Date) {
13+
return isValidDate(value) ? new Date(value.getTime()) : null;
14+
}
15+
16+
const matched = value.match(DATE_ONLY_PATTERN);
17+
if (matched) {
18+
const year = Number(matched[1]);
19+
const month = Number(matched[2]) - 1;
20+
const day = Number(matched[3]);
21+
const date = new Date(year, month, day);
22+
if (date.getFullYear() === year && date.getMonth() === month && date.getDate() === day) {
23+
return date;
24+
}
25+
return null;
26+
}
27+
28+
const date = new Date(value);
29+
return isValidDate(date) ? date : null;
30+
}
31+
32+
export function addDays(date: Date, days: number) {
33+
const nextDate = new Date(date.getTime());
34+
nextDate.setDate(nextDate.getDate() + days);
35+
return nextDate;
36+
}
37+
38+
export function getStartOfWeek(date: Date) {
39+
const startDate = new Date(date.getTime());
40+
startDate.setHours(0, 0, 0, 0);
41+
startDate.setDate(startDate.getDate() - startDate.getDay());
42+
return startDate;
43+
}
44+
945
export function getDateToString(date: Date) {
1046
return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
1147
}
1248

1349
export function formatData(data: SVGProps['value'] = []) {
1450
const result: Record<string, HeatMapValue> = {};
1551
data.forEach((item) => {
16-
if (item.date && isValidDate(new Date(item.date))) {
17-
item.date = getDateToString(new Date(item.date));
18-
result[item.date] = item;
52+
if (item.date) {
53+
const date = parseDate(item.date);
54+
if (!date) return;
55+
const dateString = getDateToString(date);
56+
result[dateString] = {
57+
...item,
58+
date: dateString,
59+
};
1960
}
2061
});
2162
return result;

core/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"extends": "../tsconfig",
33
"include": ["src"],
44
"compilerOptions": {
5-
"baseUrl": ".",
5+
"rootDir": "src",
66
"outDir": "lib",
77
"noEmit": false
88
}

tsconfig.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"compilerOptions": {
3-
"target": "es5",
3+
"target": "es6",
44
"lib": ["dom", "dom.iterable", "esnext"],
55
"allowJs": true,
66
"skipLibCheck": true,
@@ -9,11 +9,10 @@
99
"strict": true,
1010
"forceConsistentCasingInFileNames": true,
1111
"module": "esnext",
12-
"moduleResolution": "node",
12+
"moduleResolution": "bundler",
1313
"resolveJsonModule": true,
1414
"isolatedModules": true,
1515
"declaration": true,
16-
"baseUrl": ".",
1716
"jsx": "react-jsx",
1817
"noFallthroughCasesInSwitch": true,
1918
"noEmit": true

www/src/Example.tsx

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,40 @@ const data2: HeatMapValue[] = [
9494
{ date: '2016/04/22', count: 6, content: '' },
9595
];
9696

97+
const data3: HeatMapValue[] = [
98+
{ date: '2025/10/24', count: 9, content: 'DST test data' },
99+
{ date: '2025/10/25', count: 12, content: 'DST test data' },
100+
{ date: '2025/10/26', count: 35, content: 'DST test data' },
101+
{ date: '2025/10/27', count: 18, content: 'DST test data' },
102+
{ date: '2025/10/28', count: 11, content: 'DST test data' },
103+
{ date: '2025/10/29', count: 15, content: 'DST test data' },
104+
{ date: '2025/10/30', count: 21, content: 'DST test data' },
105+
{ date: '2025/10/31', count: 7, content: 'DST test data' },
106+
{ date: '2025/11/01', count: 10, content: 'DST test data' },
107+
{ date: '2025/11/02', count: 6, content: 'DST test data' },
108+
{ date: '2026/03/27', count: 16, content: 'DST test data' },
109+
{ date: '2026/03/28', count: 20, content: 'DST test data' },
110+
{ date: '2026/03/29', count: 24, content: 'DST test data' },
111+
{ date: '2026/03/30', count: 14, content: 'DST test data' },
112+
{ date: '2026/03/31', count: 8, content: 'DST test data' },
113+
];
114+
97115
const darkColor = { 0: 'rgb(255 255 255 / 25%)', 8: '#7BC96F', 4: '#C6E48B', 12: '#239A3B', 32: '#ff7b00' };
98116

99117
export default function Example() {
100118
const [value, setValue] = useState(data1);
101-
const [selectDate, setSelectDate] = useState();
119+
const [selectDate, setSelectDate] = useState<string | undefined>();
102120
const [enableEndDate, setEnableEndDate] = useState(false);
103121
const [enableDark, setEnableDark] = useState(false);
104122
const [enableCircle, setEnableCircle] = useState(false);
123+
const [enableDstCase, setEnableDstCase] = useState(false);
105124
const [rectSize, setRectSize] = useState(11);
106125
const [monthPlacement, setMonthPlacement] = useState<'top' | 'bottom'>('top');
107126
const [legendCellSize, setLegendCellSize] = useState<number | undefined>();
108127
const [enableWeekLabels, setEnableWeekLabels] = useState<false | undefined | string[]>(undefined);
109128
const [enableMonthLabels, setEnableMonthLabels] = useState<false | undefined | string[]>(undefined);
129+
const startDate = enableDstCase ? new Date('2025/10/01') : new Date('2016/01/01');
130+
const endDate = enableDstCase ? new Date('2026/04/10') : enableEndDate ? new Date('2016/6/01') : undefined;
110131
return (
111132
<Wrapper>
112133
<ExampleWrapper>
@@ -121,8 +142,8 @@ export default function Example() {
121142
legendCellSize={legendCellSize}
122143
weekLabels={enableWeekLabels}
123144
monthLabels={enableMonthLabels}
124-
startDate={new Date('2016/01/01')}
125-
endDate={enableEndDate ? new Date('2016/6/01') : undefined}
145+
startDate={startDate}
146+
endDate={endDate}
126147
monthPlacement={monthPlacement}
127148
value={value}
128149
rectProps={{
@@ -167,9 +188,34 @@ export default function Example() {
167188
</ExampleWrapper>
168189
<Tools>
169190
<div style={{ paddingLeft: 10, paddingBottom: 20 }}>
170-
<button onClick={() => setValue(data1)}>Value 1</button>
171-
<button onClick={() => setValue(data2)}>Value 2</button>
191+
<button
192+
onClick={() => {
193+
setValue(data1);
194+
setEnableDstCase(false);
195+
}}
196+
>
197+
Value 1
198+
</button>
199+
<button
200+
onClick={() => {
201+
setValue(data2);
202+
setEnableDstCase(false);
203+
}}
204+
>
205+
Value 2
206+
</button>
207+
<button
208+
onClick={() => {
209+
setValue(data3);
210+
setEnableDstCase(true);
211+
}}
212+
>
213+
DST Value
214+
</button>
172215
<span>{selectDate}</span>
216+
<span style={{ marginLeft: 12, color: '#888' }}>
217+
{enableDstCase ? 'range: 2025/10/01 - 2026/04/10' : 'range: 2016/01/01 - follow controls'}
218+
</span>
173219
</div>
174220
<label>
175221
<input type="checkbox" checked={enableEndDate} onChange={(e) => setEnableEndDate(e.target.checked)} />

www/tsconfig.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"extends": "../tsconfig",
33
"include": ["./src", ".kktrc.ts"],
44
"compilerOptions": {
5-
"baseUrl": ".",
65
"emitDeclarationOnly": true,
76
"noEmit": false
87
}

0 commit comments

Comments
 (0)