mirror of
https://github.com/logseq/logseq.git
synced 2026-06-01 19:01:22 +00:00
Merge branch 'master' into refactor/core
This commit is contained in:
@@ -3,9 +3,10 @@
|
||||
[electron.updater :refer [init-updater]]
|
||||
[electron.utils :refer [mac? win32? prod? dev? logger open]]
|
||||
[clojure.string :as string]
|
||||
["fs" :as fs]
|
||||
[promesa.core :as p]
|
||||
["fs-extra" :as fs]
|
||||
["path" :as path]
|
||||
["electron" :refer [BrowserWindow app protocol ipcMain] :as electron]
|
||||
["electron" :refer [BrowserWindow app protocol ipcMain dialog] :as electron]
|
||||
[clojure.core.async :as async]
|
||||
[electron.state :as state]))
|
||||
|
||||
@@ -54,10 +55,44 @@
|
||||
(callback #js {:path path}))))
|
||||
#(.unregisterProtocol protocol "assets"))
|
||||
|
||||
(defn- handle-export-publish-assets [_event html]
|
||||
(let [app-path (. app getAppPath)
|
||||
paths (js->clj (. dialog showOpenDialogSync (clj->js {:properties ["openDirectory" "createDirectory" "promptToCreate", "multiSelections"]})))]
|
||||
(when (seq paths)
|
||||
(let [root-dir (first paths)
|
||||
static-dir (path/join root-dir "static")
|
||||
path (path/join root-dir "index.html")]
|
||||
(p/let [_ (. fs ensureDir static-dir)
|
||||
_ (p/all (concat
|
||||
[(. fs writeFile path html)
|
||||
(. fs copy (path/join app-path "404.html") (path/join root-dir "404.html"))]
|
||||
|
||||
(map
|
||||
(fn [part]
|
||||
(. fs copy (path/join app-path part) (path/join static-dir part)))
|
||||
["css" "fonts" "icons" "img" "js"])))
|
||||
js-files ["main.js" "code-editor.js" "excalidraw.js"]
|
||||
_ (p/all (map (fn [file]
|
||||
(. fs removeSync (path/join static-dir "js" file)))
|
||||
js-files))
|
||||
_ (p/all (map (fn [file]
|
||||
(. fs moveSync
|
||||
(path/join static-dir "js" "publishing" file)
|
||||
(path/join static-dir "js" file)))
|
||||
js-files))
|
||||
_ (. fs removeSync (path/join static-dir "js" "publishing"))
|
||||
;; remove source map files
|
||||
;; TODO: ugly, replace with ls-files and filter with ".map"
|
||||
_ (p/all (map (fn [file]
|
||||
(. fs removeSync (path/join static-dir "js" (str file ".map"))))
|
||||
["main.js" "code-editor.js" "excalidraw.js" "age-encryption.js"]))]
|
||||
(. dialog showMessageBox (clj->js {:message (str "Export publish assets to " root-dir " successfully")})))))))
|
||||
|
||||
(defn setup-app-manager!
|
||||
[^js win]
|
||||
(let [toggle-win-channel "toggle-max-or-min-active-win"
|
||||
call-app-channel "call-application"
|
||||
export-publish-assets "export-publish-assets"
|
||||
web-contents (. win -webContents)]
|
||||
(doto ipcMain
|
||||
(.handle toggle-win-channel
|
||||
@@ -70,6 +105,9 @@
|
||||
(if (.isMaximized active-win)
|
||||
(.unmaximize active-win)
|
||||
(.maximize active-win))))))
|
||||
|
||||
(.handle export-publish-assets handle-export-publish-assets)
|
||||
|
||||
(.handle call-app-channel
|
||||
(fn [_ type & args]
|
||||
(try
|
||||
@@ -91,10 +129,12 @@
|
||||
(.on "leave-full-screen" #(.send web-contents "full-screen" "leave")))
|
||||
|
||||
#(do (.removeHandler ipcMain toggle-win-channel)
|
||||
(.removeHandler ipcMain export-publish-assets)
|
||||
(.removeHandler ipcMain call-app-channel))))
|
||||
|
||||
(defonce *win (atom nil))
|
||||
|
||||
|
||||
(defn- destroy-window!
|
||||
[^js win]
|
||||
(.destroy win))
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
;; TODO: Is it going to be slow if it's a huge directory
|
||||
(defmethod handle :openDir [^js window _messages]
|
||||
(let [result (.showOpenDialogSync dialog (bean/->js
|
||||
{:properties ["openDirectory"]}))
|
||||
{:properties ["openDirectory" "createDirectory" "promptToCreate"]}))
|
||||
path (first result)]
|
||||
(.. ^js window -webContents
|
||||
(send "open-dir-confirmed"
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
[lambdaisland.glogi :as log]
|
||||
[frontend.context.i18n :as i18n]
|
||||
[frontend.template :as template]
|
||||
[shadow.loader :as loader]))
|
||||
[shadow.loader :as loader]
|
||||
[frontend.search :as search]))
|
||||
|
||||
;; TODO: remove rum/with-context because it'll make reactive queries not working
|
||||
|
||||
@@ -638,7 +639,7 @@
|
||||
[:span.warning {:title "Invalid link"} full_text]
|
||||
|
||||
;; image
|
||||
(some (fn [fmt] (re-find (re-pattern (str "(?i)\\." fmt)) s)) img-formats)
|
||||
(text/image-link? img-formats s)
|
||||
(image-link config url s label metadata full_text)
|
||||
|
||||
(= \# (first s))
|
||||
@@ -676,7 +677,7 @@
|
||||
(block-reference config (:link (second url)))
|
||||
|
||||
(= protocol "file")
|
||||
(if (some (fn [fmt] (re-find (re-pattern (str "(?i)\\." fmt)) href)) img-formats)
|
||||
(if (text/image-link? img-formats href)
|
||||
(image-link config url href label metadata full_text)
|
||||
(let [label-text (get-label-text label)
|
||||
page (if (string/blank? label-text)
|
||||
@@ -701,7 +702,7 @@
|
||||
(map-inline config label)))))
|
||||
|
||||
;; image
|
||||
(some (fn [fmt] (re-find (re-pattern (str "(?i)\\." fmt)) href)) img-formats)
|
||||
(text/image-link? img-formats href)
|
||||
(image-link config url href label metadata full_text)
|
||||
|
||||
:else
|
||||
@@ -803,7 +804,7 @@
|
||||
[:iframe
|
||||
{:allow-full-screen "allowfullscreen"
|
||||
:allow
|
||||
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope"
|
||||
:frame-border "0"
|
||||
:src (str "https://www.youtube.com/embed/" youtube-id)
|
||||
:height height
|
||||
@@ -820,7 +821,7 @@
|
||||
[:iframe
|
||||
{:allow-full-screen "allowfullscreen"
|
||||
:allow
|
||||
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope"
|
||||
:frame-border "0"
|
||||
:src (str "https://player.vimeo.com/video/" vimeo-id)
|
||||
:height height
|
||||
@@ -889,13 +890,50 @@
|
||||
(get name))
|
||||
(get (state/get-macros) name)
|
||||
(get (state/get-macros) (keyword name)))
|
||||
macro-content (if (and (seq arguments) macro-content)
|
||||
macro-content (cond
|
||||
(= (str name) "img")
|
||||
(case (count arguments)
|
||||
1
|
||||
(util/format "[:img {:src \"%s\"}]" (first arguments))
|
||||
4
|
||||
(if (and (util/safe-parse-int (nth arguments 1))
|
||||
(util/safe-parse-int (nth arguments 2)))
|
||||
(util/format "[:img.%s {:src \"%s\" :style {:width %s :height %s}}]"
|
||||
(nth arguments 3)
|
||||
(first arguments)
|
||||
(util/safe-parse-int (nth arguments 1))
|
||||
(util/safe-parse-int (nth arguments 2))))
|
||||
3
|
||||
(if (and (util/safe-parse-int (nth arguments 1))
|
||||
(util/safe-parse-int (nth arguments 2)))
|
||||
(util/format "[:img {:src \"%s\" :style {:width %s :height %s}}]"
|
||||
(first arguments)
|
||||
(util/safe-parse-int (nth arguments 1))
|
||||
(util/safe-parse-int (nth arguments 2))))
|
||||
|
||||
2
|
||||
(cond
|
||||
(and (util/safe-parse-int (nth arguments 1)))
|
||||
(util/format "[:img {:src \"%s\" :style {:width %s}}]"
|
||||
(first arguments)
|
||||
(util/safe-parse-int (nth arguments 1)))
|
||||
(contains? #{"left" "right" "center"} (string/lower-case (nth arguments 1)))
|
||||
(util/format "[:img.%s {:src \"%s\"}]"
|
||||
(string/lower-case (nth arguments 1))
|
||||
(first arguments))
|
||||
:else
|
||||
macro-content)
|
||||
|
||||
macro-content)
|
||||
|
||||
(and (seq arguments) macro-content)
|
||||
(block/macro-subs macro-content arguments)
|
||||
|
||||
:else
|
||||
macro-content)
|
||||
macro-content (when macro-content
|
||||
(template/resolve-dynamic-template! macro-content))]
|
||||
(render-macro config name arguments macro-content format))
|
||||
|
||||
(when-let [macro-txt (macro->text name arguments)]
|
||||
(let [macro-txt (when macro-txt
|
||||
(template/resolve-dynamic-template! macro-txt))
|
||||
@@ -1747,7 +1785,15 @@
|
||||
[state]
|
||||
(let [[config query] (:rum/args state)
|
||||
query-atom (if (:dsl-query? config)
|
||||
(query-dsl/query (state/get-current-repo) (:query query))
|
||||
(let [result (query-dsl/query (state/get-current-repo) (:query query))]
|
||||
(if (string? result) ; full-text search
|
||||
(atom
|
||||
(if (string/blank? result)
|
||||
[]
|
||||
(let [blocks (search/block-search result 50)]
|
||||
(when (seq blocks)
|
||||
(db/pull-many (state/get-current-repo) '[*] (map (fn [b] [:block/uuid (uuid (:block/uuid b))]) blocks))))))
|
||||
result))
|
||||
(db/custom-query query))]
|
||||
(assoc state :query-atom query-atom)))
|
||||
|
||||
@@ -2041,6 +2087,7 @@
|
||||
(fn [acc block]
|
||||
(let [block (dissoc block :block/meta)
|
||||
level (:block/level block)
|
||||
config (assoc config :block/uuid (:block/uuid block))
|
||||
block-cp (if build-block-fn
|
||||
(build-block-fn config block)
|
||||
(rum/with-key
|
||||
|
||||
@@ -321,6 +321,10 @@
|
||||
38 (editor-handler/keydown-up-down-handler input true)
|
||||
;; down
|
||||
40 (editor-handler/keydown-up-down-handler input false)
|
||||
;; left
|
||||
37 (editor-handler/keydown-arrow-handler input :left)
|
||||
;; right
|
||||
39 (editor-handler/keydown-arrow-handler input :right)
|
||||
;; backspace
|
||||
8 (editor-handler/keydown-backspace-handler repo input input-id)
|
||||
;; tab
|
||||
|
||||
30
src/main/frontend/components/export.cljs
Normal file
30
src/main/frontend/components/export.cljs
Normal file
@@ -0,0 +1,30 @@
|
||||
(ns frontend.components.export
|
||||
(:require [rum.core :as rum]
|
||||
[frontend.ui :as ui]
|
||||
[frontend.util :as util]
|
||||
[frontend.handler.export :as export]
|
||||
[frontend.state :as state]
|
||||
[frontend.context.i18n :as i18n]))
|
||||
|
||||
(rum/defc export
|
||||
[]
|
||||
(when-let [current-repo (state/get-current-repo)]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div.export.w-96
|
||||
[:h1.title "Export"]
|
||||
|
||||
[:ul.mr-1
|
||||
(when (util/electron?)
|
||||
[:li.mb-4
|
||||
[:a.font-medium {:on-click #(export/export-repo-as-html! current-repo)}
|
||||
(t :export-public-pages)]])
|
||||
[:li.mb-4
|
||||
[:a.font-medium {:on-click #(export/export-repo-as-markdown! current-repo)}
|
||||
(t :export-markdown)]]
|
||||
[:li.mb-4
|
||||
[:a.font-medium {:on-click #(export/export-repo-as-edn! current-repo)}
|
||||
(t :export-edn)]]]
|
||||
[:a#download-as-edn.hidden]
|
||||
[:a#download-as-html.hidden]
|
||||
[:a#download-as-zip.hidden]
|
||||
[:a#export-as-markdown.hidden]])))
|
||||
@@ -11,10 +11,10 @@
|
||||
[frontend.context.i18n :as i18n]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
[frontend.handler.user :as user-handler]
|
||||
[frontend.handler.export :as export]
|
||||
[frontend.components.svg :as svg]
|
||||
[frontend.components.repo :as repo]
|
||||
[frontend.components.search :as search]
|
||||
[frontend.components.export :as export]
|
||||
[frontend.handler.project :as project-handler]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.handler.web.nfs :as nfs]
|
||||
@@ -128,9 +128,9 @@
|
||||
|
||||
(when current-repo
|
||||
{:title (t :export)
|
||||
:options {:on-click (fn []
|
||||
(export/export-repo-as-html! current-repo))}
|
||||
:options {:on-click #(state/set-modal! export/export)}
|
||||
:icon nil})
|
||||
|
||||
(when current-repo
|
||||
{:title (t :import)
|
||||
:options {:href (rfe/href :import)}
|
||||
@@ -148,7 +148,7 @@
|
||||
(remove nil?))
|
||||
;; {:links-footer (when (and (util/electron?) (not logged?))
|
||||
;; [:div.px-2.py-2 (login logged?)])}
|
||||
)))
|
||||
)))
|
||||
|
||||
(rum/defc header
|
||||
< rum/reactive
|
||||
@@ -212,7 +212,4 @@
|
||||
(dropdown-menu {:me me
|
||||
:t t
|
||||
:current-repo current-repo
|
||||
:default-home default-home})
|
||||
|
||||
[:a#download-as-html.hidden]
|
||||
[:a#download-as-zip.hidden]])))
|
||||
:default-home default-home})])))
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
(let [;; Don't edit the journal title
|
||||
page (string/lower-case title)
|
||||
repo (state/sub :git/current-repo)
|
||||
encoded-page-name (util/encode-str page)
|
||||
today? (= (string/lower-case title)
|
||||
(string/lower-case (date/journal-name)))
|
||||
intro? (and (not (state/logged?))
|
||||
|
||||
@@ -241,8 +241,8 @@
|
||||
[:tr [:td (t :help/new-line-in-block)] [:td "Shift-Enter"]]
|
||||
[:tr [:td (t :undo)] [:td (util/->platform-shortcut "Ctrl-z")]]
|
||||
[:tr [:td (t :redo)] [:td (util/->platform-shortcut "Ctrl-y")]]
|
||||
[:tr [:td (t :help/zoom-in)] [:td (util/->platform-shortcut (if util/mac? "Alt-." "Alt-Right"))]]
|
||||
[:tr [:td (t :help/zoom-out)] [:td (util/->platform-shortcut (if util/mac? "Alt-," "Alt-left"))]]
|
||||
[:tr [:td (t :help/zoom-in)] [:td (util/->platform-shortcut (if util/mac? "Cmd-." "Alt-Right"))]]
|
||||
[:tr [:td (t :help/zoom-out)] [:td (util/->platform-shortcut (if util/mac? "Cmd-," "Alt-left"))]]
|
||||
[:tr [:td (t :help/follow-link-under-cursor)] [:td (util/->platform-shortcut "Ctrl-o")]]
|
||||
[:tr [:td (t :help/open-link-in-sidebar)] [:td (util/->platform-shortcut "Ctrl-shift-o")]]
|
||||
[:tr [:td (t :expand)] [:td (util/->platform-shortcut "Ctrl-Down")]]
|
||||
@@ -268,7 +268,7 @@
|
||||
[:tr [:td (t :help/toggle-right-sidebar)] [:td "t r"]]
|
||||
[:tr [:td (t :help/toggle-settings)] [:td "t s"]]
|
||||
[:tr [:td (t :help/toggle-insert-new-block)] [:td "t e"]]
|
||||
[:tr [:td (t :help/jump-to-journals)] [:td (util/->platform-shortcut "Ctrl-j")]]]]
|
||||
[:tr [:td (t :help/jump-to-journals)] [:td (if util/mac? "Cmd-j" "Alt-j")]]]]
|
||||
[:table
|
||||
[:thead
|
||||
[:tr
|
||||
|
||||
@@ -173,14 +173,14 @@
|
||||
|
||||
(rum/defcs rename-page-dialog-inner <
|
||||
(rum/local "" ::input)
|
||||
[state page-name close-fn]
|
||||
[state title page-name close-fn]
|
||||
(let [input (get state ::input)]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div.w-full.sm:max-w-lg.sm:w-96
|
||||
[:div.sm:flex.sm:items-start
|
||||
[:div.mt-3.text-center.sm:mt-0.sm:text-left
|
||||
[:h3#modal-headline.text-lg.leading-6.font-medium
|
||||
(t :page/rename-to page-name)]]]
|
||||
(t :page/rename-to title)]]]
|
||||
|
||||
[:input.form-input.block.w-full.sm:text-sm.sm:leading-5.my-2
|
||||
{:auto-focus true
|
||||
@@ -193,11 +193,10 @@
|
||||
[:button.inline-flex.justify-center.w-full.rounded-md.border.border-transparent.px-4.py-2.bg-indigo-600.text-base.leading-6.font-medium.text-white.shadow-sm.hover:bg-indigo-500.focus:outline-none.focus:border-indigo-700.focus:shadow-outline-indigo.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
|
||||
{:type "button"
|
||||
:on-click (fn []
|
||||
(let [value @input]
|
||||
(let [value (string/trim value)]
|
||||
(when-not (string/blank? value)
|
||||
(page-handler/rename! page-name value)
|
||||
(state/close-modal!)))))}
|
||||
(let [value (string/trim @input)]
|
||||
(when-not (string/blank? value)
|
||||
(page-handler/rename! page-name value)
|
||||
(state/close-modal!))))}
|
||||
(t :submit)]]
|
||||
[:span.mt-3.flex.w-full.rounded-md.shadow-sm.sm:mt-0.sm:w-auto
|
||||
[:button.inline-flex.justify-center.w-full.rounded-md.border.border-gray-300.px-4.py-2.bg-white.text-base.leading-6.font-medium.text-gray-700.shadow-sm.hover:text-gray-500.focus:outline-none.focus:border-blue-300.focus:shadow-outline-blue.transition.ease-in-out.duration-150.sm:text-sm.sm:leading-5
|
||||
@@ -206,9 +205,9 @@
|
||||
(t :cancel)]]]])))
|
||||
|
||||
(defn rename-page-dialog
|
||||
[page-name]
|
||||
[title page-name]
|
||||
(fn [close-fn]
|
||||
(rename-page-dialog-inner page-name close-fn)))
|
||||
(rename-page-dialog-inner title page-name close-fn)))
|
||||
|
||||
(defn tagged-pages
|
||||
[repo tag]
|
||||
@@ -235,9 +234,8 @@
|
||||
[state {:keys [repo] :as option}]
|
||||
(let [current-repo (state/sub :git/current-repo)
|
||||
repo (or repo current-repo)
|
||||
encoded-page-name (or (get-page-name state)
|
||||
(state/get-current-page))
|
||||
path-page-name (util/url-decode encoded-page-name)
|
||||
path-page-name (or (get-page-name state)
|
||||
(state/get-current-page))
|
||||
page-name (string/lower-case path-page-name)
|
||||
marker-page? (util/marker? page-name)
|
||||
priority-page? (contains? #{"a" "b" "c"} page-name)
|
||||
@@ -303,7 +301,7 @@
|
||||
|
||||
(when-not contents?
|
||||
{:title (t :page/rename)
|
||||
:options {:on-click #(state/set-modal! (rename-page-dialog page-name))}})
|
||||
:options {:on-click #(state/set-modal! (rename-page-dialog title page-name))}})
|
||||
|
||||
(when (and file-path (util/electron?))
|
||||
[{:title (t :page/open-in-finder)
|
||||
@@ -315,38 +313,14 @@
|
||||
{:title (t :page/delete)
|
||||
:options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
|
||||
|
||||
{:title (t :page/action-publish)
|
||||
:options {:on-click
|
||||
(fn []
|
||||
(state/set-modal!
|
||||
(fn []
|
||||
[:div.cp__page-publish-actions
|
||||
(mapv (fn [{:keys [title options]}]
|
||||
(when title
|
||||
[:div.it
|
||||
(apply (partial ui/button title) (flatten (seq options)))]))
|
||||
[(if published?
|
||||
{:title (t :page/unpublish)
|
||||
:options {:on-click (fn []
|
||||
(page-handler/unpublish-page! page-name))}}
|
||||
{:title (t :page/publish)
|
||||
:options {:on-click (fn []
|
||||
(page-handler/publish-page!
|
||||
page-name project/add-project
|
||||
html-export/export-page))}})
|
||||
(when-not published?
|
||||
{:title (t :page/publish-as-slide)
|
||||
:options {:on-click (fn []
|
||||
(page-handler/publish-page-as-slide!
|
||||
page-name project/add-project
|
||||
html-export/export-page))}})
|
||||
{:title (t (if public? :page/make-private :page/make-public))
|
||||
:options {:background (if public? "gray" "indigo")
|
||||
:on-click (fn []
|
||||
(page-handler/update-public-attribute!
|
||||
page-name
|
||||
(if public? false true))
|
||||
(state/close-modal!))}}])])))}}
|
||||
(when (util/electron?)
|
||||
{:title (t (if public? :page/make-private :page/make-public))
|
||||
:options {:on-click
|
||||
(fn []
|
||||
(page-handler/update-public-attribute!
|
||||
page-name
|
||||
(if public? false true))
|
||||
(state/close-modal!))}})
|
||||
|
||||
(when file
|
||||
{:title (t :page/re-index)
|
||||
@@ -437,7 +411,7 @@
|
||||
(block/block-parents config repo block-id format)]))
|
||||
|
||||
;; blocks
|
||||
(page-blocks-cp repo page file-path page-name page-original-name encoded-page-name sidebar? journal? block? block-id format)]]
|
||||
(page-blocks-cp repo page file-path page-name page-original-name page-name sidebar? journal? block? block-id format)]]
|
||||
|
||||
(when-not block?
|
||||
(today-queries repo today? sidebar?))
|
||||
@@ -516,21 +490,20 @@
|
||||
[:th (t :file/last-modified-at)]]]
|
||||
[:tbody
|
||||
(for [page pages]
|
||||
(let [encoded-page (util/encode-str page)]
|
||||
[:tr {:key encoded-page}
|
||||
[:td [:a {:on-click (fn [e]
|
||||
(let [repo (state/get-current-repo)
|
||||
page (db/pull repo '[*] [:block/name (string/lower-case page)])]
|
||||
(when (gobj/get e "shiftKey")
|
||||
(state/sidebar-add-block!
|
||||
repo
|
||||
(:db/id page)
|
||||
:page
|
||||
{:page page}))))
|
||||
:href (rfe/href :page {:name encoded-page})}
|
||||
page]]
|
||||
[:td [:span.text-gray-500.text-sm
|
||||
(t :file/no-data)]]]))]]))])))
|
||||
[:tr {:key page}
|
||||
[:td [:a {:on-click (fn [e]
|
||||
(let [repo (state/get-current-repo)
|
||||
page (db/pull repo '[*] [:block/name (string/lower-case page)])]
|
||||
(when (gobj/get e "shiftKey")
|
||||
(state/sidebar-add-block!
|
||||
repo
|
||||
(:db/id page)
|
||||
:page
|
||||
{:page page}))))
|
||||
:href (rfe/href :page {:name page})}
|
||||
page]]
|
||||
[:td [:span.text-gray-500.text-sm
|
||||
(t :file/no-data)]]])]]))])))
|
||||
|
||||
(rum/defcs new < rum/reactive
|
||||
(rum/local "" ::title)
|
||||
|
||||
@@ -78,16 +78,10 @@
|
||||
:on-click (fn []
|
||||
(repo-handler/re-index! nfs-handler/rebuild-index!))}
|
||||
"Re-index"]
|
||||
;; [:a.control.ml-4 {:title "Export as JSON"
|
||||
;; :on-click (fn []
|
||||
;; (export-handler/export-repo-as-json! (:url repo)))}
|
||||
;; "Export as JSON"]
|
||||
[:a.text-gray-400.ml-4 {:title "No worries, unlink this graph will clear its cache only, it does not remove your files on the disk."
|
||||
:on-click (fn []
|
||||
(repo-handler/remove-repo! repo))}
|
||||
"Unlink"]]]))]
|
||||
|
||||
[:a#download-as-json.hidden]]
|
||||
"Unlink"]]]))]]
|
||||
(widgets/add-graph)))))
|
||||
|
||||
(rum/defc sync-status < rum/reactive
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
|
||||
(defn recent-pages
|
||||
[]
|
||||
(let [pages (db/get-key-value :recent/pages)]
|
||||
(let [pages (->> (db/get-key-value :recent/pages)
|
||||
(remove #(= (string/lower-case %) "contents")))]
|
||||
[:div.recent-pages.text-sm.flex-col.flex.ml-3.mt-2
|
||||
(if (seq pages)
|
||||
(for [page pages]
|
||||
@@ -200,7 +201,7 @@
|
||||
|
||||
(date/journal-name))]
|
||||
(if page
|
||||
(util/url-decode (string/lower-case page)))))
|
||||
(string/lower-case page))))
|
||||
|
||||
(defn get-current-page
|
||||
[]
|
||||
|
||||
@@ -244,7 +244,7 @@
|
||||
search-q (state/sub :search/q)
|
||||
show-result? (boolean (seq search-result))
|
||||
blocks-count (or (db/blocks-count) 0)
|
||||
timeout (if (> blocks-count 2000) 500 100)]
|
||||
timeout (if (> blocks-count 2000) 500 300)]
|
||||
(rum/with-context [[t] i18n/*tongue-context*]
|
||||
[:div#search.flex-1.flex
|
||||
[:div.inner
|
||||
|
||||
@@ -131,7 +131,8 @@
|
||||
(ui/loading (t :loading))]]
|
||||
|
||||
:else
|
||||
[:div.max-w-7xl.mx-auto {:style {:margin-bottom (if global-graph-pages? 0 120)}}
|
||||
[:div {:class (if global-graph-pages? "" (util/hiccup->class "max-w-7xl.mx-auto"))
|
||||
:style {:margin-bottom (if global-graph-pages? 0 120)}}
|
||||
main-content])]]
|
||||
(right-sidebar/sidebar)]))
|
||||
|
||||
@@ -184,6 +185,11 @@
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name (:page default-home)}})
|
||||
|
||||
(and config/publishing?
|
||||
(not default-home)
|
||||
(empty? latest-journals))
|
||||
(route-handler/redirect! {:to :all-pages})
|
||||
|
||||
importing-to-db?
|
||||
(ui/loading (t :parsing-files))
|
||||
|
||||
|
||||
@@ -28,10 +28,17 @@
|
||||
(def asset-domain (util/format "https://asset.%s.com"
|
||||
app-name))
|
||||
|
||||
;; TODO: Remove this, switch to lazy loader
|
||||
(defn asset-uri
|
||||
[path]
|
||||
(if (util/file-protocol?)
|
||||
(cond
|
||||
publishing?
|
||||
path
|
||||
|
||||
(util/file-protocol?)
|
||||
(string/replace path "/static/" "./")
|
||||
|
||||
:else
|
||||
(if dev? path
|
||||
(str asset-domain path))))
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
remove-conn!]
|
||||
|
||||
[frontend.db.utils
|
||||
date->int db->json db->string get-max-tx-id get-tx-id
|
||||
date->int db->json db->edn-str db->string get-max-tx-id get-tx-id
|
||||
group-by-page seq-flatten sort-by-pos
|
||||
string->db with-repo
|
||||
|
||||
|
||||
@@ -570,7 +570,8 @@
|
||||
(->> (string/split-lines content)
|
||||
(take-while (fn [line]
|
||||
(or (string/blank? line)
|
||||
(string/starts-with? line "#+"))))
|
||||
(string/starts-with? line "#+")
|
||||
(re-find #"^:.+?:" line))))
|
||||
(string/join "\n"))
|
||||
|
||||
:markdown
|
||||
|
||||
@@ -46,16 +46,17 @@
|
||||
|
||||
(defn query-wrapper
|
||||
[where blocks?]
|
||||
(let [q (if blocks? ; FIXME: it doesn't need to be either blocks or pages
|
||||
'[:find (pull ?b [*])
|
||||
:where]
|
||||
'[:find (pull ?p [*])
|
||||
:where])
|
||||
result (if (coll? (first where))
|
||||
(apply conj q where)
|
||||
(conj q where))]
|
||||
(prn "Datascript query: " result)
|
||||
result))
|
||||
(when where
|
||||
(let [q (if blocks? ; FIXME: it doesn't need to be either blocks or pages
|
||||
'[:find (pull ?b [*])
|
||||
:where]
|
||||
'[:find (pull ?p [*])
|
||||
:where])
|
||||
result (if (coll? (first where))
|
||||
(apply conj q where)
|
||||
(conj q where))]
|
||||
(prn "Datascript query: " result)
|
||||
result)))
|
||||
|
||||
;; (between -7d +7d)
|
||||
(defn- ->journal-day-int [input]
|
||||
@@ -151,7 +152,7 @@
|
||||
(contains? #{'and 'or 'not} fe)
|
||||
(let [clauses (->> (map (fn [form]
|
||||
(build-query repo form (assoc env :current-filter fe) (inc level)))
|
||||
(rest e))
|
||||
(rest e))
|
||||
remove-nil?
|
||||
(distinct))]
|
||||
(when (seq clauses)
|
||||
@@ -221,7 +222,7 @@
|
||||
(text/page-ref-un-brackets!))
|
||||
sym (if (= current-filter 'or)
|
||||
'?v
|
||||
(uniq-symbol counter "?v"))]
|
||||
(uniq-symbol counter "?v"))]
|
||||
[['?b :block/properties '?prop]
|
||||
[(list 'get '?prop (name (nth e 1))) sym]
|
||||
(list
|
||||
@@ -354,39 +355,47 @@
|
||||
(try
|
||||
(let [form (some-> s
|
||||
(pre-transform)
|
||||
(reader/read-string))
|
||||
sort-by (atom nil)
|
||||
blocks? (atom nil)
|
||||
result (when form (build-query repo form {:sort-by sort-by
|
||||
:blocks? blocks?
|
||||
:counter counter}))
|
||||
result (when (seq result)
|
||||
(let [key (if (coll? (first result))
|
||||
(keyword (ffirst result))
|
||||
(keyword (first result)))
|
||||
result (case key
|
||||
:and
|
||||
(rest result)
|
||||
(reader/read-string))]
|
||||
(if (symbol? form)
|
||||
(str form)
|
||||
(let [sort-by (atom nil)
|
||||
blocks? (atom nil)
|
||||
result (when form (build-query repo form {:sort-by sort-by
|
||||
:blocks? blocks?
|
||||
:counter counter}))]
|
||||
(if (string? result)
|
||||
result
|
||||
(let [result (when (seq result)
|
||||
(let [key (if (coll? (first result))
|
||||
(keyword (ffirst result))
|
||||
(keyword (first result)))
|
||||
result (case key
|
||||
:and
|
||||
(rest result)
|
||||
|
||||
result)]
|
||||
(add-bindings! result)))]
|
||||
{:query result
|
||||
:sort-by @sort-by
|
||||
:blocks? (boolean @blocks?)})
|
||||
result)]
|
||||
(add-bindings! result)))]
|
||||
{:query result
|
||||
:sort-by @sort-by
|
||||
:blocks? (boolean @blocks?)})))))
|
||||
(catch js/Error e
|
||||
(log/error :query-dsl/parse-error e))))))
|
||||
|
||||
(defn query
|
||||
[repo query-string]
|
||||
(when (string? query-string)
|
||||
(let [query-string (template/resolve-dynamic-template! query-string)
|
||||
{:keys [query sort-by blocks?]} (parse repo query-string)]
|
||||
(when query
|
||||
(let [query (query-wrapper query blocks?)]
|
||||
(react/react-query repo
|
||||
{:query query}
|
||||
(if sort-by
|
||||
{:transform-fn sort-by})))))))
|
||||
(let [query-string (template/resolve-dynamic-template! query-string)]
|
||||
(when-not (string/blank? query-string)
|
||||
(let [{:keys [query sort-by blocks?] :as result} (parse repo query-string)]
|
||||
(if (string? result)
|
||||
(if (= "\"" (first result) (last result))
|
||||
(subs result 1 (dec (count result)))
|
||||
result)
|
||||
(when-let [query (query-wrapper query blocks?)]
|
||||
(react/react-query repo
|
||||
{:query query}
|
||||
(if sort-by
|
||||
{:transform-fn sort-by})))))))))
|
||||
|
||||
(defn custom-query
|
||||
[repo query-m query-opts]
|
||||
@@ -395,7 +404,7 @@
|
||||
query-string (template/resolve-dynamic-template! query-string)
|
||||
{:keys [query sort-by blocks?]} (parse repo query-string)]
|
||||
(when query
|
||||
(let [query (query-wrapper query blocks?)]
|
||||
(when-let [query (query-wrapper query blocks?)]
|
||||
(react/react-query repo
|
||||
(merge
|
||||
query-m
|
||||
|
||||
@@ -99,5 +99,5 @@
|
||||
k [:custom query']]
|
||||
(apply react/q repo k query-opts query inputs))
|
||||
(catch js/Error e
|
||||
(println "Custom query failed: ")
|
||||
(println "Custom query failed: " {:query query'})
|
||||
(js/console.dir e))))
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
|
||||
(date/journal-name))]
|
||||
(when page
|
||||
(let [page-name (util/url-decode (string/lower-case page))]
|
||||
(let [page-name (string/lower-case page)]
|
||||
(db-utils/entity [:block/name page-name])))))
|
||||
|
||||
(defn get-current-priority
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
(for [d (d/datoms db :eavt)]
|
||||
#js [(:e d) (name (:a d)) (:v d)]))))
|
||||
|
||||
(defn db->edn-str [db]
|
||||
(pr-str db))
|
||||
|
||||
(defn string->db [s]
|
||||
(dt/read-transit-str s))
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ some changes on the right sidebar, those referenced blocks will be changed too!
|
||||
[:iframe
|
||||
{:allowFullScreen \"allowfullscreen\"
|
||||
:allow
|
||||
\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\"
|
||||
\"accelerometer; autoplay; encrypted-media; gyroscope\"
|
||||
:frameBorder \"0\"
|
||||
:src \"https://www.youtube.com/embed/Afmqowr0qEQ\"
|
||||
:height \"367\"
|
||||
@@ -50,7 +50,7 @@ some changes on the right sidebar, those referenced blocks will be changed too!
|
||||
### DONE Create a page
|
||||
### CANCELED [#C] Write a page with more than 1000 blocks
|
||||
## That's it! You can create more bullets or open a local directory to import some notes now!
|
||||
##
|
||||
## You can also download our desktop app at https://github.com/logseq/logseq/releases
|
||||
"
|
||||
:tutorial/dummy-notes "---
|
||||
title: How to take dummy notes?
|
||||
@@ -229,7 +229,7 @@ title: How to take dummy notes?
|
||||
:page/open-in-finder "Open in directory"
|
||||
:page/open-with-default-app "Open with default app"
|
||||
:page/action-publish "Publish"
|
||||
:page/make-public "Publish it when exporting to an html file"
|
||||
:page/make-public "Make it public for publishing"
|
||||
:page/make-private "Make it private"
|
||||
:page/delete "Delete page"
|
||||
:page/publish "Publish this page on Logseq"
|
||||
@@ -310,7 +310,6 @@ title: How to take dummy notes?
|
||||
:cancel "Cancel"
|
||||
:close "Close"
|
||||
:re-index "Re-index"
|
||||
:export-json "Export as JSON"
|
||||
:unlink "unlink"
|
||||
:search (if config/publishing?
|
||||
"Search"
|
||||
@@ -320,7 +319,11 @@ title: How to take dummy notes?
|
||||
:graph "Graph"
|
||||
:graph-view "View Graph"
|
||||
:publishing "Publishing"
|
||||
:export "Export public pages"
|
||||
:export "Export"
|
||||
:export-json "Export as JSON"
|
||||
:export-markdown "Export as Markdown"
|
||||
:export-public-pages "Export public pages"
|
||||
:export-edn "Export as EDN"
|
||||
:all-graphs "All graphs"
|
||||
:all-pages "All pages"
|
||||
:all-files "All files"
|
||||
@@ -1033,6 +1036,7 @@ title: How to take dummy notes?
|
||||
:cancel "取消"
|
||||
:re-index "重新建立索引"
|
||||
:export-json "以 JSON 格式导出"
|
||||
:export-markdown "以 Markdown 格式导出"
|
||||
:unlink "解除绑定"
|
||||
:search (if config/publishing?
|
||||
"搜索"
|
||||
@@ -1297,6 +1301,7 @@ title: How to take dummy notes?
|
||||
:cancel "取消"
|
||||
:re-index "重新建立索引"
|
||||
:export-json "以 JSON 格式導出"
|
||||
:export-markdown "以 Markdown 格式導出"
|
||||
:unlink "解除綁定"
|
||||
:search (if config/publishing?
|
||||
"搜索"
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
["codemirror/mode/clojure/clojure"]
|
||||
["codemirror/mode/powershell/powershell"]
|
||||
["codemirror/mode/javascript/javascript"]
|
||||
["codemirror/mode/jsx/jsx"]
|
||||
["codemirror/mode/clike/clike"]
|
||||
["codemirror/mode/vue/vue"]
|
||||
["codemirror/mode/commonlisp/commonlisp"]
|
||||
@@ -100,6 +101,10 @@
|
||||
"csharp" "text/x-csharp"
|
||||
"objective-c" "text/x-objectivec"
|
||||
"scala" "text/x-scala"
|
||||
"js" "text/javascript"
|
||||
"typescript" "text/typescript"
|
||||
"ts" "text/typescript"
|
||||
"tsx" "text/typescript-jsx"
|
||||
mode))))
|
||||
|
||||
(defn render!
|
||||
|
||||
10
src/main/frontend/external/roam.cljc
vendored
10
src/main/frontend/external/roam.cljc
vendored
@@ -5,7 +5,8 @@
|
||||
[medley.core :as medley]
|
||||
[clojure.walk :as walk]
|
||||
[clojure.string :as string]
|
||||
[frontend.util :as util]))
|
||||
[frontend.util :as util]
|
||||
[frontend.text :as text]))
|
||||
|
||||
(defonce all-refed-uids (atom #{}))
|
||||
(defonce uid->uuid (atom {}))
|
||||
@@ -34,12 +35,9 @@
|
||||
(defn macro-transform
|
||||
[text]
|
||||
(string/replace text macro-pattern (fn [[original text]]
|
||||
(let [[name arg] (-> (string/replace text #" " "")
|
||||
(string/split #":"))]
|
||||
(let [[name arg] (util/split-first ":" text)]
|
||||
(if name
|
||||
(let [name (case name
|
||||
"[[embed]]" "embed"
|
||||
name)]
|
||||
(let [name (text/page-ref-un-brackets! name)]
|
||||
(util/format "{{%s %s}}" name arg))
|
||||
original)))))
|
||||
|
||||
|
||||
@@ -33,8 +33,10 @@
|
||||
|
||||
;; html
|
||||
(defn get-default-config
|
||||
[format]
|
||||
(mldoc/default-config format))
|
||||
([format]
|
||||
(mldoc/default-config format))
|
||||
([format heading-to-list?]
|
||||
(mldoc/default-config format heading-to-list?)))
|
||||
|
||||
(defn to-html
|
||||
([content format]
|
||||
@@ -62,7 +64,7 @@
|
||||
(protocol/loaded? record)))
|
||||
|
||||
(def marker-pattern
|
||||
#"^(NOW|LATER|TODO|DOING|DONE|WAIT|WAITING|CANCELED|CANCELLED|STARTED|IN-PROGRESS)?\s?")
|
||||
#"^(NOW|LATER|TODO|DOING|DONE|WAITING|WAIT|CANCELED|CANCELLED|STARTED|IN-PROGRESS)?\s?")
|
||||
|
||||
(def bare-marker-pattern
|
||||
#"^(NOW|LATER|TODO|DOING|DONE|WAIT|WAITING|CANCELED|CANCELLED|STARTED|IN-PROGRESS){1}\s+")
|
||||
#"^(NOW|LATER|TODO|DOING|DONE|WAITING|WAIT|CANCELED|CANCELLED|STARTED|IN-PROGRESS){1}\s+")
|
||||
|
||||
@@ -26,4 +26,6 @@
|
||||
(lazyLoad [this ok-handler]
|
||||
(loader/load
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/asciidoctor.js/1.5.9/asciidoctor.min.js"
|
||||
ok-handler)))
|
||||
ok-handler))
|
||||
(exportMarkdown [this content config references]
|
||||
(throw "not support")))
|
||||
|
||||
@@ -60,11 +60,11 @@
|
||||
(and (vector? block)
|
||||
(= "Macro" (first block)))
|
||||
(let [{:keys [name arguments]} (second block)]
|
||||
(when (and (= name "embed")
|
||||
(string? (first arguments))
|
||||
(string/starts-with? (first arguments) "[[")
|
||||
(string/ends-with? (first arguments) "]]"))
|
||||
(subs (first arguments) 2 (- (count (first arguments)) 2))))
|
||||
(let [argument (string/join ", " arguments)]
|
||||
(when (and (= name "embed")
|
||||
(string? argument)
|
||||
(text/page-ref? argument))
|
||||
(text/page-ref-un-brackets! argument))))
|
||||
:else
|
||||
nil)]
|
||||
(when (and
|
||||
@@ -234,8 +234,15 @@
|
||||
(swap! ref-pages conj tag)))
|
||||
form)
|
||||
(concat title body))
|
||||
(let [ref-pages (remove string/blank? @ref-pages)]
|
||||
(assoc block :ref-pages (vec ref-pages)))))
|
||||
(let [ref-pages (remove string/blank? @ref-pages)
|
||||
children-pages (->> (mapcat (fn [p]
|
||||
(if (string/includes? p "/")
|
||||
;; Don't create the last page for now
|
||||
(butlast (string/split p #"/"))))
|
||||
ref-pages)
|
||||
(remove string/blank?))
|
||||
ref-pages (distinct (concat ref-pages children-pages))]
|
||||
(assoc block :ref-pages ref-pages))))
|
||||
|
||||
(defn with-block-refs
|
||||
[{:keys [title body] :as block}]
|
||||
|
||||
@@ -14,16 +14,26 @@
|
||||
(defonce parseInlineJson (gobj/get Mldoc "parseInlineJson"))
|
||||
(defonce parseHtml (gobj/get Mldoc "parseHtml"))
|
||||
(defonce anchorLink (gobj/get Mldoc "anchorLink"))
|
||||
(defonce parseAndExportMarkdown (gobj/get Mldoc "parseAndExportMarkdown"))
|
||||
|
||||
(defn default-config
|
||||
[format]
|
||||
(let [format (string/capitalize (name (or format :markdown)))]
|
||||
(js/JSON.stringify
|
||||
(bean/->js
|
||||
(assoc {:toc false
|
||||
:heading_number false
|
||||
:keep_line_break true}
|
||||
:format format)))))
|
||||
([format]
|
||||
(default-config format false))
|
||||
([format export-heading-to-list?]
|
||||
(let [format (string/capitalize (name (or format :markdown)))]
|
||||
(js/JSON.stringify
|
||||
(bean/->js
|
||||
{:toc false
|
||||
:heading_number false
|
||||
:keep_line_break true
|
||||
:format format
|
||||
:heading_to_list export-heading-to-list?})))))
|
||||
|
||||
(def default-references
|
||||
(js/JSON.stringify
|
||||
(clj->js {:embed_blocks []
|
||||
:embed_pages []
|
||||
:refer_blocks []})))
|
||||
|
||||
(defn parse-json
|
||||
[content config]
|
||||
@@ -33,6 +43,12 @@
|
||||
[text config]
|
||||
(parseInlineJson text (or config default-config)))
|
||||
|
||||
(defn parse-export-markdown
|
||||
[content config references]
|
||||
(parseAndExportMarkdown content
|
||||
(or config default-config)
|
||||
(or references default-references)))
|
||||
|
||||
;; Org-roam
|
||||
(defn get-tags-from-definition
|
||||
[ast]
|
||||
@@ -82,8 +98,12 @@
|
||||
(if (seq ast)
|
||||
(let [original-ast ast
|
||||
ast (map first ast) ; without position meta
|
||||
directive? (fn [item] (= "directive" (string/lower-case (first item))))
|
||||
properties (->> (take-while directive? ast)
|
||||
directive?
|
||||
(fn [[item _]] (= "directive" (string/lower-case (first item))))
|
||||
grouped-ast (group-by directive? original-ast)
|
||||
[directive-ast other-ast]
|
||||
[(get grouped-ast true) (get grouped-ast false)]
|
||||
properties (->> (map first directive-ast)
|
||||
(map (fn [[_ k v]]
|
||||
(let [k (keyword (string/lower-case k))
|
||||
comma? (contains? #{:tags :alias :roam_tags} k)
|
||||
@@ -91,6 +111,7 @@
|
||||
v
|
||||
(text/split-page-refs-without-brackets v comma?))]
|
||||
[k v])))
|
||||
(reverse)
|
||||
(into {}))
|
||||
macro-properties (filter (fn [x] (= :macro (first x))) properties)
|
||||
macros (if (seq macro-properties)
|
||||
@@ -134,8 +155,7 @@
|
||||
(update :roam_alias ->vec)
|
||||
(update :roam_tags (constantly roam-tags))
|
||||
(update :filetags (constantly filetags)))
|
||||
properties (medley/filter-kv (fn [k v] (not (empty? v))) properties)
|
||||
other-ast (drop-while (fn [[item _pos]] (directive? item)) original-ast)]
|
||||
properties (medley/filter-kv (fn [k v] (not (empty? v))) properties)]
|
||||
(if (seq properties)
|
||||
(cons [["Properties" properties] nil] other-ast)
|
||||
original-ast))
|
||||
@@ -174,7 +194,10 @@
|
||||
(loaded? [this]
|
||||
true)
|
||||
(lazyLoad [this ok-handler]
|
||||
true))
|
||||
true)
|
||||
(exportMarkdown [this content config references]
|
||||
(parse-export-markdown content config references))
|
||||
)
|
||||
|
||||
(defn plain->text
|
||||
[plains]
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
(toEdn [this content config])
|
||||
(toHtml [this content config])
|
||||
(loaded? [this])
|
||||
(lazyLoad [this ok-handler]))
|
||||
(lazyLoad [this ok-handler])
|
||||
(exportMarkdown [this content config references]))
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
(when file
|
||||
(nfs-saved-handler repo path file))))
|
||||
(do
|
||||
(js/alert (str "The file has been modified in your local disk! File path: " path
|
||||
(js/alert (str "The file has been modified on your local disk! File path: " path
|
||||
", please save your changes and click the refresh button to reload it.")))))
|
||||
;; create file handle
|
||||
(->
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
(p/let [disk-mtime (when stat (gobj/get stat "mtime"))
|
||||
db-mtime (db/get-file-last-modified-at repo path)]
|
||||
(if (not= disk-mtime db-mtime)
|
||||
(js/alert (str "The file has been modified in your local disk! File path: " path
|
||||
(js/alert (str "The file has been modified on your local disk! File path: " path
|
||||
", please save your changes and click the refresh button to reload it."))
|
||||
(->
|
||||
(p/let [result (ipc/ipc "writeFile" path content)
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
[]
|
||||
(let [f (fn []
|
||||
(when-not (state/nfs-refreshing?)
|
||||
(repo-handler/create-today-journal!))
|
||||
;; Don't create the journal file until user writes something
|
||||
(repo-handler/create-today-journal! false))
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when (and (search-db/empty? repo)
|
||||
(state/input-idle? repo))
|
||||
@@ -155,8 +156,8 @@
|
||||
(defn on-load-events
|
||||
[]
|
||||
(let [f (fn []
|
||||
(init-sentry))]
|
||||
(set! js/window.onload f)))
|
||||
(when-not config/dev? (init-sentry)))]
|
||||
(set! js/window.onload f)))
|
||||
|
||||
(defn start!
|
||||
[render]
|
||||
|
||||
@@ -2336,6 +2336,47 @@
|
||||
(not (in-auto-complete? input)))
|
||||
(on-up-down state e up?))))
|
||||
|
||||
(defn- move-to-block-when-cross-boundrary
|
||||
[state e direction]
|
||||
(let [up? (= :left direction)
|
||||
pos (if up? :max 0)
|
||||
{:keys [id block-id block block-parent-id dummy? value format] :as block-state} (get-state state)
|
||||
element (gdom/getElement id)]
|
||||
(when block-id
|
||||
(let [f (if up? get-prev-block-non-collapsed get-next-block-non-collapsed)
|
||||
sibling-block (f (gdom/getElement block-parent-id))]
|
||||
(when sibling-block
|
||||
(when-let [sibling-block-id (d/attr sibling-block "blockid")]
|
||||
(let [state (get-state state)
|
||||
content (:block/content block)
|
||||
value (:value state)]
|
||||
(when (not= (-> content
|
||||
(text/remove-level-spaces format)
|
||||
text/remove-properties!
|
||||
string/trim)
|
||||
(string/trim value))
|
||||
(save-block! state (:value state))))
|
||||
(let [block (db/pull (state/get-current-repo) '[*] [:block/uuid (uuid sibling-block-id)])]
|
||||
(edit-block! block pos format id)
|
||||
(util/stop e))))))))
|
||||
|
||||
(defn- on-arrow-move-to-boundray
|
||||
[state input e direction]
|
||||
(when (or (and (= :left direction) (util/input-start? input))
|
||||
(and (= :right direction) (util/input-end? input)))
|
||||
(move-to-block-when-cross-boundrary state e direction)))
|
||||
|
||||
(defn keydown-arrow-handler
|
||||
[input direction]
|
||||
(fn [state e]
|
||||
(when (and
|
||||
input
|
||||
(not (gobj/get e "shiftKey"))
|
||||
(not (gobj/get e "ctrlKey"))
|
||||
(not (gobj/get e "metaKey"))
|
||||
(not (in-auto-complete? input)))
|
||||
(on-arrow-move-to-boundray state input e direction))))
|
||||
|
||||
(defn keydown-backspace-handler
|
||||
[repo input id]
|
||||
(fn [state e]
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
(ns frontend.handler.export
|
||||
(:require [frontend.state :as state]
|
||||
[frontend.db :as db]
|
||||
[frontend.format.protocol :as fp]
|
||||
[frontend.format :as f]
|
||||
[datascript.core :as d]
|
||||
[frontend.util :as util]
|
||||
[cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
@@ -44,6 +47,16 @@
|
||||
(.setAttribute anchor "download" (str (last (string/split repo #"/")) ".json"))
|
||||
(.click anchor)))))
|
||||
|
||||
(defn export-repo-as-edn!
|
||||
[repo]
|
||||
(when-let [db (db/get-conn repo)]
|
||||
(let [db-edn (db/db->edn-str db)
|
||||
data-str (str "data:text/edn;charset=utf-8," (js/encodeURIComponent db-edn))]
|
||||
(when-let [anchor (gdom/getElement "download-as-edn")]
|
||||
(.setAttribute anchor "href" data-str)
|
||||
(.setAttribute anchor "download" (str (last (string/split repo #"/")) ".edn"))
|
||||
(.click anchor)))))
|
||||
|
||||
(defn download-file!
|
||||
[file-path]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
@@ -59,24 +72,27 @@
|
||||
(defn export-repo-as-html!
|
||||
[repo]
|
||||
(when-let [db (db/get-conn repo)]
|
||||
(let [db (if (state/all-pages-public?)
|
||||
(db/clean-export! db)
|
||||
(db/filter-only-public-pages-and-blocks db))
|
||||
db-str (db/db->string db)
|
||||
state (select-keys @state/state
|
||||
[:ui/theme :ui/cycle-collapse
|
||||
:ui/collapsed-blocks
|
||||
:ui/sidebar-collapsed-blocks
|
||||
:ui/show-recent?
|
||||
:config])
|
||||
state (update state :config (fn [config]
|
||||
{"local" (get config repo)}))
|
||||
html-str (str "data:text/html;charset=UTF-8,"
|
||||
(js/encodeURIComponent (html/publishing-html db-str (pr-str state))))]
|
||||
(when-let [anchor (gdom/getElement "download-as-html")]
|
||||
(.setAttribute anchor "href" html-str)
|
||||
(.setAttribute anchor "download" "index.html")
|
||||
(.click anchor)))))
|
||||
(let [db (if (state/all-pages-public?)
|
||||
(db/clean-export! db)
|
||||
(db/filter-only-public-pages-and-blocks db))
|
||||
db-str (db/db->string db)
|
||||
state (select-keys @state/state
|
||||
[:ui/theme :ui/cycle-collapse
|
||||
:ui/collapsed-blocks
|
||||
:ui/sidebar-collapsed-blocks
|
||||
:ui/show-recent?
|
||||
:config])
|
||||
state (update state :config (fn [config]
|
||||
{"local" (get config repo)}))
|
||||
raw-html-str (html/publishing-html db-str (pr-str state))
|
||||
html-str (str "data:text/html;charset=UTF-8,"
|
||||
(js/encodeURIComponent raw-html-str))]
|
||||
(if (util/electron?)
|
||||
(js/window.apis.exportPublishAssets raw-html-str)
|
||||
(when-let [anchor (gdom/getElement "download-as-html")]
|
||||
(.setAttribute anchor "href" html-str)
|
||||
(.setAttribute anchor "download" "index.html")
|
||||
(.click anchor))))))
|
||||
|
||||
(defn export-repo-as-zip!
|
||||
[repo]
|
||||
@@ -89,3 +105,117 @@
|
||||
(.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
|
||||
(.setAttribute anchor "download" (.-name zipfile))
|
||||
(.click anchor))))))
|
||||
|
||||
|
||||
|
||||
(defn- get-file-contents-with-suffix
|
||||
[repo]
|
||||
(let [conn (db/get-conn repo)]
|
||||
(->>
|
||||
(filterv (fn [[path _]]
|
||||
(or (string/ends-with? path ".md")))
|
||||
(db/get-file-contents repo))
|
||||
(mapv (fn [[path content]] {:path path :content content
|
||||
:names (d/q '[:find [?n ?n2]
|
||||
:in $ ?p
|
||||
:where [?e :file/path ?p]
|
||||
[?e2 :block/file ?e]
|
||||
[?e2 :block/name ?n]
|
||||
[?e2 :block/original-name ?n2]] conn path)
|
||||
:format (f/get-format path)})))))
|
||||
|
||||
(defn- get-embed-and-refs-blocks-pages-aux
|
||||
[repo page-or-block is-block? exclude-blocks exclude-pages]
|
||||
(let [[ref-blocks ref-pages]
|
||||
(->> (if is-block?
|
||||
[page-or-block]
|
||||
(db/get-page-blocks
|
||||
repo page-or-block {:use-cache? false
|
||||
:pull-keys '[:block/ref-pages :block/ref-blocks]}))
|
||||
(filterv #(or (:block/ref-blocks %) (:block/ref-pages %)))
|
||||
(mapv (fn [b] [(:block/ref-blocks b), (:block/ref-pages b)]))
|
||||
(apply mapv vector)
|
||||
(mapv #(vec (distinct (flatten (remove nil? %))))))
|
||||
ref-block-ids
|
||||
(->> ref-blocks
|
||||
(#(remove (fn [b] (contains? exclude-blocks (:db/id b))) %))
|
||||
(mapv #(:db/id %)))
|
||||
ref-page-ids
|
||||
(->> ref-pages
|
||||
(#(remove (fn [b] (contains? exclude-pages (:db/id b))) %))
|
||||
(mapv #(:db/id %)))
|
||||
ref-blocks
|
||||
(->> ref-block-ids
|
||||
(db/pull-many repo '[*])
|
||||
(flatten))
|
||||
ref-pages
|
||||
(->> ref-page-ids
|
||||
(db/pull-many repo '[*])
|
||||
(flatten))
|
||||
[next-ref-blocks1 next-ref-pages1]
|
||||
(->> ref-blocks
|
||||
(mapv #(get-embed-and-refs-blocks-pages-aux repo % true
|
||||
(set (concat ref-block-ids exclude-blocks)) exclude-pages))
|
||||
(apply mapv vector))
|
||||
[next-ref-blocks2 next-ref-pages2]
|
||||
(->> ref-pages
|
||||
(mapv #(get-embed-and-refs-blocks-pages-aux repo (:block/name %) false
|
||||
exclude-blocks (set (concat ref-page-ids exclude-pages))))
|
||||
(apply mapv vector))]
|
||||
[(->> (concat ref-block-ids next-ref-blocks1 next-ref-blocks2)
|
||||
(flatten)
|
||||
(distinct))
|
||||
(->> (concat ref-page-ids next-ref-pages1 next-ref-pages2)
|
||||
(flatten)
|
||||
(distinct))]))
|
||||
|
||||
|
||||
(defn- get-embed-and-refs-blocks-pages
|
||||
[repo page]
|
||||
(let [[block-ids page-ids]
|
||||
(get-embed-and-refs-blocks-pages-aux repo page false #{} #{})
|
||||
blocks
|
||||
(db/pull-many repo '[*] block-ids)
|
||||
pages-name-and-content
|
||||
(->> page-ids
|
||||
(d/q '[:find ?n (pull ?p [:file/path])
|
||||
:in $ [?e ...]
|
||||
:where
|
||||
[?e :block/file ?p]
|
||||
[?e :block/name ?n]] (db/get-conn repo))
|
||||
(mapv (fn [[page-name file-path]] [page-name (:file/path file-path)]))
|
||||
(d/q '[:find ?n ?c
|
||||
:in $ [[?n ?p] ...]
|
||||
:where
|
||||
[?e :file/path ?p]
|
||||
[?e :file/content ?c]] @(db/get-files-conn repo)))
|
||||
embed-blocks
|
||||
(mapv (fn [b] [(str (:block/uuid b))
|
||||
[(apply str
|
||||
(mapv #(:block/content %)
|
||||
(db/get-block-and-children repo (:block/uuid b))))
|
||||
(:block/title b)]])
|
||||
blocks)]
|
||||
{:embed_blocks embed-blocks
|
||||
:embed_pages pages-name-and-content}))
|
||||
|
||||
(defn export-repo-as-markdown!
|
||||
[repo]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [files (get-file-contents-with-suffix repo)]
|
||||
(let [heading-to-list? (state/export-heading-to-list?)
|
||||
files
|
||||
(->> files
|
||||
(mapv (fn [{:keys [path content names format]}]
|
||||
(when (first names)
|
||||
[path (fp/exportMarkdown f/mldoc-record content
|
||||
(f/get-default-config format heading-to-list?)
|
||||
(js/JSON.stringify
|
||||
(clj->js (get-embed-and-refs-blocks-pages repo (first names)))))])))
|
||||
(remove nil?))
|
||||
zip-file-name (str repo "_markdown_" (quot (util/time-ms) 1000))]
|
||||
(p/let [zipfile (zip/make-zip zip-file-name files)]
|
||||
(when-let [anchor (gdom/getElement "export-as-markdown")]
|
||||
(.setAttribute anchor "href" (js/window.URL.createObjectURL zipfile))
|
||||
(.setAttribute anchor "download" (.-name zipfile))
|
||||
(.click anchor)))))))
|
||||
|
||||
@@ -36,9 +36,11 @@
|
||||
|
||||
(defn- get-file-name
|
||||
[journal? title]
|
||||
(if journal?
|
||||
(date/journal-title->default title)
|
||||
(util/page-name-sanity (string/lower-case title))))
|
||||
(when-let [s (if journal?
|
||||
(date/journal-title->default title)
|
||||
(util/page-name-sanity (string/lower-case title)))]
|
||||
;; Win10 file path has a length limit of 260 chars
|
||||
(util/safe-subs s 0 200)))
|
||||
|
||||
(defn create!
|
||||
([title]
|
||||
@@ -100,7 +102,9 @@
|
||||
file (db/entity (:db/id (:block/file page)))
|
||||
file-path (:file/path file)
|
||||
file-content (db/get-file file-path)
|
||||
after-content (subs file-content (inc (count properties-content)))
|
||||
after-content (if (empty? properties-content)
|
||||
file-content
|
||||
(subs file-content (inc (count properties-content))))
|
||||
new-properties-content (db/add-properties! page-format properties-content properties)
|
||||
full-content (str new-properties-content "\n\n" (string/trim after-content))]
|
||||
(file-handler/alter-file (state/get-current-repo)
|
||||
@@ -430,27 +434,27 @@
|
||||
|
||||
(defn get-page-ref-text
|
||||
[page]
|
||||
(when-let [edit-block (state/get-edit-block)]
|
||||
(let [page-name (string/lower-case page)
|
||||
edit-block-file-path (-> (:db/id (:block/file edit-block))
|
||||
(db/entity)
|
||||
:file/path)]
|
||||
(if (and edit-block-file-path
|
||||
(state/org-mode-file-link? (state/get-current-repo)))
|
||||
(if-let [ref-file-path (:file/path (:block/file (db/entity [:block/name page-name])))]
|
||||
(let [edit-block-file-path (some-> (state/get-edit-block)
|
||||
(get-in [:block/file :db/id])
|
||||
db/entity
|
||||
:file/path)
|
||||
page-name (string/lower-case page)]
|
||||
(if (and edit-block-file-path
|
||||
(state/org-mode-file-link? (state/get-current-repo)))
|
||||
(if-let [ref-file-path (:file/path (:file/file (db/entity [:file/name page-name])))]
|
||||
(util/format "[[file:%s][%s]]"
|
||||
(util/get-relative-path edit-block-file-path ref-file-path)
|
||||
page)
|
||||
(let [journal? (date/valid-journal-title? page)
|
||||
ref-file-path (str (get-directory journal?)
|
||||
"/"
|
||||
(get-file-name journal? page)
|
||||
".org")]
|
||||
(create! page {:redirect? false})
|
||||
(util/format "[[file:%s][%s]]"
|
||||
(util/get-relative-path edit-block-file-path ref-file-path)
|
||||
page)
|
||||
(let [journal? (date/valid-journal-title? page)
|
||||
ref-file-path (str (get-directory journal?)
|
||||
"/"
|
||||
(get-file-name journal? page)
|
||||
".org")]
|
||||
(create! page {:redirect? false})
|
||||
(util/format "[[file:%s][%s]]"
|
||||
(util/get-relative-path edit-block-file-path ref-file-path)
|
||||
page)))
|
||||
(util/format "[[%s]]" page)))))
|
||||
page)))
|
||||
(util/format "[[%s]]" page))))
|
||||
|
||||
(defn init-commands!
|
||||
[]
|
||||
|
||||
@@ -111,7 +111,8 @@
|
||||
(defn create-today-journal-if-not-exists
|
||||
([repo-url]
|
||||
(create-today-journal-if-not-exists repo-url nil))
|
||||
([repo-url content]
|
||||
([repo-url {:keys [content write-file?]
|
||||
:or {write-file? true}}]
|
||||
(spec/validate :repos/url repo-url)
|
||||
(when (state/enable-journals? repo-url)
|
||||
(let [repo-dir (config/get-repo-dir repo-url)
|
||||
@@ -144,22 +145,28 @@
|
||||
file-exists? (fs/file-exists? repo-dir file-path)]
|
||||
(when-not file-exists?
|
||||
(file-handler/reset-file! repo-url path content)
|
||||
(p/let [_ (fs/create-if-not-exists repo-url repo-dir file-path content)]
|
||||
(if write-file?
|
||||
(p/let [_ (fs/create-if-not-exists repo-url repo-dir file-path content)]
|
||||
(when-not (state/editing?)
|
||||
(ui-handler/re-render-root!))
|
||||
(git-handler/git-add repo-url path))
|
||||
(when-not (state/editing?)
|
||||
(ui-handler/re-render-root!))))))))))
|
||||
|
||||
(defn create-today-journal!
|
||||
[]
|
||||
(state/set-today! (date/today))
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when (or (db/cloned? repo)
|
||||
(and (config/local-db? repo)
|
||||
;; config file exists
|
||||
(let [path (config/get-config-path)]
|
||||
(db/get-file path))))
|
||||
(let [today-page (string/lower-case (date/today))]
|
||||
(when (empty? (db/get-page-blocks-no-cache repo today-page))
|
||||
(create-today-journal-if-not-exists repo))))))
|
||||
([]
|
||||
(create-today-journal! true))
|
||||
([write-file?]
|
||||
(state/set-today! (date/today))
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when (or (db/cloned? repo)
|
||||
(and (config/local-db? repo)
|
||||
;; config file exists
|
||||
(let [path (config/get-config-path)]
|
||||
(db/get-file path))))
|
||||
(let [today-page (string/lower-case (date/today))]
|
||||
(when (empty? (db/get-page-blocks-no-cache repo today-page))
|
||||
(create-today-journal-if-not-exists repo {:write-file? write-file?})))))))
|
||||
|
||||
(defn create-default-files!
|
||||
([repo-url]
|
||||
@@ -169,7 +176,7 @@
|
||||
(file-handler/create-metadata-file repo-url encrypted?)
|
||||
;; TODO: move to frontend.handler.file
|
||||
(create-config-file-if-not-exists repo-url)
|
||||
(create-today-journal-if-not-exists repo-url)
|
||||
(create-today-journal-if-not-exists repo-url {:write-file? false})
|
||||
(create-contents-file repo-url)
|
||||
(create-custom-theme repo-url)))
|
||||
|
||||
@@ -611,7 +618,7 @@
|
||||
(when-not config/publishing?
|
||||
(let [tutorial (get-in dicts/dicts [:en :tutorial/text])
|
||||
tutorial (string/replace-first tutorial "$today" (date/today))]
|
||||
(create-today-journal-if-not-exists repo tutorial)))
|
||||
(create-today-journal-if-not-exists repo {:content tutorial})))
|
||||
(create-config-file-if-not-exists repo)
|
||||
(create-contents-file repo)
|
||||
(create-custom-theme repo)
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
:all-journals
|
||||
"All journals"
|
||||
:file
|
||||
(str "File " (util/url-decode (:path path-params)))
|
||||
(str "File " (:path path-params))
|
||||
:new-page
|
||||
"Create a new page"
|
||||
:page
|
||||
@@ -55,13 +55,12 @@
|
||||
(str (subs content 0 48) "...")
|
||||
content))
|
||||
"Page no longer exists!!")
|
||||
(let [page (util/url-decode name)
|
||||
page (db/pull [:block/name (string/lower-case page)])]
|
||||
(let [page (db/pull [:block/name (string/lower-case name)])]
|
||||
(or (:block/original-name page)
|
||||
(:block/name page)
|
||||
"Logseq"))))
|
||||
:tag
|
||||
(str "#" (util/url-decode (:name path-params)))
|
||||
(str "#" (:name path-params))
|
||||
:diff
|
||||
"Git diff"
|
||||
:draw
|
||||
|
||||
@@ -84,4 +84,4 @@
|
||||
;; TODO: should make this configurable
|
||||
[:script {:src "/static/js/highlight.min.js"}]
|
||||
[:script {:src "/static/js/interact.min.js"}]
|
||||
[:script {:src "/static/js/publishing/main.js"}]]))))
|
||||
[:script {:src "/static/js/main.js"}]]))))
|
||||
|
||||
@@ -38,8 +38,10 @@
|
||||
indice (fuse. blocks
|
||||
(clj->js {:keys ["uuid" "content"]
|
||||
:shouldSort true
|
||||
:tokenize true
|
||||
:minMatchCharLength 2
|
||||
:threshold 0.2}))]
|
||||
:distance 1000
|
||||
:threshold 0.35}))]
|
||||
(swap! indices assoc-in [repo :blocks] indice)
|
||||
indice)))
|
||||
|
||||
@@ -53,8 +55,10 @@
|
||||
indice (fuse. pages
|
||||
(clj->js {:keys ["name"]
|
||||
:shouldSort true
|
||||
:tokenize true
|
||||
:minMatchCharLength 2
|
||||
:threshold 0.2
|
||||
:distance 1000
|
||||
:threshold 0.35
|
||||
}))]
|
||||
(swap! indices assoc-in [repo :pages] indice)
|
||||
indice)))
|
||||
|
||||
@@ -198,6 +198,11 @@
|
||||
(not (false? (:feature/enable-journals?
|
||||
(get (sub-config) repo)))))
|
||||
|
||||
(defn export-heading-to-list?
|
||||
[]
|
||||
(not (false? (:export/heading-to-list?
|
||||
(get (sub-config) (get-current-repo))))))
|
||||
|
||||
(defn enable-encryption?
|
||||
[repo]
|
||||
(:feature/enable-encryption?
|
||||
|
||||
@@ -249,3 +249,7 @@
|
||||
(let [items (map (fn [item] (str "\"" item "\"")) col)]
|
||||
(util/format "[%s]"
|
||||
(string/join ", " items))))
|
||||
|
||||
(defn image-link?
|
||||
[img-formats s]
|
||||
(some (fn [fmt] (re-find (re-pattern (str "(?i)\\." fmt "(?:\\?([^#]*))?(?:#(.*))?$")) s)) img-formats))
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
.ui__toggle {
|
||||
.wrapper {
|
||||
@apply relative inline-block flex-shrink-0
|
||||
@apply relative flex-shrink-0
|
||||
h-6 w-11 border-2 border-transparent flex
|
||||
rounded-full cursor-pointer focus:outline-none focus:shadow-outline;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
(ns frontend.util
|
||||
#?(:clj (:refer-clojure :exclude [format]))
|
||||
(:require
|
||||
#?(:cljs [cljs-bean.core :as bean])
|
||||
#?(:cljs [cljs-time.coerce :as tc])
|
||||
@@ -749,6 +750,18 @@
|
||||
[input]
|
||||
(and input (.-selectionStart input))))
|
||||
|
||||
#?(:cljs
|
||||
(defn input-start?
|
||||
[input]
|
||||
(and input (zero? (.-selectionStart input)))))
|
||||
|
||||
#?(:cljs
|
||||
(defn input-end?
|
||||
[input]
|
||||
(and input
|
||||
(= (count (.-value input))
|
||||
(.-selectionStart input)))))
|
||||
|
||||
#?(:cljs
|
||||
(defn get-selected-text
|
||||
[]
|
||||
@@ -1025,6 +1038,7 @@
|
||||
(defn page-name-sanity
|
||||
[page-name]
|
||||
(-> page-name
|
||||
(string/replace #"/" ".")
|
||||
;; Windows reserved path characters
|
||||
(string/replace #"[\\/:\\*\\?\"<>|]+" "_")))
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
(ns frontend.version)
|
||||
|
||||
(defonce version "0.0.12")
|
||||
(defonce version "0.0.13-1")
|
||||
|
||||
Reference in New Issue
Block a user