From 14b467e1556dc5be96a606bef277765ea0472a52 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Sun, 7 Nov 2021 12:36:28 +0800 Subject: [PATCH] fix: adapt for user defined date formats --- package.json | 2 +- pnpm-lock.yaml | 13 ++++----- src/App.tsx | 28 +++++++++++--------- src/Heatmap.tsx | 70 +++++++++++++++++++++++++------------------------ src/main.tsx | 7 ++--- src/utils.ts | 33 ++++++++++++++++++++++- 6 files changed, 95 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index 442bd7b..9f304f5 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "dependencies": { "@logseq/libs": "0.0.1-alpha.30", "@types/uuid": "^8.3.1", - "dayjs": "^1.10.7", + "date-fns": "^2.25.0", "react": "^17.0.2", "react-calendar-heatmap": "^1.8.1", "react-dom": "^17.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9bf5a19..7f61c2e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,7 +15,7 @@ specifiers: '@typescript-eslint/parser': 4.33.0 '@vitejs/plugin-react-refresh': 1.3.6 conventional-changelog-conventionalcommits: 4.6.1 - dayjs: ^1.10.7 + date-fns: ^2.25.0 eslint: 7.32.0 eslint-plugin-react: 7.26.1 react: ^17.0.2 @@ -32,7 +32,7 @@ specifiers: dependencies: '@logseq/libs': 0.0.1-alpha.30 '@types/uuid': 8.3.1 - dayjs: 1.10.7 + date-fns: 2.25.0 react: 17.0.2 react-calendar-heatmap: 1.8.1_react@17.0.2 react-dom: 17.0.2_react@17.0.2 @@ -1269,14 +1269,15 @@ packages: resolution: {integrity: sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==} dev: false + /date-fns/2.25.0: + resolution: {integrity: sha512-ovYRFnTrbGPD4nqaEqescPEv1mNwvt+UTqI3Ay9SzNtey9NZnYu6E2qCcBBgJ6/2VF1zGGygpyTDITqpQQ5e+w==} + engines: {node: '>=0.11'} + dev: false + /dateformat/3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} dev: true - /dayjs/1.10.7: - resolution: {integrity: sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==} - dev: false - /debug/4.3.2: resolution: {integrity: sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==} engines: {node: '>=6.0'} diff --git a/src/App.tsx b/src/App.tsx index 0cd54d1..6649e96 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,8 @@ import React, { useRef } from "react"; -import { Heatmap } from "./Heatmap"; import { useAppVisible, useThemeMode } from "./utils"; - -console.log(await logseq.App.getUserInfo()) +const Heatmap = React.lazy(() => + import("./Heatmap").then((d) => ({ default: d.Heatmap })) +); function App() { const innerRef = useRef(null); @@ -23,16 +23,18 @@ function App() { }, [visible]); if (started) { return ( -
{ - if (!innerRef.current?.contains(e.target as any)) { - window.logseq.hideMainUI(); - } - }} - > - -
+ +
{ + if (!innerRef.current?.contains(e.target as any)) { + window.logseq.hideMainUI(); + } + }} + > + +
+
); } return null; diff --git a/src/Heatmap.tsx b/src/Heatmap.tsx index 90ecfa9..3f828cb 100644 --- a/src/Heatmap.tsx +++ b/src/Heatmap.tsx @@ -1,18 +1,22 @@ -import dayjs from "dayjs"; -import customParseFormat from "dayjs/plugin/customParseFormat"; -import advancedFormat from "dayjs/plugin/advancedFormat"; - +import { + addDays, + addWeeks, + differenceInDays, + endOfWeek, + parse, + startOfWeek, +} from "date-fns"; import * as React from "react"; import CalendarHeatmap from "react-calendar-heatmap"; import ReactTooltip from "react-tooltip"; import { useMountedState } from "react-use"; import "./Heatmap.css"; -import { getIconPosition as getTriggerIconPosition } from "./utils"; - -dayjs.extend(customParseFormat); -dayjs.extend(advancedFormat); - -const defaultFormat = "YYYY-MM-DD"; +import { + formatAsDashed, + formatAsLocale, + formatAsParam, + getIconPosition as getTriggerIconPosition, +} from "./utils"; const useActivities = (startDate: string, endDate: string) => { const [values, setValues] = React.useState< @@ -22,8 +26,8 @@ const useActivities = (startDate: string, endDate: string) => { React.useLayoutEffect(() => { (async () => { - const d0 = dayjs(startDate).format("YYYYMMDD"); - const d1 = dayjs(endDate).format("YYYYMMDD"); + const date0 = new Date(startDate); + const date1 = new Date(endDate); const res: any[] = await logseq.DB.datascriptQuery(` [:find (pull ?p [*]) (count ?b) @@ -31,15 +35,15 @@ const useActivities = (startDate: string, endDate: string) => { [?b :block/page ?p] [?p :block/journal? true] [?p :block/journal-day ?d] - [(>= ?d ${d0})] [(<= ?d ${d1})]] + [(>= ?d ${formatAsParam(date0)})] [(<= ?d ${formatAsParam(date1)})]] `); const mapping = Object.fromEntries( res.map(([page, count]: any[]) => { const datum = { count: count ?? 0, - date: dayjs("" + page["journal-day"], "YYYYMMDD").format( - defaultFormat + date: formatAsDashed( + parse(`${page["journal-day"]}`, "yyyyMMdd", new Date()) ), originalName: page["original-name"] as string, }; @@ -47,18 +51,17 @@ const useActivities = (startDate: string, endDate: string) => { }) ); - const totalDays = dayjs(endDate).diff(dayjs(startDate), "d") + 1; + const totalDays = differenceInDays(date1, date0) + 1; const newValues: Datum[] = []; for (let i = 0; i < totalDays; i++) { - const date = dayjs(startDate).add(i, "d").format(defaultFormat); + const date = formatAsDashed(addDays(date0, i)); if (mapping[date]) { newValues.push(mapping[date]); } else { newValues.push({ date, count: 0, - // FIXME: only support default date format for now - originalName: dayjs(date).format("MMM Do, YYYY"), + originalName: formatAsLocale(date), }); } } @@ -167,24 +170,23 @@ const DateRange = ({ }) => { React.useLayoutEffect(() => { if (!range) { - const endDate = dayjs(today).endOf("week").format(defaultFormat); - const startDate = dayjs(endDate) - .add(-NUM_WEEKS, "week") - .startOf("week") - .format(defaultFormat); + const endDate = formatAsDashed(endOfWeek(new Date(today))); + const startDate = formatAsDashed( + startOfWeek(addWeeks(endOfWeek(new Date(today)), -NUM_WEEKS)) + ); onRangeChange([startDate, endDate]); } }, [range]); const onRangeClick = (isPrev: boolean) => { const [, endDate] = range!; - const newEndDate = dayjs(endDate) - .add(isPrev ? -12 : 12, "weeks") - .format(defaultFormat); - const newStartDate = dayjs(newEndDate) - .add(-NUM_WEEKS, "week") - .startOf("week") - .format(defaultFormat); + const newEndDate = formatAsDashed( + addWeeks(new Date(endDate), isPrev ? -12 : 12) + ); + + const newStartDate = formatAsDashed( + startOfWeek(addWeeks(new Date(newEndDate), -NUM_WEEKS)) + ); onRangeChange([newStartDate, newEndDate]); }; @@ -195,11 +197,11 @@ const DateRange = ({
From onRangeClick(true)}> - {dayjs(startDate).format("MMM Do, YYYY")} + {formatAsLocale(startDate)} to onRangeClick(false)}> - {dayjs(endDate).format("MMM Do, YYYY")} + {formatAsLocale(endDate)}
); @@ -208,7 +210,7 @@ const DateRange = ({ }; export const Heatmap = React.forwardRef(({}, ref) => { - const today = dayjs().format(defaultFormat); + const today = formatAsDashed(new Date()); const [range, setRange] = React.useState<[string, string] | null>(null); const { bottom, right } = getTriggerIconPosition(); return ( diff --git a/src/main.tsx b/src/main.tsx index 5933764..bab9cf2 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,7 +5,7 @@ import "virtual:windi-devtools"; import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; -import { openIconName } from "./utils"; +import { getDisplayDateFormat, openIconName } from "./utils"; // @ts-expect-error const css = (t, ...args) => String.raw(t, ...args); @@ -24,7 +24,8 @@ function main() { function createModel() { return { - show() { + async show() { + await getDisplayDateFormat(); logseq.showMainUI(); }, }; @@ -53,7 +54,7 @@ function main() { logseq.App.registerUIItem("toolbar", { key: openIconName, template: ` - +
`, diff --git a/src/utils.ts b/src/utils.ts index aaa39a8..35325c9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,3 +1,4 @@ +import { format } from "date-fns"; import React, { useState } from "react"; import { useMountedState } from "react-use"; @@ -50,7 +51,7 @@ export const useThemeMode = () => { (top?.document .querySelector("html") ?.getAttribute("data-theme") as typeof mode) ?? - (matchMedia("prefers-color-scheme: dark").matches ? "dark" : "light") + (matchMedia("prefers-color-scheme: dark").matches ? "dark" : "light") ); logseq.App.onThemeModeChanged((s) => { console.log(s); @@ -62,3 +63,33 @@ export const useThemeMode = () => { return mode; }; + + +export let displayDateFormat = "MMM do, yyyy"; + +export async function getDisplayDateFormat() { + let format = + (await logseq.App.getUserConfigs())?.preferredDateFormat ?? "MMM do, yyyy"; + + displayDateFormat = format; + return format; +} + +export const toDate = (d: Date | string) => { + if (typeof d !== "string") { + return d; + } + return new Date(d); +}; + +export const formatAsDashed = (d: Date | string) => { + return format(toDate(d), "yyyy-MM-dd"); +}; + +export const formatAsParam = (d: Date | string) => { + return format(toDate(d), "yyyyMMdd"); +}; + +export const formatAsLocale = (d: Date | string) => { + return format(toDate(d), displayDateFormat); +}; \ No newline at end of file