1- import "@logseq/libs" ;
1+ import '@logseq/libs' ;
2+ import moment from 'moment' ;
3+ import TickTick from './ticktick/ticktick' ;
4+ import { NewTask , Subtask } from './ticktick/task' ;
5+ import { logseq as PackageLogseq } from '../package.json' ;
6+ import { settingsSchema , getTickTickSettings } from './settings' ;
7+ import { BlockEntity } from '@logseq/libs/dist/LSPlugin' ;
28
3- import React from "react" ;
4- import * as ReactDOM from "react-dom/client" ;
5- import App from "./App" ;
6- import "./index.css" ;
9+ const pluginId = PackageLogseq . id ;
10+ const ticktick = new TickTick ( ) ;
711
8- import { logseq as PL } from "../package.json" ;
12+ const priorityToNum = ( text : string ) : 0 | 1 | 3 | 5 => {
13+ const priority = text . match ( / \[ # ( [ A - C ] ) \] / ) ;
14+ if ( priority ) {
15+ switch ( priority [ 1 ] ) {
16+ case 'A' :
17+ return 5 ;
18+ case 'B' :
19+ return 3 ;
20+ case 'C' :
21+ return 1 ;
22+ }
23+ }
24+ return 0 ;
25+ } ;
26+
27+ const priorityToTag = ( priority : 0 | 1 | 3 | 5 | undefined ) : string => {
28+ switch ( priority ) {
29+ case 5 :
30+ return ' [#A] ' ;
31+ case 3 :
32+ return ' [#B] ' ;
33+ case 1 :
34+ return ' [#C] ' ;
35+ }
36+ return '' ;
37+ } ;
938
10- // @ts -expect-error
11- const css = ( t , ...args ) => String . raw ( t , ...args ) ;
39+ const parseTask = ( text : string ) : NewTask => {
40+ // parse priority and remove it from the title
41+ const priority = priorityToNum ( text ) ;
42+ let title = text . replace ( / \[ # ( [ A - C ] ) \] / , '' ) ;
43+ title = title . replace ( / T O D O / , '' ) ;
1244
13- const pluginId = PL . id ;
45+ return {
46+ title,
47+ priority,
48+ items : [ ] ,
49+ } ;
50+ } ;
1451
15- function main ( ) {
16- console . info ( `#${ pluginId } : MAIN` ) ;
17- const root = ReactDOM . createRoot ( document . getElementById ( "app" ) ! ) ;
18-
19- root . render (
20- < React . StrictMode >
21- < App />
22- </ React . StrictMode >
23- ) ;
24-
25- function createModel ( ) {
26- return {
27- show ( ) {
28- logseq . showMainUI ( ) ;
29- } ,
30- } ;
52+ const getTreeContent : ( block : BlockEntity ) => Promise < BlockEntity | null > = async ( block ) => {
53+ const blockEntity = await logseq . Editor . getBlock ( block . uuid , { includeChildren : true } ) ;
54+
55+ return blockEntity ;
56+ }
57+
58+ const flattenTree : ( node : BlockEntity ) => BlockEntity [ ] = ( node ) => {
59+ const result : BlockEntity [ ] = [ node ] ;
60+
61+ if ( node . children ) {
62+ for ( const child of node . children ) {
63+ result . push ( ...flattenTree ( child as BlockEntity ) ) ;
64+ }
3165 }
3266
33- logseq . provideModel ( createModel ( ) ) ;
34- logseq . setMainUIInlineStyle ( {
35- zIndex : 11 ,
67+ return result ;
68+ }
69+
70+ const main : ( ) => Promise < void > = async ( ) => {
71+ console . info ( `#${ pluginId } : MAIN` ) ;
72+
73+ logseq . useSettingsSchema ( settingsSchema ) ;
74+ let settings = getTickTickSettings ( ) ;
75+
76+ logseq . onSettingsChanged ( ( ) => {
77+ settings = getTickTickSettings ( ) ;
78+
79+ if (
80+ settings . accessToken === '' &&
81+ settings . accessCode !== '' &&
82+ settings . clientId !== '' &&
83+ settings . clientSecret !== '' &&
84+ settings . redirectUri !== ''
85+ ) {
86+ ticktick
87+ . getAccessToken (
88+ settings . clientId ,
89+ settings . clientSecret ,
90+ settings . accessCode ,
91+ settings . redirectUri ,
92+ )
93+ . then ( ( accessToken ) => {
94+ logseq . updateSettings ( { accessToken } ) ;
95+ logseq . UI . showMsg (
96+ 'TickTick access token updated successfully.' ,
97+ 'success' ,
98+ ) ;
99+ } ) ;
100+ }
36101 } ) ;
37102
38- const openIconName = "template-plugin-open" ;
103+ if ( settings . accessToken !== '' ) {
104+ ticktick . setAccessToken ( settings . accessToken ) ;
105+ }
39106
40- logseq . provideStyle ( css `
41- . ${ openIconName } {
42- opacity : 0.55 ;
43- font-size : 20 px ;
44- margin-top : 4 px ;
107+ logseq . Editor . registerSlashCommand ( 'tt' , async ( ) => {
108+ const blockEntity = await logseq . Editor . getCurrentBlock ( ) ;
109+ if ( ! blockEntity ) {
110+ console . error ( 'No block selected' ) ;
111+ return ;
45112 }
46113
47- .${ openIconName } : hover {
48- opacity: 0.9;
114+ let contentTree = await getTreeContent ( blockEntity ) ;
115+ if ( ! contentTree ) {
116+ console . error ( 'Cannot get tree content from block entity' ) ;
117+ return ;
49118 }
50- ` ) ;
51119
52- logseq . App . registerUIItem ( "toolbar" , {
53- key : openIconName ,
54- template : `
55- <div data-on-click="show" class="${ openIconName } ">⚙️</div>
56- ` ,
120+ const flatContentTree = flattenTree ( contentTree ) ;
121+ console . log ( flatContentTree ) ;
122+
123+ const subtasks : Subtask [ ] = flatContentTree . slice ( 1 ) . map ( child => {
124+ const subtask : Subtask = {
125+ title : child . content . replace ( / T O D O / , '' ) . replace ( / \[ # ( [ A - C ] ) \] / , '' ) ,
126+ } ;
127+ return subtask ;
128+ } ) ;
129+
130+ const task = parseTask ( flatContentTree [ 0 ] ?. content || '' ) ;
131+ task . items = subtasks ;
132+
133+ try {
134+ const newTask = await ticktick . createTask ( task ) ;
135+ await logseq . Editor . updateBlock (
136+ blockEntity . uuid ,
137+ `TODO${ priorityToTag ( newTask . priority ) } [${ newTask . title } ](${ newTask . taskUrl } )` ,
138+ ) ;
139+ } catch ( error ) {
140+ logseq . UI . showMsg ( 'TickTick access token is invalid.' , 'error' ) ;
141+ }
57142 } ) ;
58143}
59144
60- logseq . ready ( main ) . catch ( console . error ) ;
145+ logseq . ready ( main ) . catch ( console . error ) ;
0 commit comments