diff --git a/package.json b/package.json index 1277481..3307c04 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@logseq/libs": "^0.0.2", "classnames": "^2.3.1", "dayjs": "^1.11.1", + "lodash-es": "^4.17.21", "rc-checkbox": "^2.3.2", "react": "^18.0.0", "react-dom": "^18.0.0", @@ -27,6 +28,7 @@ "@semantic-release/exec": "6.0.3", "@semantic-release/git": "10.0.1", "@semantic-release/npm": "9.0.1", + "@types/lodash-es": "^4.17.6", "@types/node": "17.0.23", "@types/react": "18.0.6", "@types/react-dom": "18.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99e9a19..7f3aede 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,7 @@ specifiers: '@semantic-release/exec': 6.0.3 '@semantic-release/git': 10.0.1 '@semantic-release/npm': 9.0.1 + '@types/lodash-es': ^4.17.6 '@types/node': 17.0.23 '@types/react': 18.0.6 '@types/react-dom': 18.0.2 @@ -19,6 +20,7 @@ specifiers: eslint: 8.13.0 eslint-plugin-react: 7.29.4 eslint-plugin-react-hooks: ^4.6.0 + lodash-es: ^4.17.21 node-fetch: 3.2.3 rc-checkbox: ^2.3.2 react: ^18.0.0 @@ -40,6 +42,7 @@ dependencies: '@logseq/libs': 0.0.2 classnames: 2.3.1 dayjs: 1.11.1 + lodash-es: 4.17.21 rc-checkbox: 2.3.2_react-dom@18.0.0+react@18.0.0 react: 18.0.0 react-dom: 18.0.0_react@18.0.0 @@ -55,6 +58,7 @@ devDependencies: '@semantic-release/exec': 6.0.3_semantic-release@19.0.2 '@semantic-release/git': 10.0.1_semantic-release@19.0.2 '@semantic-release/npm': 9.0.1_semantic-release@19.0.2 + '@types/lodash-es': 4.17.6 '@types/node': 17.0.23 '@types/react': 18.0.6 '@types/react-dom': 18.0.2 @@ -704,6 +708,16 @@ packages: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true + /@types/lodash-es/4.17.6: + resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==} + dependencies: + '@types/lodash': 4.14.185 + dev: true + + /@types/lodash/4.14.185: + resolution: {integrity: sha512-evMDG1bC4rgQg4ku9tKpuMh5iBNEwNa3tf9zRHdP1qlv+1WUg44xat4IxCE14gIpZRGUUWAx2VhItCZc25NfMA==} + dev: true + /@types/minimist/1.2.2: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} dev: true diff --git a/src/App.tsx b/src/App.tsx index b165731..53f9d7b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,7 +4,7 @@ import { ErrorBoundary, FallbackProps } from 'react-error-boundary'; import dayjs from 'dayjs'; import advancedFormat from 'dayjs/plugin/advancedFormat'; import TaskInput, { ITaskInputRef } from './components/TaskInput'; -import TaskSection from './components/TaskSection'; +import TaskSection, { GroupBy } from './components/TaskSection'; import { logseq as plugin } from '../package.json'; import { useRecoilCallback, useRecoilValue } from 'recoil'; import { visibleState } from './state/visible'; @@ -115,7 +115,7 @@ function App() {
- +
diff --git a/src/api.ts b/src/api.ts index 069a7be..23bb9be 100644 --- a/src/api.ts +++ b/src/api.ts @@ -54,7 +54,6 @@ export async function setTaskScheduled(task: TaskEntityObject, date: Date | null scheduledString, ); } else { - // FIXME: 多行文本会有问题 const lines = rawContent.split('\n'); lines.splice(1, 0, scheduledString); newRawContent = lines.join('\n'); diff --git a/src/components/TaskSection.tsx b/src/components/TaskSection.tsx index c667704..b402a89 100644 --- a/src/components/TaskSection.tsx +++ b/src/components/TaskSection.tsx @@ -1,18 +1,26 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { useRecoilRefresher_UNSTABLE, useRecoilValue, useRecoilValueLoadable, } from 'recoil'; +import { groupBy } from 'lodash-es'; import { TaskEntityObject } from '../models/TaskEntity'; import { tasksState } from '../state/tasks'; import { themeStyleState } from '../state/theme'; import { visibleState } from '../state/visible'; import TaskItem from './TaskItem'; +export enum GroupBy { + Page, + Tag, + Namespace, +} + export interface ITaskSectionProps { title: string; query: string; + groupBy?: GroupBy; } const TaskSection: React.FC = (props) => { @@ -39,6 +47,15 @@ const TaskSection: React.FC = (props) => { } }, [visible, refresh]); + const taskGroups = useMemo(() => { + switch (props.groupBy) { + case GroupBy.Page: + return groupBy(tasks, (task: TaskEntityObject) => task.page.name); + default: + return { '': tasks }; + } + }, [props.groupBy, tasks]); + if (tasks.length === 0) { return null; } @@ -47,16 +64,21 @@ const TaskSection: React.FC = (props) => {

{title}

- {tasks.map((task) => ( - - ))} + {Object.entries(taskGroups).map(([name, tasks]) => { + return ( +
+ {name &&

{name}

} + {tasks.map((task) => ( + + ))} +
+ ); + })}
); diff --git a/src/models/TaskEntity.ts b/src/models/TaskEntity.ts index 10f47c8..b28e51a 100644 --- a/src/models/TaskEntity.ts +++ b/src/models/TaskEntity.ts @@ -31,6 +31,7 @@ export interface TaskEntityObject { marker: TaskMarker; priority: TaskPriority; scheduled: number; + repeated: boolean; completed: boolean; page: { name: string; @@ -80,6 +81,10 @@ class TaskEntity { return this.block.scheduled ?? this.block.deadline ?? this.page.journalDay; } + public get repeated(): boolean { + return !!this.block.repeated; + } + public get completed(): boolean { return this.marker === TaskMarker.DONE; } @@ -97,6 +102,7 @@ class TaskEntity { marker: this.marker, priority: this.priority, scheduled: this.scheduled, + repeated: this.repeated, completed: this.completed, page: { name: this.page.name,