setups.cljs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. (ns frontend.components.onboarding.setups
  2. (:require [frontend.state :as state]
  3. [rum.core :as rum]
  4. [frontend.ui :as ui]
  5. [frontend.context.i18n :refer [t]]
  6. [frontend.components.svg :as svg]
  7. [frontend.components.widgets :as widgets]
  8. [frontend.handler.page :as page-handler]
  9. [frontend.handler.route :as route-handler]
  10. [frontend.handler.ui :as ui-handler]
  11. [frontend.util :as util]
  12. [frontend.handler.web.nfs :as nfs]
  13. [frontend.mobile.util :as mobile-util]
  14. [frontend.mobile.graph-picker :as graph-picker]
  15. [frontend.handler.notification :as notification]
  16. [frontend.handler.external :as external-handler]
  17. [frontend.modules.shortcut.core :as shortcut]
  18. [frontend.handler.user :as user-handler]
  19. [clojure.string :as string]
  20. [goog.object :as gobj]))
  21. (defonce DEVICE (if (util/mobile?) "phone" "computer"))
  22. (rum/defc setups-container
  23. [flag content]
  24. [:div.cp__onboarding-setups.flex.flex-1
  25. (let [picker? (= flag :picker)]
  26. [:div.inner-card.flex.flex-col.items-center
  27. [:h1.text-xl
  28. (if picker?
  29. [:span [:strong (ui/icon "heart")] "Welcome to " [:strong "Logseq!"]]
  30. [:span [:strong (ui/icon "file-import")] "Import existing notes"])]
  31. [:h2
  32. (if picker?
  33. "First you need to choose a folder where Logseq will store your thoughts, ideas, notes."
  34. "You can also do this later in the app.")]
  35. content])])
  36. (rum/defc mobile-intro
  37. []
  38. [:div.mobile-intro
  39. (cond
  40. (mobile-util/native-android?)
  41. [:div.px-4
  42. "You can save them in your local storage, and use Logseq Sync or any third-party sync service to keep your notes sync with other devices. "
  43. "If you prefer to use Dropbox to sync your notes, you can use "
  44. [:a {:href "https://play.google.com/store/apps/details?id=com.ttxapps.dropsync"
  45. :target "_blank"}
  46. "Dropsync"]
  47. ". Or you can use "
  48. [:a {:href "https://play.google.com/store/apps/details?id=dk.tacit.android.foldersync.lite"
  49. :target "_blank"}
  50. "FolderSync"]
  51. "."]
  52. :else
  53. nil)])
  54. (rum/defcs picker < rum/reactive
  55. [_state onboarding-and-home?]
  56. (let [parsing? (state/sub :repo/parsing-files?)
  57. _ (state/sub :auth/id-token)
  58. native-ios? (mobile-util/native-ios?)
  59. native-icloud? (not (string/blank? (state/sub [:mobile/container-urls :iCloudContainerUrl])))
  60. logged? (user-handler/logged-in?)]
  61. (setups-container
  62. :picker
  63. [:article.flex.w-full
  64. [:section.a.
  65. (when (and (mobile-util/native-platform?) (not native-ios?))
  66. (mobile-intro))
  67. (if native-ios?
  68. ;; TODO: open for all native mobile platforms
  69. (graph-picker/graph-picker-cp {:onboarding-and-home? onboarding-and-home?
  70. :logged? logged?
  71. :native-icloud? native-icloud?})
  72. (if (or (nfs/supported?) (mobile-util/native-platform?))
  73. [:div.choose.flex.flex-col.items-center
  74. {:on-click #(page-handler/ls-dir-files!
  75. (fn []
  76. (shortcut/refresh!)))}
  77. [:i]
  78. [:div.control
  79. [:label.action-input.flex.items-center.justify-center.flex-col
  80. {:disabled parsing?}
  81. (if parsing?
  82. (ui/loading "")
  83. [[:strong "Choose a folder"]
  84. [:small "Open existing directory or Create a new one"]])]]]
  85. [:div.px-5
  86. (ui/admonition :warning
  87. (widgets/native-fs-api-alert))]))]
  88. [:section.b.flex.items-center.flex-col
  89. [:p.flex
  90. [:i.as-flex-center (ui/icon "zoom-question" {:style {:fontSize "22px"}})]
  91. [:span.flex-1.flex.flex-col
  92. [:strong "How Logseq saves your work"]
  93. [:small.opacity-60 "Inside the directory you choose, Logseq will create 4 folders."]]]
  94. [:p.text-sm.pt-5.tracking-wide
  95. [:span (str "Each page is a file stored only on your " DEVICE ".")]
  96. [:br]
  97. [:span "You may choose to sync it later."]]
  98. [:ul
  99. (for [[title label icon]
  100. [["Graphics & Documents" "/assets" "whiteboard"]
  101. ["Daily notes" "/journals" "calendar-plus"]
  102. ["PAGES" "/pages" "page"]
  103. []
  104. ["APP Internal" "/logseq" "tool"]
  105. ["Config File" "/logseq/config.edn"]]]
  106. (if-not title
  107. [:li.hr]
  108. [:li
  109. {:key title}
  110. [:i.as-flex-center
  111. {:class (when (string/ends-with? label ".edn") "is-file")}
  112. (when icon (ui/icon icon))]
  113. [:span
  114. [:strong.uppercase title]
  115. [:small.opacity-50 label]]]))]]])))
  116. (defonce *opml-imported-pages (atom nil))
  117. (defn- finished-cb
  118. []
  119. (route-handler/redirect-to-home!)
  120. (notification/show! "Import finished!" :success)
  121. (ui-handler/re-render-root!))
  122. (defn- roam-import-handler
  123. [e]
  124. (let [file (first (array-seq (.-files (.-target e))))
  125. file-name (gobj/get file "name")]
  126. (if (string/ends-with? file-name ".json")
  127. (do
  128. (state/set-state! :graph/importing :roam-json)
  129. (let [reader (js/FileReader.)]
  130. (set! (.-onload reader)
  131. (fn [e]
  132. (let [text (.. e -target -result)]
  133. (external-handler/import-from-roam-json!
  134. text
  135. #(do
  136. (state/set-state! :graph/importing nil)
  137. (finished-cb))))))
  138. (.readAsText reader file)))
  139. (notification/show! "Please choose a JSON file."
  140. :error))))
  141. (defn- lsq-import-handler
  142. [e]
  143. (let [file (first (array-seq (.-files (.-target e))))
  144. file-name (some-> (gobj/get file "name")
  145. (string/lower-case))
  146. edn? (string/ends-with? file-name ".edn")
  147. json? (string/ends-with? file-name ".json")]
  148. (if (or edn? json?)
  149. (do
  150. (state/set-state! :graph/importing :logseq)
  151. (let [reader (js/FileReader.)
  152. import-f (if edn?
  153. external-handler/import-from-edn!
  154. external-handler/import-from-json!)]
  155. (set! (.-onload reader)
  156. (fn [e]
  157. (let [text (.. e -target -result)]
  158. (import-f
  159. text
  160. #(do
  161. (state/set-state! :graph/importing nil)
  162. (finished-cb))))))
  163. (.readAsText reader file)))
  164. (notification/show! "Please choose an EDN or a JSON file."
  165. :error))))
  166. (defn- opml-import-handler
  167. [e]
  168. (let [file (first (array-seq (.-files (.-target e))))
  169. file-name (gobj/get file "name")]
  170. (if (string/ends-with? file-name ".opml")
  171. (do
  172. (state/set-state! :graph/importing :opml)
  173. (let [reader (js/FileReader.)]
  174. (set! (.-onload reader)
  175. (fn [e]
  176. (let [text (.. e -target -result)]
  177. (external-handler/import-from-opml! text
  178. (fn [pages]
  179. (reset! *opml-imported-pages pages)
  180. (state/set-state! :graph/importing nil)
  181. (finished-cb))))))
  182. (.readAsText reader file)))
  183. (notification/show! "Please choose a OPML file."
  184. :error))))
  185. (rum/defc importer < rum/reactive
  186. [{:keys [query-params]}]
  187. (if (state/sub :graph/importing)
  188. (let [{:keys [total current-idx current-page]} (state/sub :graph/importing-state)
  189. left-label [:div.flex.flex-row.font-bold
  190. (t :importing)
  191. [:div.hidden.md:flex.flex-row
  192. [:span.mr-1 ": "]
  193. [:div.text-ellipsis-wrapper {:style {:max-width 300}}
  194. current-page]]]
  195. width (js/Math.round (* (.toFixed (/ current-idx total) 2) 100))
  196. process (when (and total current-idx)
  197. (str current-idx "/" total))]
  198. (ui/progress-bar-with-label width left-label process))
  199. (setups-container
  200. :importer
  201. [:article.flex.flex-col.items-center.importer.py-16.px-8
  202. [:section.c.text-center
  203. [:h1 "Do you already have notes that you want to import?"]
  204. [:h2 "If they are in a JSON, EDN or Markdown format Logseq can work with them."]]
  205. [:section.d.md:flex
  206. [:label.action-input.flex.items-center.mx-2.my-2
  207. [:span.as-flex-center [:i (svg/roam-research 28)]]
  208. [:div.flex.flex-col
  209. [[:strong "RoamResearch"]
  210. [:small "Import a JSON Export of your Roam graph"]]]
  211. [:input.absolute.hidden
  212. {:id "import-roam"
  213. :type "file"
  214. :on-change roam-import-handler}]]
  215. [:label.action-input.flex.items-center.mx-2.my-2
  216. [:span.as-flex-center [:i (svg/logo 28)]]
  217. [:span.flex.flex-col
  218. [[:strong "EDN / JSON"]
  219. [:small "Import an EDN or a JSON Export of your Logseq graph"]]]
  220. [:input.absolute.hidden
  221. {:id "import-lsq"
  222. :type "file"
  223. :on-change lsq-import-handler}]]
  224. [:label.action-input.flex.items-center.mx-2.my-2
  225. [:span.as-flex-center (ui/icon "sitemap" {:style {:fontSize "26px"}})]
  226. [:span.flex.flex-col
  227. [[:strong "OPML"]
  228. [:small " Import OPML files"]]]
  229. [:input.absolute.hidden
  230. {:id "import-opml"
  231. :type "file"
  232. :on-change opml-import-handler}]]]
  233. (when (= "picker" (:from query-params))
  234. [:section.e
  235. [:a.button {:on-click #(route-handler/redirect-to-home!)} "Skip"]])])))