state.cljs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717
  1. (ns frontend.state
  2. (:require [cljs-bean.core :as bean]
  3. [cljs.core.async :as async]
  4. [clojure.string :as string]
  5. [cljs.spec.alpha :as s]
  6. [dommy.core :as dom]
  7. [medley.core :as medley]
  8. [electron.ipc :as ipc]
  9. [frontend.storage :as storage]
  10. [frontend.util :as util]
  11. [frontend.util.cursor :as cursor]
  12. [goog.dom :as gdom]
  13. [goog.object :as gobj]
  14. [promesa.core :as p]
  15. [rum.core :as rum]
  16. [logseq.graph-parser.config :as gp-config]
  17. [frontend.mobile.util :as mobile-util]))
  18. (defonce ^:large-vars/data-var state
  19. (let [document-mode? (or (storage/get :document/mode?) false)
  20. current-graph (let [graph (storage/get :git/current-repo)]
  21. (when graph (ipc/ipc "setCurrentGraph" graph))
  22. graph)]
  23. (atom
  24. {:route-match nil
  25. :today nil
  26. :system/events (async/chan 100)
  27. :db/batch-txs (async/chan 100)
  28. :file/writes (async/chan 100)
  29. :file/unlinked-dirs #{}
  30. :reactive/custom-queries (async/chan 100)
  31. :notification/show? false
  32. :notification/content nil
  33. :repo/loading-files? {}
  34. :nfs/user-granted? {}
  35. :nfs/refreshing? nil
  36. :instrument/disabled? (storage/get "instrument-disabled")
  37. ;; TODO: how to detect the network reliably?
  38. :network/online? true
  39. :indexeddb/support? true
  40. :me nil
  41. :git/current-repo current-graph
  42. :format/loading {}
  43. :draw? false
  44. :db/restoring? nil
  45. :journals-length 3
  46. :search/q ""
  47. :search/mode :global
  48. :search/result nil
  49. :search/graph-filters []
  50. ;; modals
  51. :modal/id nil
  52. :modal/label ""
  53. :modal/show? false
  54. :modal/panel-content nil
  55. :modal/fullscreen? false
  56. :modal/close-btn? nil
  57. :modal/subsets []
  58. ;; right sidebar
  59. :ui/fullscreen? false
  60. :ui/settings-open? false
  61. :ui/sidebar-open? false
  62. :ui/left-sidebar-open? (boolean (storage/get "ls-left-sidebar-open?"))
  63. :ui/theme (or (storage/get :ui/theme) "light")
  64. :ui/system-theme? ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
  65. :ui/custom-theme (or (storage/get :ui/custom-theme) {:light {:mode "light"} :dark {:mode "dark"}})
  66. :ui/wide-mode? (storage/get :ui/wide-mode)
  67. ;; ui/collapsed-blocks is to separate the collapse/expand state from db for:
  68. ;; 1. right sidebar
  69. ;; 2. zoom-in view
  70. ;; 3. queries
  71. ;; 4. references
  72. ;; graph => {:block-id bool}
  73. :ui/collapsed-blocks {}
  74. :ui/sidebar-collapsed-blocks {}
  75. :ui/root-component nil
  76. :ui/file-component nil
  77. :ui/custom-query-components {}
  78. :ui/show-recent? false
  79. :ui/command-palette-open? false
  80. :ui/developer-mode? (or (= (storage/get "developer-mode") "true")
  81. false)
  82. ;; remember scroll positions of visited paths
  83. :ui/paths-scroll-positions {}
  84. :ui/shortcut-tooltip? (if (false? (storage/get :ui/shortcut-tooltip?))
  85. false
  86. true)
  87. :ui/scrolling? false
  88. :document/mode? document-mode?
  89. :config {}
  90. :block/component-editing-mode? false
  91. :editor/draw-mode? false
  92. :editor/show-page-search? false
  93. :editor/show-page-search-hashtag? false
  94. :editor/show-date-picker? false
  95. ;; With label or other data
  96. :editor/show-input nil
  97. :editor/show-zotero false
  98. :editor/last-saved-cursor nil
  99. :editor/editing? nil
  100. :editor/in-composition? false
  101. :editor/content {}
  102. :editor/block nil
  103. :editor/block-dom-id nil
  104. :editor/set-timestamp-block nil
  105. :editor/last-input-time nil
  106. :editor/document-mode? document-mode?
  107. :editor/args nil
  108. :editor/on-paste? false
  109. :editor/last-key-code nil
  110. ;; for audio record
  111. :editor/record-status "NONE"
  112. :db/last-transact-time {}
  113. ;; whether database is persisted
  114. :db/persisted? {}
  115. :cursor-range nil
  116. :selection/mode false
  117. ;; Warning: blocks order is determined when setting this attribute
  118. :selection/blocks []
  119. :selection/start-block nil
  120. ;; either :up or :down, defaults to down
  121. ;; used to determine selection direction when two or more blocks are selected
  122. :selection/direction :down
  123. :custom-context-menu/show? false
  124. :custom-context-menu/links nil
  125. ;; pages or blocks in the right sidebar
  126. ;; It is a list of `[repo db-id block-type block-data]` 4-tuple
  127. :sidebar/blocks '()
  128. :preferred-language (storage/get :preferred-language)
  129. ;; electron
  130. :electron/auto-updater-downloaded false
  131. :electron/updater-pending? false
  132. :electron/updater {}
  133. :electron/user-cfgs nil
  134. ;; mobile
  135. :mobile/show-action-bar? false
  136. :mobile/actioned-block nil
  137. :mobile/show-toolbar? false
  138. :mobile/show-recording-bar? false
  139. ;;; toolbar icon doesn't update correctly when clicking after separate it from box,
  140. ;;; add a random in (<= 1000000) to observer its update
  141. :mobile/toolbar-update-observer 0
  142. :mobile/show-tabbar? false
  143. ;; plugin
  144. :plugin/enabled (and (util/electron?)
  145. ;; true false :theme-only
  146. ((fnil identity true) (storage/get :lsp-core-enabled)))
  147. :plugin/preferences nil
  148. :plugin/indicator-text nil
  149. :plugin/installed-plugins {}
  150. :plugin/installed-themes []
  151. :plugin/installed-slash-commands {}
  152. :plugin/installed-ui-items {}
  153. :plugin/installed-resources {}
  154. :plugin/installed-hooks {}
  155. :plugin/simple-commands {}
  156. :plugin/selected-theme nil
  157. :plugin/selected-unpacked-pkg nil
  158. :plugin/marketplace-pkgs nil
  159. :plugin/marketplace-stats nil
  160. :plugin/installing nil
  161. :plugin/active-readme nil
  162. :plugin/updates-pending {}
  163. :plugin/updates-coming {}
  164. :plugin/updates-downloading? false
  165. :plugin/updates-unchecked #{}
  166. :plugin/navs-settings? true
  167. :plugin/focused-settings nil ;; plugin id
  168. ;; pdf
  169. :pdf/current nil
  170. :pdf/ref-highlight nil
  171. ;; all notification contents as k-v pairs
  172. :notification/contents {}
  173. :graph/syncing? false
  174. ;; graph -> state
  175. :graph/parsing-state {}
  176. ;; copied blocks
  177. :copy/blocks {:copy/content nil
  178. :copy/graph nil
  179. :copy/blocks nil}
  180. :copy/export-block-text-indent-style (or (storage/get :copy/export-block-text-indent-style)
  181. "dashes")
  182. :copy/export-block-text-remove-options (or (storage/get :copy/export-block-text-remove-options)
  183. #{})
  184. :date-picker/date nil
  185. :youtube/players {}
  186. ;; command palette
  187. :command-palette/commands []
  188. :view/components {}
  189. :favorites/dragging nil
  190. :srs/mode? false
  191. :srs/cards-due-count nil
  192. :reactive/query-dbs {}
  193. ;; login, userinfo, token, ...
  194. :auth/refresh-token nil
  195. :auth/access-token nil
  196. :auth/id-token nil
  197. ;; file-sync
  198. :file-sync/sync-manager nil
  199. :file-sync/sync-state-manager nil
  200. :file-sync/sync-state nil
  201. :file-sync/sync-uploading-files nil
  202. :file-sync/sync-downloading-files nil
  203. :file-sync/download-init-progress nil
  204. :encryption/graph-parsing? false
  205. :ui/whiteboards {}
  206. })))
  207. ;; block uuid -> {content(String) -> ast}
  208. (def blocks-ast-cache (atom {}))
  209. (defn add-block-ast-cache!
  210. [block-uuid content ast]
  211. (when (and block-uuid content ast)
  212. (let [new-value (assoc-in @blocks-ast-cache [block-uuid content] ast)
  213. new-value (if (> (count new-value) 10000)
  214. (into {} (take 5000 new-value))
  215. new-value)]
  216. (reset! blocks-ast-cache new-value))))
  217. (defn get-block-ast
  218. [block-uuid content]
  219. (when (and block-uuid content)
  220. (get-in @blocks-ast-cache [block-uuid content])))
  221. (defn sub
  222. [ks]
  223. (if (coll? ks)
  224. (util/react (rum/cursor-in state ks))
  225. (util/react (rum/cursor state ks))))
  226. (defn get-route-match
  227. []
  228. (:route-match @state))
  229. (defn get-current-route
  230. []
  231. (get-in (get-route-match) [:data :name]))
  232. (defn home?
  233. []
  234. (= :home (get-current-route)))
  235. (defn setups-picker?
  236. []
  237. (= :repo-add (get-current-route)))
  238. (defn get-current-page
  239. []
  240. (when (= :page (get-current-route))
  241. (get-in (get-route-match)
  242. [:path-params :name])))
  243. (defn route-has-p?
  244. []
  245. (get-in (get-route-match) [:query-params :p]))
  246. (defn set-state!
  247. [path value]
  248. (if (vector? path)
  249. (swap! state assoc-in path value)
  250. (swap! state assoc path value)))
  251. (defn update-state!
  252. [path f]
  253. (if (vector? path)
  254. (swap! state update-in path f)
  255. (swap! state update path f)))
  256. (defn get-current-repo
  257. []
  258. (or (:git/current-repo @state)
  259. (when-not (mobile-util/native-platform?)
  260. "local")))
  261. (defn get-config
  262. ([]
  263. (get-config (get-current-repo)))
  264. ([repo-url]
  265. (get-in @state [:config repo-url])))
  266. (def default-arweave-gateway "https://arweave.net")
  267. (defn get-arweave-gateway
  268. []
  269. (:arweave/gateway (get-config) default-arweave-gateway))
  270. (defonce built-in-macros
  271. {"img" "[:img.$4 {:src \"$1\" :style {:width $2 :height $3}}]"})
  272. (defn get-macros
  273. []
  274. (merge
  275. built-in-macros
  276. (:macros (get-config))))
  277. (defn sub-config
  278. []
  279. (sub :config))
  280. (defn get-custom-css-link
  281. []
  282. (:custom-css-url (get-config)))
  283. (defn get-custom-js-link
  284. []
  285. (:custom-js-url (get-config)))
  286. (defn get-default-journal-template
  287. []
  288. (when-let [template (get-in (get-config) [:default-templates :journals])]
  289. (when-not (string/blank? template)
  290. (string/trim template))))
  291. (defn all-pages-public?
  292. []
  293. (let [value (:publishing/all-pages-public? (get-config))
  294. value (if (some? value) value (:all-pages-public? (get-config)))]
  295. (true? value)))
  296. (defn enable-grammarly?
  297. []
  298. (true? (:feature/enable-grammarly?
  299. (get (sub-config) (get-current-repo)))))
  300. ;; (defn store-block-id-in-file?
  301. ;; []
  302. ;; (true? (:block/store-id-in-file? (get-config))))
  303. (defn scheduled-deadlines-disabled?
  304. []
  305. (true? (:feature/disable-scheduled-and-deadline-query?
  306. (get (sub-config) (get-current-repo)))))
  307. (defn enable-timetracking?
  308. []
  309. (not (false? (:feature/enable-timetracking?
  310. (get (sub-config) (get-current-repo))))))
  311. (defn enable-journals?
  312. [repo]
  313. (not (false? (:feature/enable-journals?
  314. (get (sub-config) repo)))))
  315. (defn enable-flashcards?
  316. [repo]
  317. (not (false? (:feature/enable-flashcards?
  318. (get (sub-config) repo)))))
  319. (defn export-heading-to-list?
  320. []
  321. (not (false? (:export/heading-to-list?
  322. (get (sub-config) (get-current-repo))))))
  323. (defn enable-git-auto-push?
  324. [repo]
  325. (not (false? (:git-auto-push
  326. (get (sub-config) repo)))))
  327. (defn enable-block-timestamps?
  328. []
  329. (true? (:feature/enable-block-timestamps?
  330. (get (sub-config) (get-current-repo)))))
  331. (defn sub-graph-config
  332. []
  333. (get (sub-config) (get-current-repo)))
  334. (defn sub-graph-config-settings
  335. []
  336. (:graph/settings (sub-graph-config)))
  337. ;; Enable by default
  338. (defn show-brackets?
  339. []
  340. (not (false? (:ui/show-brackets?
  341. (get (sub-config) (get-current-repo))))))
  342. (defn get-default-home
  343. []
  344. (:default-home (get-config)))
  345. (defn sub-default-home-page
  346. []
  347. (get-in (sub-config) [(get-current-repo) :default-home :page] ""))
  348. (defn custom-home-page?
  349. []
  350. (some? (:page (get-default-home))))
  351. (defn get-preferred-format
  352. ([]
  353. (get-preferred-format (get-current-repo)))
  354. ([repo-url]
  355. (keyword
  356. (or
  357. (when-let [fmt (:preferred-format (get-config repo-url))]
  358. (string/lower-case (name fmt)))
  359. (get-in @state [:me :preferred_format] "markdown")))))
  360. ;; TODO: consider adding a pane in Settings to set this through the GUI (rather
  361. ;; than having to go through the config.edn file)
  362. (defn get-editor-command-trigger
  363. ([] (get-editor-command-trigger (get-current-repo)))
  364. ([repo-url]
  365. (or
  366. (:editor/command-trigger (get-config repo-url)) ;; Get from user config
  367. "/"))) ;; Set the default
  368. (defn markdown?
  369. []
  370. (= (keyword (get-preferred-format))
  371. :markdown))
  372. (defn get-pages-directory
  373. []
  374. (or
  375. (when-let [repo (get-current-repo)]
  376. (:pages-directory (get-config repo)))
  377. "pages"))
  378. (defn get-journals-directory
  379. []
  380. (or
  381. (when-let [repo (get-current-repo)]
  382. (:journals-directory (get-config repo)))
  383. "journals"))
  384. (defn org-mode-file-link?
  385. [repo]
  386. (:org-mode/insert-file-link? (get-config repo)))
  387. (defn get-journal-file-name-format
  388. []
  389. (when-let [repo (get-current-repo)]
  390. (:journal/file-name-format (get-config repo))))
  391. (defn get-preferred-workflow
  392. []
  393. (keyword
  394. (or
  395. (when-let [workflow (:preferred-workflow (get-config))]
  396. (let [workflow (name workflow)]
  397. (if (util/safe-re-find #"now|NOW" workflow)
  398. :now
  399. :todo)))
  400. (get-in @state [:me :preferred_workflow] :now))))
  401. (defn get-preferred-todo
  402. []
  403. (if (= (get-preferred-workflow) :now)
  404. "LATER"
  405. "TODO"))
  406. (defn page-name-order
  407. "Decide whether to use file name or :title as page name. If it returns \"file\", use the file
  408. name unless it is missing."
  409. []
  410. (:page-name-order (get-config)))
  411. (defn get-repos
  412. []
  413. (get-in @state [:me :repos]))
  414. (defn set-repos!
  415. [repos]
  416. (set-state! [:me :repos] repos))
  417. (defn add-repo!
  418. [repo]
  419. (when (not (string/blank? repo))
  420. (update-state! [:me :repos]
  421. (fn [repos]
  422. (->> (conj repos repo)
  423. (distinct))))))
  424. (defn set-current-repo!
  425. [repo]
  426. (swap! state assoc :git/current-repo repo)
  427. (if repo
  428. (storage/set :git/current-repo repo)
  429. (storage/remove :git/current-repo))
  430. (ipc/ipc "setCurrentGraph" repo))
  431. (defn set-preferred-format!
  432. [format]
  433. (swap! state assoc-in [:me :preferred_format] (name format)))
  434. (defn set-preferred-workflow!
  435. [workflow]
  436. (swap! state assoc-in [:me :preferred_workflow] (name workflow)))
  437. (defn set-preferred-language!
  438. [language]
  439. (set-state! :preferred-language (name language))
  440. (storage/set :preferred-language (name language)))
  441. (defn delete-repo!
  442. [repo]
  443. (swap! state update-in [:me :repos]
  444. (fn [repos]
  445. (->> (remove #(= (:url repo)
  446. (:url %))
  447. repos)
  448. (util/distinct-by :url)))))
  449. (defn set-timestamp-block!
  450. [value]
  451. (set-state! :editor/set-timestamp-block value))
  452. (defn get-timestamp-block
  453. []
  454. (:editor/set-timestamp-block @state))
  455. (defn set-edit-content!
  456. ([input-id value] (set-edit-content! input-id value true))
  457. ([input-id value set-input-value?]
  458. (when input-id
  459. (when set-input-value?
  460. (when-let [input (gdom/getElement input-id)]
  461. (util/set-change-value input value)))
  462. (update-state! :editor/content (fn [m]
  463. (assoc m input-id value))))))
  464. (defn get-edit-input-id
  465. []
  466. (ffirst (:editor/editing? @state)))
  467. (defn get-input
  468. []
  469. (when-let [id (get-edit-input-id)]
  470. (gdom/getElement id)))
  471. (defn editing?
  472. []
  473. (let [input (get-input)]
  474. (and input (= input (.-activeElement js/document)))))
  475. (defn get-edit-content
  476. []
  477. (get (:editor/content @state) (get-edit-input-id)))
  478. (defn sub-edit-content
  479. []
  480. (sub [:editor/content (get-edit-input-id)]))
  481. (defn get-cursor-range
  482. []
  483. (:cursor-range @state))
  484. (defn set-cursor-range!
  485. [range]
  486. (set-state! :cursor-range range))
  487. (defn set-q!
  488. [value]
  489. (set-state! :search/q value))
  490. (defn set-search-mode!
  491. [value]
  492. (set-state! :search/mode value))
  493. (defn set-editor-show-page-search!
  494. [value]
  495. (set-state! :editor/show-page-search? value))
  496. (defn get-editor-show-page-search?
  497. []
  498. (get @state :editor/show-page-search?))
  499. (defn set-editor-show-page-search-hashtag!
  500. [value]
  501. (set-state! :editor/show-page-search? value)
  502. (set-state! :editor/show-page-search-hashtag? value))
  503. (defn get-editor-show-page-search-hashtag?
  504. []
  505. (get @state :editor/show-page-search-hashtag?))
  506. (defn set-editor-show-block-search!
  507. [value]
  508. (set-state! :editor/show-block-search? value))
  509. (defn get-editor-show-block-search?
  510. []
  511. (get @state :editor/show-block-search?))
  512. (defn set-editor-show-template-search!
  513. [value]
  514. (set-state! :editor/show-template-search? value))
  515. (defn get-editor-show-template-search?
  516. []
  517. (get @state :editor/show-template-search?))
  518. (defn set-editor-show-date-picker!
  519. [value]
  520. (set-state! :editor/show-date-picker? value))
  521. (defn get-editor-show-date-picker?
  522. []
  523. (get @state :editor/show-date-picker?))
  524. (defn set-editor-show-input!
  525. [value]
  526. (set-state! :editor/show-input value))
  527. (defn get-editor-show-input
  528. []
  529. (get @state :editor/show-input))
  530. (defn set-editor-show-zotero!
  531. [value]
  532. (set-state! :editor/show-zotero value))
  533. ;; TODO: refactor, use one state
  534. (defn clear-editor-show-state!
  535. []
  536. (swap! state (fn [state]
  537. (assoc state
  538. :editor/show-input nil
  539. :editor/show-zotero false
  540. :editor/show-date-picker? false
  541. :editor/show-block-search? false
  542. :editor/show-template-search? false
  543. :editor/show-page-search? false
  544. :editor/show-page-search-hashtag? false))))
  545. (defn set-edit-input-id!
  546. [input-id]
  547. (swap! state update :editor/editing?
  548. (fn [_m]
  549. (and input-id {input-id true}))))
  550. (defn get-edit-pos
  551. []
  552. (when-let [input (get-input)]
  553. (util/get-selection-start input)))
  554. (defn set-selection-start-block!
  555. [start-block]
  556. (swap! state assoc :selection/start-block start-block))
  557. (defn get-selection-start-block
  558. []
  559. (get @state :selection/start-block))
  560. (defn set-selection-blocks!
  561. ([blocks]
  562. (set-selection-blocks! blocks :down))
  563. ([blocks direction]
  564. (when (seq blocks)
  565. (let [blocks (util/sort-by-height blocks)]
  566. (swap! state assoc
  567. :selection/mode true
  568. :selection/blocks blocks
  569. :selection/direction direction)))))
  570. (defn into-selection-mode!
  571. []
  572. (swap! state assoc :selection/mode true))
  573. (defn clear-selection!
  574. []
  575. (swap! state assoc
  576. :selection/mode false
  577. :selection/blocks nil
  578. :selection/direction :down
  579. :selection/start-block nil))
  580. (defn get-selection-blocks
  581. []
  582. (:selection/blocks @state))
  583. (defn get-selection-block-ids
  584. []
  585. (->> (sub :selection/blocks)
  586. (keep #(when-let [id (dom/attr % "blockid")]
  587. (uuid id)))
  588. (distinct)))
  589. (defn get-selection-start-block-or-first
  590. []
  591. (or (get-selection-start-block)
  592. (some-> (first (get-selection-blocks))
  593. (gobj/get "id"))))
  594. (defn in-selection-mode?
  595. []
  596. (:selection/mode @state))
  597. (defn selection?
  598. "True sense of selection mode with valid selected block"
  599. []
  600. (and (in-selection-mode?) (seq (get-selection-blocks))))
  601. (defn conj-selection-block!
  602. [block direction]
  603. (dom/add-class! block "selected noselect")
  604. (swap! state assoc
  605. :selection/mode true
  606. :selection/blocks (-> (conj (vec (:selection/blocks @state)) block)
  607. (util/sort-by-height))
  608. :selection/direction direction))
  609. (defn drop-last-selection-block!
  610. []
  611. (let [last-block (peek (vec (:selection/blocks @state)))]
  612. (swap! state assoc
  613. :selection/mode true
  614. :selection/blocks (pop (vec (:selection/blocks @state))))
  615. last-block))
  616. (defn get-selection-direction
  617. []
  618. (:selection/direction @state))
  619. (defn show-custom-context-menu!
  620. [links]
  621. (swap! state assoc
  622. :custom-context-menu/show? true
  623. :custom-context-menu/links links))
  624. (defn hide-custom-context-menu!
  625. []
  626. (swap! state assoc
  627. :custom-context-menu/show? false
  628. :custom-context-menu/links nil))
  629. (defn toggle-sidebar-open?!
  630. []
  631. (swap! state update :ui/sidebar-open? not))
  632. (defn open-right-sidebar!
  633. []
  634. (swap! state assoc :ui/sidebar-open? true))
  635. (defn hide-right-sidebar!
  636. []
  637. (swap! state assoc :ui/sidebar-open? false))
  638. (defn sidebar-add-block!
  639. [repo db-id block-type]
  640. (when (not (util/sm-breakpoint?))
  641. (when db-id
  642. (update-state! :sidebar/blocks (fn [blocks]
  643. (->> (remove #(= (second %) db-id) blocks)
  644. (cons [repo db-id block-type])
  645. (distinct))))
  646. (open-right-sidebar!)
  647. (when-let [elem (gdom/getElementByClass "cp__right-sidebar-scrollable")]
  648. (util/scroll-to elem 0)))))
  649. (defn sidebar-remove-block!
  650. [idx]
  651. (update-state! :sidebar/blocks (fn [blocks]
  652. (if (string? idx)
  653. (remove #(= (second %) idx) blocks)
  654. (util/drop-nth idx blocks))))
  655. (when (empty? (:sidebar/blocks @state))
  656. (hide-right-sidebar!)))
  657. (defn sidebar-replace-block!
  658. [old-sidebar-key new-sidebar-key]
  659. (update-state! :sidebar/blocks (fn [blocks]
  660. (map #(if (= % old-sidebar-key)
  661. new-sidebar-key
  662. %) blocks))))
  663. (defn sidebar-block-exists?
  664. [idx]
  665. (some #(= (second %) idx) (:sidebar/blocks @state)))
  666. (defn clear-sidebar-blocks!
  667. []
  668. (set-state! :sidebar/blocks '()))
  669. (defn sidebar-block-toggle-collapse!
  670. [db-id]
  671. (when db-id
  672. (update-state! [:ui/sidebar-collapsed-blocks db-id] not)))
  673. (defn get-edit-block
  674. []
  675. (get @state :editor/block))
  676. (defn get-current-edit-block-and-position
  677. []
  678. (let [edit-input-id (get-edit-input-id)
  679. edit-block (get-edit-block)
  680. block-element (when edit-input-id (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block")))
  681. container (when block-element
  682. (util/get-block-container block-element))]
  683. (when container
  684. {:last-edit-block edit-block
  685. :container (gobj/get container "id")
  686. :pos (cursor/pos (gdom/getElement edit-input-id))})))
  687. (defonce publishing? (atom nil))
  688. (defn publishing-enable-editing?
  689. []
  690. (and @publishing? (:publishing/enable-editing? (get-config))))
  691. (defn enable-editing?
  692. []
  693. (or (not @publishing?) (:publishing/enable-editing? (get-config))))
  694. (defn set-editing!
  695. ([edit-input-id content block cursor-range]
  696. (set-editing! edit-input-id content block cursor-range true))
  697. ([edit-input-id content block cursor-range move-cursor?]
  698. (when (and edit-input-id block
  699. (or
  700. (publishing-enable-editing?)
  701. (not @publishing?)))
  702. (let [block-element (gdom/getElement (string/replace edit-input-id "edit-block" "ls-block"))
  703. container (util/get-block-container block-element)
  704. block (if container
  705. (assoc block
  706. :block/container (gobj/get container "id"))
  707. block)
  708. content (string/trim (or content ""))]
  709. (swap! state
  710. (fn [state]
  711. (-> state
  712. (assoc-in [:editor/content edit-input-id] content)
  713. (assoc
  714. :editor/block block
  715. :editor/editing? {edit-input-id true}
  716. :editor/last-key-code nil
  717. :cursor-range cursor-range))))
  718. (when-let [input (gdom/getElement edit-input-id)]
  719. (let [pos (count cursor-range)]
  720. (when content
  721. (util/set-change-value input content))
  722. (when move-cursor?
  723. (cursor/move-cursor-to input pos))
  724. (when (or (util/mobile?) (mobile-util/native-platform?))
  725. (set-state! :mobile/show-action-bar? false))))))))
  726. (defn clear-edit!
  727. []
  728. (swap! state merge {:editor/editing? nil
  729. :editor/block nil
  730. :cursor-range nil
  731. :editor/last-saved-cursor nil}))
  732. (defn into-code-editor-mode!
  733. []
  734. (swap! state merge {:editor/editing? nil
  735. :cursor-range nil
  736. :editor/code-mode? true}))
  737. (defn set-editor-last-pos!
  738. [new-pos]
  739. (set-state! [:editor/last-saved-cursor (:block/uuid (get-edit-block))] new-pos))
  740. (defn clear-editor-last-pos!
  741. []
  742. (set-state! :editor/last-saved-cursor nil))
  743. (defn get-editor-last-pos
  744. []
  745. (get-in @state [:editor/last-saved-cursor (:block/uuid (get-edit-block))]))
  746. (defn set-block-content-and-last-pos!
  747. [edit-input-id content new-pos]
  748. (when edit-input-id
  749. (set-edit-content! edit-input-id content)
  750. (set-state! [:editor/last-saved-cursor (:block/uuid (get-edit-block))] new-pos)))
  751. (defn set-theme-mode!
  752. [mode]
  753. (when (mobile-util/native-ios?)
  754. (if (= mode "light")
  755. (util/set-theme-light)
  756. (util/set-theme-dark)))
  757. (set-state! :ui/theme mode)
  758. (storage/set :ui/theme mode))
  759. (defn sync-system-theme!
  760. []
  761. (let [system-dark? (.-matches (js/window.matchMedia "(prefers-color-scheme: dark)"))]
  762. (set-theme-mode! (if system-dark? "dark" "light"))
  763. (set-state! :ui/system-theme? true)
  764. (storage/set :ui/system-theme? true)))
  765. (defn use-theme-mode!
  766. [theme-mode]
  767. (if (= theme-mode "system")
  768. (sync-system-theme!)
  769. (do
  770. (set-theme-mode! theme-mode)
  771. (set-state! :ui/system-theme? false)
  772. (storage/set :ui/system-theme? false))))
  773. (defn toggle-theme
  774. [theme]
  775. (if (= theme "dark") "light" "dark"))
  776. (defn toggle-theme!
  777. []
  778. (use-theme-mode! (toggle-theme (:ui/theme @state))))
  779. (defn set-custom-theme!
  780. ([custom-theme]
  781. (set-custom-theme! nil custom-theme))
  782. ([mode theme]
  783. (set-state! (if mode [:ui/custom-theme (keyword mode)] :ui/custom-theme) theme)
  784. (storage/set :ui/custom-theme (:ui/custom-theme @state))))
  785. (defn set-editing-block-dom-id!
  786. [block-dom-id]
  787. (set-state! :editor/block-dom-id block-dom-id))
  788. (defn get-editing-block-dom-id
  789. []
  790. (:editor/block-dom-id @state))
  791. (defn set-root-component!
  792. [component]
  793. (set-state! :ui/root-component component))
  794. (defn get-root-component
  795. []
  796. (get @state :ui/root-component))
  797. (defn load-app-user-cfgs
  798. ([] (load-app-user-cfgs false))
  799. ([refresh?]
  800. (p/let [cfgs (if (or refresh? (nil? (:electron/user-cfgs @state)))
  801. (ipc/ipc "userAppCfgs")
  802. (:electron/user-cfgs @state))
  803. cfgs (if (object? cfgs) (bean/->clj cfgs) cfgs)]
  804. (set-state! :electron/user-cfgs cfgs))))
  805. (defn setup-electron-updater!
  806. []
  807. (when (util/electron?)
  808. (js/window.apis.setUpdatesCallback
  809. (fn [_ args]
  810. (let [data (bean/->clj args)
  811. pending? (not= (:type data) "completed")]
  812. (set-state! :electron/updater-pending? pending?)
  813. (when pending? (set-state! :electron/updater data))
  814. nil)))))
  815. (defn set-file-component!
  816. [component]
  817. (set-state! :ui/file-component component))
  818. (defn clear-file-component!
  819. []
  820. (set-state! :ui/file-component nil))
  821. (defn get-file-component
  822. []
  823. (get @state :ui/file-component))
  824. (defn set-journals-length!
  825. [value]
  826. (when value
  827. (set-state! :journals-length value)))
  828. (defn add-custom-query-component!
  829. [query-string component]
  830. (update-state! :ui/custom-query-components
  831. (fn [m]
  832. (assoc m query-string component))))
  833. (defn remove-custom-query-component!
  834. [query-string]
  835. (update-state! :ui/custom-query-components
  836. (fn [m]
  837. (dissoc m query-string))))
  838. (defn get-custom-query-components
  839. []
  840. (vals (get @state :ui/custom-query-components)))
  841. (defn save-scroll-position!
  842. ([value]
  843. (save-scroll-position! value js/window.location.hash))
  844. ([value path]
  845. (set-state! [:ui/paths-scroll-positions path] value)))
  846. (defn get-saved-scroll-position
  847. ([]
  848. (get-saved-scroll-position js/window.location.hash))
  849. ([path]
  850. (get-in @state [:ui/paths-scroll-positions path] 0)))
  851. (defn set-today!
  852. [value]
  853. (set-state! :today value))
  854. (defn get-date-formatter
  855. []
  856. (gp-config/get-date-formatter (get-config)))
  857. (defn shortcuts []
  858. (get-in @state [:config (get-current-repo) :shortcuts]))
  859. (defn get-me
  860. []
  861. (:me @state))
  862. (defn deprecated-logged?
  863. "Whether the user has logged in."
  864. []
  865. false)
  866. (defn set-db-restoring!
  867. [value]
  868. (set-state! :db/restoring? value))
  869. (defn set-indexedb-support!
  870. [value]
  871. (set-state! :indexeddb/support? value))
  872. (defn modal-opened?
  873. []
  874. (:modal/show? @state))
  875. (declare set-modal!)
  876. (declare close-modal!)
  877. (defn get-sub-modals
  878. []
  879. (:modal/subsets @state))
  880. (defn set-sub-modal!
  881. ([panel-content]
  882. (set-sub-modal! panel-content
  883. {:close-btn? true}))
  884. ([panel-content {:keys [id label close-btn? show? center?] :as opts}]
  885. (if (not (modal-opened?))
  886. (set-modal! panel-content opts)
  887. (let [modals (:modal/subsets @state)
  888. idx (and id (first (keep-indexed #(when (= (:modal/id %2) id) %1)
  889. modals)))
  890. input (medley/filter-vals
  891. #(not (nil? %1))
  892. {:modal/id id
  893. :modal/label (or label (if center? "ls-modal-align-center" ""))
  894. :modal/show? (if (boolean? show?) show? true)
  895. :modal/panel-content panel-content
  896. :modal/close-btn? close-btn?})]
  897. (swap! state update-in
  898. [:modal/subsets (or idx (count modals))]
  899. merge input)
  900. (:modal/subsets @state)))))
  901. (defn close-sub-modal!
  902. ([] (close-sub-modal! nil))
  903. ([all?-a-id]
  904. (if (true? all?-a-id)
  905. (swap! state assoc :modal/subsets [])
  906. (let [id all?-a-id
  907. mid (:modal/id @state)
  908. modals (:modal/subsets @state)]
  909. (if (and id (not (string/blank? mid)) (= id mid))
  910. (close-modal!)
  911. (when-let [idx (if id (first (keep-indexed #(when (= (:modal/id %2) id) %1) modals))
  912. (dec (count modals)))]
  913. (swap! state assoc :modal/subsets (into [] (medley/remove-nth idx modals)))))))
  914. (:modal/subsets @state)))
  915. (defn set-modal!
  916. ([modal-panel-content]
  917. (set-modal! modal-panel-content
  918. {:fullscreen? false
  919. :close-btn? true}))
  920. ([modal-panel-content {:keys [id label fullscreen? close-btn? center?]}]
  921. (when (seq (get-sub-modals))
  922. (close-sub-modal! true))
  923. (swap! state assoc
  924. :modal/id id
  925. :modal/label (or label (if center? "ls-modal-align-center" ""))
  926. :modal/show? (boolean modal-panel-content)
  927. :modal/panel-content modal-panel-content
  928. :modal/fullscreen? fullscreen?
  929. :modal/close-btn? close-btn?)))
  930. (defn close-modal!
  931. []
  932. (if (seq (get-sub-modals))
  933. (close-sub-modal!)
  934. (swap! state assoc
  935. :modal/id nil
  936. :modal/label ""
  937. :modal/show? false
  938. :modal/fullscreen? false
  939. :modal/panel-content nil
  940. :ui/open-select nil)))
  941. (defn get-db-batch-txs-chan
  942. []
  943. (:db/batch-txs @state))
  944. (defn get-file-write-chan
  945. []
  946. (:file/writes @state))
  947. (defn get-reactive-custom-queries-chan
  948. []
  949. (:reactive/custom-queries @state))
  950. (defn get-write-chan-length
  951. []
  952. (let [c (get-file-write-chan)]
  953. (count (gobj/get c "buf"))))
  954. (defn get-left-sidebar-open?
  955. []
  956. (get-in @state [:ui/left-sidebar-open?]))
  957. (defn set-left-sidebar-open!
  958. [value]
  959. (storage/set "ls-left-sidebar-open?" (boolean value))
  960. (set-state! :ui/left-sidebar-open? value))
  961. (defn toggle-left-sidebar!
  962. []
  963. (set-left-sidebar-open!
  964. (not (get-left-sidebar-open?))))
  965. (defn set-developer-mode!
  966. [value]
  967. (set-state! :ui/developer-mode? value)
  968. (storage/set "developer-mode" (str value)))
  969. (defn developer-mode?
  970. []
  971. (:ui/developer-mode? @state))
  972. (defn get-notification-contents
  973. []
  974. (get @state :notification/contents))
  975. (defn document-mode?
  976. []
  977. (get @state :document/mode?))
  978. (defn doc-mode-enter-for-new-line?
  979. []
  980. (and (document-mode?)
  981. (not (:shortcut/doc-mode-enter-for-new-block? (sub-graph-config)))))
  982. (defn toggle-document-mode!
  983. []
  984. (let [mode (document-mode?)]
  985. (set-state! :document/mode? (not mode))
  986. (storage/set :document/mode? (not mode))))
  987. (defn shortcut-tooltip-enabled?
  988. []
  989. (get @state :ui/shortcut-tooltip?))
  990. (defn toggle-shortcut-tooltip!
  991. []
  992. (let [mode (shortcut-tooltip-enabled?)]
  993. (set-state! :ui/shortcut-tooltip? (not mode))
  994. (storage/set :ui/shortcut-tooltip? (not mode))))
  995. (defn mobile?
  996. []
  997. (or (util/mobile?) (mobile-util/native-platform?)))
  998. (defn enable-tooltip?
  999. []
  1000. (if (mobile?)
  1001. false
  1002. (get (get (sub-config) (get-current-repo))
  1003. :ui/enable-tooltip?
  1004. true)))
  1005. (defn show-command-doc?
  1006. []
  1007. (get (get (sub-config) (get-current-repo))
  1008. :ui/show-command-doc?
  1009. true))
  1010. (defn set-config!
  1011. [repo-url value]
  1012. (set-state! [:config repo-url] value))
  1013. (defn get-wide-mode?
  1014. []
  1015. (:ui/wide-mode? @state))
  1016. (defn toggle-wide-mode!
  1017. []
  1018. (update-state! :ui/wide-mode? not))
  1019. (defn set-online!
  1020. [value]
  1021. (set-state! :network/online? value))
  1022. (defn get-commands
  1023. []
  1024. (:commands (get-config)))
  1025. (defn get-plugins-commands
  1026. []
  1027. (mapcat seq (flatten (vals (:plugin/installed-slash-commands @state)))))
  1028. (defn get-plugins-commands-with-type
  1029. [type]
  1030. (filterv #(= (keyword (first %)) (keyword type))
  1031. (apply concat (vals (:plugin/simple-commands @state)))))
  1032. (defn get-plugins-ui-items-with-type
  1033. [type]
  1034. (filterv #(= (keyword (first %)) (keyword type))
  1035. (apply concat (vals (:plugin/installed-ui-items @state)))))
  1036. (defn get-plugin-resources-with-type
  1037. [pid type]
  1038. (when-let [pid (and type (keyword pid))]
  1039. (get-in @state [:plugin/installed-resources pid (keyword type)])))
  1040. (defn get-plugin-resource
  1041. [pid type key]
  1042. (when-let [resources (get-plugin-resources-with-type pid type)]
  1043. (get resources key)))
  1044. (defn upt-plugin-resource
  1045. [pid type key attr val]
  1046. (when-let [resource (get-plugin-resource pid type key)]
  1047. (let [resource (assoc resource (keyword attr) val)]
  1048. (set-state!
  1049. [:plugin/installed-resources (keyword pid) (keyword type) key] resource)
  1050. resource)))
  1051. (defn install-plugin-hook
  1052. [pid hook]
  1053. (when-let [pid (keyword pid)]
  1054. (set-state!
  1055. [:plugin/installed-hooks hook]
  1056. (conj
  1057. ((fnil identity #{}) (get-in @state [:plugin/installed-hooks hook]))
  1058. pid)) true))
  1059. (defn uninstall-plugin-hook
  1060. [pid hook-or-all]
  1061. (when-let [pid (keyword pid)]
  1062. (if (nil? hook-or-all)
  1063. (swap! state update :plugin/installed-hooks #(update-vals % (fn [ids] (disj ids pid))))
  1064. (when-let [coll (get-in @state [:plugin/installed-hooks hook-or-all])]
  1065. (set-state! [:plugin/installed-hooks hook-or-all] (disj coll pid))))
  1066. true))
  1067. (defn get-scheduled-future-days
  1068. []
  1069. (let [days (:scheduled/future-days (get-config))]
  1070. (or (when (int? days) days) 0)))
  1071. (defn set-graph-syncing?
  1072. [value]
  1073. (set-state! :graph/syncing? value))
  1074. (defn set-editor-in-composition!
  1075. [value]
  1076. (set-state! :editor/in-composition? value))
  1077. (defn editor-in-composition?
  1078. []
  1079. (:editor/in-composition? @state))
  1080. (defn set-loading-files!
  1081. [repo value]
  1082. (when repo
  1083. (set-state! [:repo/loading-files? repo] value)))
  1084. (defn loading-files?
  1085. [repo]
  1086. (get-in @state [:repo/loading-files? repo]))
  1087. (defn set-editor-last-input-time!
  1088. [repo time]
  1089. (swap! state assoc-in [:editor/last-input-time repo] time))
  1090. (defn set-last-transact-time!
  1091. [repo time]
  1092. (swap! state assoc-in [:db/last-transact-time repo] time)
  1093. ;; THINK: new block, indent/outdent, drag && drop, etc.
  1094. (set-editor-last-input-time! repo time))
  1095. (defn set-db-persisted!
  1096. [repo value]
  1097. (swap! state assoc-in [:db/persisted? repo] value))
  1098. (defn db-idle?
  1099. [repo]
  1100. (when repo
  1101. (when-let [last-time (get-in @state [:db/last-transact-time repo])]
  1102. (let [now (util/time-ms)]
  1103. (>= (- now last-time) 3000)))))
  1104. (defn input-idle?
  1105. [repo]
  1106. (when repo
  1107. (or
  1108. (when-let [last-time (get-in @state [:editor/last-input-time repo])]
  1109. (let [now (util/time-ms)]
  1110. (>= (- now last-time) 500)))
  1111. ;; not in editing mode
  1112. (not (get-edit-input-id)))))
  1113. (defn set-nfs-refreshing!
  1114. [value]
  1115. (set-state! :nfs/refreshing? value))
  1116. (defn nfs-refreshing?
  1117. []
  1118. (:nfs/refreshing? @state))
  1119. (defn set-search-result!
  1120. [value]
  1121. (set-state! :search/result value))
  1122. (defn clear-search-result!
  1123. []
  1124. (set-search-result! nil))
  1125. (defn add-graph-search-filter!
  1126. [q]
  1127. (when-not (string/blank? q)
  1128. (update-state! :search/graph-filters
  1129. (fn [value]
  1130. (vec (distinct (conj value q)))))))
  1131. (defn remove-search-filter!
  1132. [q]
  1133. (when-not (string/blank? q)
  1134. (update-state! :search/graph-filters
  1135. (fn [value]
  1136. (remove #{q} value)))))
  1137. (defn clear-search-filters!
  1138. []
  1139. (set-state! :search/graph-filters []))
  1140. (defn get-search-mode
  1141. []
  1142. (:search/mode @state))
  1143. (defn toggle!
  1144. [path]
  1145. (update-state! path not))
  1146. (defn toggle-settings!
  1147. []
  1148. (toggle! :ui/settings-open?))
  1149. (defn settings-open?
  1150. []
  1151. (:ui/settings-open? @state))
  1152. (defn close-settings!
  1153. []
  1154. (set-state! :ui/settings-open? false))
  1155. (defn open-settings!
  1156. []
  1157. (set-state! :ui/settings-open? true))
  1158. ;; TODO: Move those to the uni `state`
  1159. (defonce editor-op (atom nil))
  1160. (defn set-editor-op!
  1161. [value]
  1162. (reset! editor-op value))
  1163. (defn get-editor-op
  1164. []
  1165. @editor-op)
  1166. (defn get-start-of-week
  1167. []
  1168. (or
  1169. (when-let [repo (get-current-repo)]
  1170. (get-in @state [:config repo :start-of-week]))
  1171. (get-in @state [:me :settings :start-of-week])
  1172. 6))
  1173. (defn get-ref-open-blocks-level
  1174. []
  1175. (or
  1176. (when-let [value (:ref/default-open-blocks-level (get-config))]
  1177. (when (integer? value)
  1178. value))
  1179. 2))
  1180. (defn get-linked-references-collapsed-threshold
  1181. []
  1182. (or
  1183. (when-let [value (:ref/linked-references-collapsed-threshold (get-config))]
  1184. (when (integer? value)
  1185. value))
  1186. 100))
  1187. (defn get-events-chan
  1188. []
  1189. (:system/events @state))
  1190. (defn pub-event!
  1191. [payload]
  1192. (let [chan (get-events-chan)]
  1193. (async/put! chan payload)))
  1194. (defn get-copied-blocks
  1195. []
  1196. (:copy/blocks @state))
  1197. (defn set-copied-blocks!
  1198. [content blocks]
  1199. (set-state! :copy/blocks {:copy/graph (get-current-repo)
  1200. :copy/content (or content (get-in @state [:copy/blocks :copy/content]))
  1201. :copy/blocks blocks}))
  1202. (defn get-export-block-text-indent-style []
  1203. (:copy/export-block-text-indent-style @state))
  1204. (defn set-export-block-text-indent-style!
  1205. [v]
  1206. (set-state! :copy/export-block-text-indent-style v)
  1207. (storage/set :copy/export-block-text-indent-style v))
  1208. (defn get-export-block-text-remove-options []
  1209. (:copy/export-block-text-remove-options @state))
  1210. (defn update-export-block-text-remove-options!
  1211. [e k]
  1212. (let [f (if (util/echecked? e) conj disj)]
  1213. (update-state! :copy/export-block-text-remove-options
  1214. #(f % k))
  1215. (storage/set :copy/export-block-text-remove-options
  1216. (get-export-block-text-remove-options))))
  1217. (defn set-editor-args!
  1218. [args]
  1219. (set-state! :editor/args args))
  1220. (defn block-component-editing?
  1221. []
  1222. (:block/component-editing-mode? @state))
  1223. (defn set-block-component-editing-mode!
  1224. [value]
  1225. (set-state! :block/component-editing-mode? value))
  1226. (defn logical-outdenting?
  1227. []
  1228. (:editor/logical-outdenting?
  1229. (get (sub-config) (get-current-repo))))
  1230. (defn get-editor-args
  1231. []
  1232. (:editor/args @state))
  1233. (defn get-export-bullet-indentation
  1234. []
  1235. (case (get (get-config) :export/bullet-indentation :tab)
  1236. :eight-spaces
  1237. " "
  1238. :four-spaces
  1239. " "
  1240. :two-spaces
  1241. " "
  1242. :tab
  1243. "\t"))
  1244. (defn set-page-blocks-cp!
  1245. [value]
  1246. (set-state! [:view/components :page-blocks] value))
  1247. (defn get-page-blocks-cp
  1248. []
  1249. (get-in @state [:view/components :page-blocks]))
  1250. ;; To avoid circular dependencies
  1251. (defn set-component!
  1252. [k value]
  1253. (set-state! [:view/components k] value))
  1254. (defn get-component
  1255. [k]
  1256. (get-in @state [:view/components k]))
  1257. (defn exit-editing-and-set-selected-blocks!
  1258. ([blocks]
  1259. (exit-editing-and-set-selected-blocks! blocks :down))
  1260. ([blocks direction]
  1261. (clear-edit!)
  1262. (set-selection-blocks! blocks direction)))
  1263. (defn remove-watch-state [key]
  1264. (remove-watch state key))
  1265. (defn get-git-auto-commit-enabled?
  1266. []
  1267. (false? (sub [:electron/user-cfgs :git/disable-auto-commit?])))
  1268. (defn set-last-key-code!
  1269. [key-code]
  1270. (set-state! :editor/last-key-code key-code))
  1271. (defn get-last-key-code
  1272. []
  1273. (:editor/last-key-code @state))
  1274. (defn get-plugin-by-id
  1275. [id]
  1276. (when-let [id (and id (keyword id))]
  1277. (get-in @state [:plugin/installed-plugins id])))
  1278. (defn get-enabled?-installed-plugins
  1279. ([theme?] (get-enabled?-installed-plugins theme? true false))
  1280. ([theme? enabled? include-unpacked?]
  1281. (filterv
  1282. #(and (if include-unpacked? true (:iir %))
  1283. (if-not (boolean? enabled?) true (= (not enabled?) (boolean (get-in % [:settings :disabled]))))
  1284. (= (boolean theme?) (:theme %)))
  1285. (vals (:plugin/installed-plugins @state)))))
  1286. (defn lsp-enabled?-or-theme
  1287. []
  1288. (:plugin/enabled @state))
  1289. (def lsp-enabled?
  1290. (lsp-enabled?-or-theme))
  1291. (defn consume-updates-coming-plugin
  1292. [payload updated?]
  1293. (when-let [id (keyword (:id payload))]
  1294. (let [pending? (boolean (seq (:plugin/updates-pending @state)))]
  1295. (swap! state update :plugin/updates-pending dissoc id)
  1296. (if updated?
  1297. (if-let [error (:error-code payload)]
  1298. (swap! state update-in [:plugin/updates-coming id] assoc :error-code error)
  1299. (swap! state update :plugin/updates-coming dissoc id))
  1300. (swap! state update :plugin/updates-coming assoc id payload))
  1301. (pub-event! [:plugin/consume-updates id pending? updated?]))))
  1302. (defn coming-update-new-version?
  1303. [pkg]
  1304. (and pkg (:latest-version pkg)))
  1305. (defn plugin-update-available?
  1306. [id]
  1307. (when-let [pkg (and id (get (:plugin/updates-coming @state) (keyword id)))]
  1308. (coming-update-new-version? pkg)))
  1309. (defn all-available-coming-updates
  1310. []
  1311. (when-let [updates (vals (:plugin/updates-coming @state))]
  1312. (filterv #(coming-update-new-version? %) updates)))
  1313. (defn get-next-selected-coming-update
  1314. []
  1315. (when-let [updates (all-available-coming-updates)]
  1316. (let [unchecked (:plugin/updates-unchecked @state)]
  1317. (first (filter #(and (not (and (seq unchecked) (contains? unchecked (:id %))))
  1318. (not (:error-code %))) updates)))))
  1319. (defn set-unchecked-update
  1320. [id unchecked?]
  1321. (swap! state update :plugin/updates-unchecked (if unchecked? conj disj) id))
  1322. (defn reset-unchecked-update
  1323. []
  1324. (swap! state assoc :plugin/updates-unchecked #{}))
  1325. (defn reset-all-updates-state
  1326. []
  1327. (swap! state assoc
  1328. :plugin/updates-pending {}
  1329. :plugin/updates-coming {}
  1330. :plugin/updates-downloading? false))
  1331. (defn sub-right-sidebar-blocks
  1332. []
  1333. (when-let [current-repo (get-current-repo)]
  1334. (->> (sub :sidebar/blocks)
  1335. (filter #(= (first %) current-repo)))))
  1336. (defn toggle-collapsed-block!
  1337. [block-id]
  1338. (let [current-repo (get-current-repo)]
  1339. (update-state! [:ui/collapsed-blocks current-repo block-id] not)))
  1340. (defn set-collapsed-block!
  1341. [block-id value]
  1342. (let [current-repo (get-current-repo)]
  1343. (set-state! [:ui/collapsed-blocks current-repo block-id] value)))
  1344. (defn sub-collapsed
  1345. [block-id]
  1346. (sub [:ui/collapsed-blocks (get-current-repo) block-id]))
  1347. (defn get-modal-id
  1348. []
  1349. (:modal/id @state))
  1350. (defn edit-in-query-component
  1351. []
  1352. (and (editing?)
  1353. ;; config
  1354. (:custom-query? (last (get-editor-args)))))
  1355. (defn set-auth-id-token
  1356. [id-token]
  1357. (set-state! :auth/id-token id-token))
  1358. (defn set-auth-refresh-token
  1359. [refresh-token]
  1360. (set-state! :auth/refresh-token refresh-token))
  1361. (defn set-auth-access-token
  1362. [access-token]
  1363. (set-state! :auth/access-token access-token))
  1364. (defn get-auth-id-token []
  1365. (:auth/id-token @state))
  1366. (defn get-auth-refresh-token []
  1367. (:auth/refresh-token @state))
  1368. (defn set-file-sync-manager [v]
  1369. (set-state! :file-sync/sync-manager v))
  1370. (defn set-file-sync-state [v]
  1371. (when v (s/assert :frontend.fs.sync/sync-state v))
  1372. (set-state! :file-sync/sync-state v))
  1373. (defn get-file-sync-manager []
  1374. (:file-sync/sync-manager @state))
  1375. (defn get-file-sync-state []
  1376. (:file-sync/sync-state @state))
  1377. (defn reset-file-sync-download-init-state!
  1378. []
  1379. (set-state! [:file-sync/download-init-progress (get-current-repo)] {}))
  1380. (defn set-file-sync-download-init-state!
  1381. [m]
  1382. (update-state! [:file-sync/download-init-progress (get-current-repo)]
  1383. (if (fn? m) m
  1384. (fn [old-value] (merge old-value m)))))
  1385. (defn get-file-sync-download-init-state
  1386. []
  1387. (get-in @state [:file-sync/download-init-progress (get-current-repo)]))
  1388. (defn reset-parsing-state!
  1389. []
  1390. (set-state! [:graph/parsing-state (get-current-repo)] {}))
  1391. (defn set-parsing-state!
  1392. [m]
  1393. (update-state! [:graph/parsing-state (get-current-repo)]
  1394. (if (fn? m) m
  1395. (fn [old-value] (merge old-value m)))))
  1396. (defn http-proxy-enabled-or-val? []
  1397. (when-let [agent-opts (sub [:electron/user-cfgs :settings/agent])]
  1398. (when (every? not-empty (vals agent-opts))
  1399. (str (:protocol agent-opts) "://" (:host agent-opts) ":" (:port agent-opts)))))
  1400. (defn enable-encryption?
  1401. [repo]
  1402. (:feature/enable-encryption?
  1403. (get (sub-config) repo)))
  1404. ;; FIXME:
  1405. (defn get-current-whiteboard
  1406. []
  1407. (second (first (:ui/whiteboards @state))))
  1408. (defn get-tldraw-api
  1409. []
  1410. (some-> (get-current-whiteboard)
  1411. (gobj/get "api")))
  1412. (defn unlinked-dir?
  1413. [dir]
  1414. (contains? (:file/unlinked-dirs @state) dir))