|
|
@@ -25,57 +25,46 @@
|
|
|
|
|
|
(rum/defc commands < rum/reactive
|
|
|
[id format]
|
|
|
- (let [show-commands? (util/react *show-commands)]
|
|
|
- (when (and show-commands?
|
|
|
- @*slash-caret-pos
|
|
|
- (not (state/sub :editor/show-page-search?))
|
|
|
- (not (state/sub :editor/show-block-search?))
|
|
|
- (not (state/sub :editor/show-template-search?))
|
|
|
- (not (state/sub :editor/show-input))
|
|
|
- (not (state/sub :editor/show-zotero))
|
|
|
- (not (state/sub :editor/show-date-picker?)))
|
|
|
- (let [matched (util/react *matched-commands)]
|
|
|
- (ui/auto-complete
|
|
|
- matched
|
|
|
- {:get-group-name
|
|
|
- (fn [item]
|
|
|
- (get *first-command-group (first item)))
|
|
|
-
|
|
|
- :item-render
|
|
|
- (fn [item]
|
|
|
- (let [command-name (first item)
|
|
|
- command-doc (get item 2)]
|
|
|
- [:div {:title (when (state/show-command-doc?) command-doc)} command-name]))
|
|
|
-
|
|
|
- :on-chosen
|
|
|
- (fn [chosen-item]
|
|
|
- (let [command (first chosen-item)]
|
|
|
- (reset! commands/*current-command command)
|
|
|
- (let [command-steps (get (into {} matched) command)
|
|
|
- restore-slash? (or
|
|
|
- (contains? #{"Today" "Yesterday" "Tomorrow"} command)
|
|
|
- (and
|
|
|
- (not (fn? command-steps))
|
|
|
- (not (contains? (set (map first command-steps)) :editor/input))
|
|
|
- (not (contains? #{"Date Picker" "Template" "Deadline" "Scheduled" "Upload an image"} command))))]
|
|
|
- (editor-handler/insert-command! id command-steps
|
|
|
- format
|
|
|
- {:restore? restore-slash?}))))
|
|
|
- :class
|
|
|
- "black"})))))
|
|
|
+ (let [matched (util/react *matched-commands)]
|
|
|
+ (ui/auto-complete
|
|
|
+ matched
|
|
|
+ {:get-group-name
|
|
|
+ (fn [item]
|
|
|
+ (get *first-command-group (first item)))
|
|
|
+
|
|
|
+ :item-render
|
|
|
+ (fn [item]
|
|
|
+ (let [command-name (first item)
|
|
|
+ command-doc (get item 2)]
|
|
|
+ [:div {:title (when (state/show-command-doc?) command-doc)} command-name]))
|
|
|
+
|
|
|
+ :on-chosen
|
|
|
+ (fn [chosen-item]
|
|
|
+ (let [command (first chosen-item)]
|
|
|
+ (reset! commands/*current-command command)
|
|
|
+ (let [command-steps (get (into {} matched) command)
|
|
|
+ restore-slash? (or
|
|
|
+ (contains? #{"Today" "Yesterday" "Tomorrow"} command)
|
|
|
+ (and
|
|
|
+ (not (fn? command-steps))
|
|
|
+ (not (contains? (set (map first command-steps)) :editor/input))
|
|
|
+ (not (contains? #{"Date Picker" "Template" "Deadline" "Scheduled" "Upload an image"} command))))]
|
|
|
+ (editor-handler/insert-command! id command-steps
|
|
|
+ format
|
|
|
+ {:restore? restore-slash?}))))
|
|
|
+ :class
|
|
|
+ "black"})))
|
|
|
|
|
|
(rum/defc block-commands < rum/reactive
|
|
|
[id format]
|
|
|
- (when (and (util/react *show-block-commands)
|
|
|
- @*angle-bracket-caret-pos)
|
|
|
- (let [matched (util/react *matched-block-commands)]
|
|
|
- (ui/auto-complete
|
|
|
- (map first matched)
|
|
|
- {:on-chosen (fn [chosen]
|
|
|
- (editor-handler/insert-command! id (get (into {} matched) chosen)
|
|
|
- format
|
|
|
- {:last-pattern commands/angle-bracket}))
|
|
|
- :class "black"}))))
|
|
|
+ (let [matched (util/react *matched-block-commands)]
|
|
|
+ (ui/auto-complete
|
|
|
+ (map first matched)
|
|
|
+ {:on-chosen (fn [chosen]
|
|
|
+ (editor-handler/insert-command! id (get (into {} matched) chosen)
|
|
|
+ format
|
|
|
+ {:last-pattern commands/angle-bracket}))
|
|
|
+ :class "black"})))
|
|
|
|
|
|
(defn- in-sidebar? [el]
|
|
|
(not (.contains (.getElementById js/document "left-container") el)))
|
|
|
@@ -83,38 +72,37 @@
|
|
|
(rum/defc page-search < rum/reactive
|
|
|
{:will-unmount (fn [state] (reset! editor-handler/*selected-text nil) state)}
|
|
|
[id format]
|
|
|
- (when (state/sub :editor/show-page-search?)
|
|
|
- (let [pos (:editor/last-saved-cursor @state/state)
|
|
|
- input (gdom/getElement id)]
|
|
|
- (when input
|
|
|
- (let [current-pos (cursor/pos input)
|
|
|
- edit-content (or (state/sub [:editor/content id]) "")
|
|
|
- edit-block (state/sub :editor/block)
|
|
|
- sidebar? (in-sidebar? input)
|
|
|
- q (or
|
|
|
- @editor-handler/*selected-text
|
|
|
- (when (state/sub :editor/show-page-search-hashtag?)
|
|
|
- (util/safe-subs edit-content pos current-pos))
|
|
|
- (when (> (count edit-content) current-pos)
|
|
|
- (util/safe-subs edit-content pos current-pos)))
|
|
|
- matched-pages (when-not (string/blank? q)
|
|
|
- (editor-handler/get-matched-pages q))]
|
|
|
- (ui/auto-complete
|
|
|
- matched-pages
|
|
|
- {:on-chosen (page-handler/on-chosen-handler input id q pos format)
|
|
|
- :on-enter #(page-handler/page-not-exists-handler input id q current-pos)
|
|
|
- :item-render (fn [page-name chosen?]
|
|
|
- [:div.py-2.preview-trigger-wrapper
|
|
|
- (block/page-preview-trigger
|
|
|
- {:children [:div (search/highlight-exact-query page-name q)]
|
|
|
- :open? chosen?
|
|
|
- :manual? true
|
|
|
- :fixed-position? true
|
|
|
- :tippy-distance 24
|
|
|
- :tippy-position (if sidebar? "left" "right")}
|
|
|
- page-name)])
|
|
|
- :empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a page"]
|
|
|
- :class "black"}))))))
|
|
|
+ (let [pos (:editor/last-saved-cursor @state/state)
|
|
|
+ input (gdom/getElement id)]
|
|
|
+ (when input
|
|
|
+ (let [current-pos (cursor/pos input)
|
|
|
+ edit-content (or (state/sub [:editor/content id]) "")
|
|
|
+ edit-block (state/sub :editor/block)
|
|
|
+ sidebar? (in-sidebar? input)
|
|
|
+ q (or
|
|
|
+ @editor-handler/*selected-text
|
|
|
+ (when (state/sub :editor/show-page-search-hashtag?)
|
|
|
+ (util/safe-subs edit-content pos current-pos))
|
|
|
+ (when (> (count edit-content) current-pos)
|
|
|
+ (util/safe-subs edit-content pos current-pos)))
|
|
|
+ matched-pages (when-not (string/blank? q)
|
|
|
+ (editor-handler/get-matched-pages q))]
|
|
|
+ (ui/auto-complete
|
|
|
+ matched-pages
|
|
|
+ {:on-chosen (page-handler/on-chosen-handler input id q pos format)
|
|
|
+ :on-enter #(page-handler/page-not-exists-handler input id q current-pos)
|
|
|
+ :item-render (fn [page-name chosen?]
|
|
|
+ [:div.py-2.preview-trigger-wrapper
|
|
|
+ (block/page-preview-trigger
|
|
|
+ {:children [:div (search/highlight-exact-query page-name q)]
|
|
|
+ :open? chosen?
|
|
|
+ :manual? true
|
|
|
+ :fixed-position? true
|
|
|
+ :tippy-distance 24
|
|
|
+ :tippy-position (if sidebar? "left" "right")}
|
|
|
+ page-name)])
|
|
|
+ :empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a page"]
|
|
|
+ :class "black"})))))
|
|
|
|
|
|
(rum/defcs block-search-auto-complete < rum/reactive
|
|
|
{:init (fn [state]
|
|
|
@@ -151,44 +139,42 @@
|
|
|
(state/clear-search-result!)
|
|
|
state)}
|
|
|
[state id format]
|
|
|
- (when (state/sub :editor/show-block-search?)
|
|
|
- (let [pos (:editor/last-saved-cursor @state/state)
|
|
|
- input (gdom/getElement id)
|
|
|
- [id format] (:rum/args state)
|
|
|
- current-pos (cursor/pos input)
|
|
|
- edit-content (state/sub [:editor/content id])
|
|
|
- edit-block (state/get-edit-block)
|
|
|
- q (or
|
|
|
- @editor-handler/*selected-text
|
|
|
- (when (> (count edit-content) current-pos)
|
|
|
- (subs edit-content pos current-pos)))]
|
|
|
- (when input
|
|
|
- (block-search-auto-complete edit-block input id q format)))))
|
|
|
+ (let [pos (:editor/last-saved-cursor @state/state)
|
|
|
+ input (gdom/getElement id)
|
|
|
+ [id format] (:rum/args state)
|
|
|
+ current-pos (cursor/pos input)
|
|
|
+ edit-content (state/sub [:editor/content id])
|
|
|
+ edit-block (state/get-edit-block)
|
|
|
+ q (or
|
|
|
+ @editor-handler/*selected-text
|
|
|
+ (when (> (count edit-content) current-pos)
|
|
|
+ (subs edit-content pos current-pos)))]
|
|
|
+ (when input
|
|
|
+ (block-search-auto-complete edit-block input id q format))))
|
|
|
|
|
|
(rum/defc template-search < rum/reactive
|
|
|
{:will-unmount (fn [state] (reset! editor-handler/*selected-text nil) state)}
|
|
|
[id format]
|
|
|
- (when (state/sub :editor/show-template-search?)
|
|
|
- (let [pos (:editor/last-saved-cursor @state/state)
|
|
|
- input (gdom/getElement id)]
|
|
|
- (when input
|
|
|
- (let [current-pos (cursor/pos input)
|
|
|
- edit-content (state/sub [:editor/content id])
|
|
|
- q (or
|
|
|
- (when (>= (count edit-content) current-pos)
|
|
|
- (subs edit-content pos current-pos))
|
|
|
- "")
|
|
|
- matched-templates (editor-handler/get-matched-templates q)
|
|
|
- non-exist-handler (fn [_state]
|
|
|
- (state/set-editor-show-template-search! false))]
|
|
|
- (ui/auto-complete
|
|
|
- matched-templates
|
|
|
- {:on-chosen (editor-handler/template-on-chosen-handler id)
|
|
|
- :on-enter non-exist-handler
|
|
|
- :empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a template"]
|
|
|
- :item-render (fn [[template _block-db-id]]
|
|
|
- template)
|
|
|
- :class "black"}))))))
|
|
|
+ (let [pos (:editor/last-saved-cursor @state/state)
|
|
|
+ input (gdom/getElement id)]
|
|
|
+ (when input
|
|
|
+ (let [current-pos (cursor/pos input)
|
|
|
+ edit-content (state/sub [:editor/content id])
|
|
|
+ q (or
|
|
|
+ (when (>= (count edit-content) current-pos)
|
|
|
+ (subs edit-content pos current-pos))
|
|
|
+ "")
|
|
|
+ matched-templates (editor-handler/get-matched-templates q)
|
|
|
+ non-exist-handler (fn [_state]
|
|
|
+ (state/set-editor-show-template-search! false))]
|
|
|
+ (ui/auto-complete
|
|
|
+ matched-templates
|
|
|
+ {:on-chosen (editor-handler/template-on-chosen-handler id)
|
|
|
+ :on-enter non-exist-handler
|
|
|
+ :empty-div [:div.text-gray-500.pl-4.pr-4 "Search for a template"]
|
|
|
+ :item-render (fn [[template _block-db-id]]
|
|
|
+ template)
|
|
|
+ :class "black"})))))
|
|
|
|
|
|
(rum/defc mobile-bar < rum/reactive
|
|
|
[parent-state parent-id]
|
|
|
@@ -242,7 +228,7 @@
|
|
|
(let [input-value (get state ::input-value)
|
|
|
input-option (get @state/state :editor/show-input)]
|
|
|
(when (seq @input-value)
|
|
|
- ;; no new line input
|
|
|
+ ;; no new line input
|
|
|
(util/stop e)
|
|
|
(let [[_id on-submit] (:rum/args state)
|
|
|
{:keys [pos]} @*slash-caret-pos
|
|
|
@@ -317,7 +303,7 @@
|
|
|
{:top (+ top offset-top)
|
|
|
:max-height to-max-height
|
|
|
:max-width 700
|
|
|
- ;; TODO: auto responsive fixed size
|
|
|
+ ;; TODO: auto responsive fixed size
|
|
|
:width "fit-content"
|
|
|
:z-index 11}
|
|
|
(when set-default-width?
|
|
|
@@ -423,6 +409,63 @@
|
|
|
[:span {:id (str "mock-text_" idx)
|
|
|
:key idx} c]))])
|
|
|
|
|
|
+(defn animated-modal
|
|
|
+ [key component set-default-width? *pos]
|
|
|
+ (when *pos
|
|
|
+ (ui/css-transition
|
|
|
+ {:key key
|
|
|
+ :class-names {:enter "origin-top-left opacity-0 transform scale-95"
|
|
|
+ :enter-done "origin-top-left transition opacity-100"
|
|
|
+ :enter-active "origin-top-left transition"
|
|
|
+ :exit "origin-top-left transition opacity-0 transform scale-95"
|
|
|
+ :exit-active "origin-top-left transition"
|
|
|
+ :exit-done "origin-top-left transition opacity-0 transform scale-95"}
|
|
|
+ :timeout 100}
|
|
|
+ (fn [_]
|
|
|
+ (absolute-modal
|
|
|
+ component
|
|
|
+ set-default-width?
|
|
|
+ *pos)))))
|
|
|
+
|
|
|
+
|
|
|
+(rum/defc modals < rum/reactive
|
|
|
+ "React to atom changes, find and render the correct modal"
|
|
|
+ [id format]
|
|
|
+ (ui/transition-group
|
|
|
+ (cond
|
|
|
+ (and (util/react *show-commands)
|
|
|
+ (not (state/sub :editor/show-page-search?))
|
|
|
+ (not (state/sub :editor/show-block-search?))
|
|
|
+ (not (state/sub :editor/show-template-search?))
|
|
|
+ (not (state/sub :editor/show-input))
|
|
|
+ (not (state/sub :editor/show-zotero))
|
|
|
+ (not (state/sub :editor/show-date-picker?)))
|
|
|
+ (animated-modal "commands" (commands id format) true (util/react *slash-caret-pos))
|
|
|
+
|
|
|
+ (and (util/react *show-block-commands) @*angle-bracket-caret-pos)
|
|
|
+ (animated-modal "block-commands" (block-commands id format) true (util/react *angle-bracket-caret-pos))
|
|
|
+
|
|
|
+ (state/sub :editor/show-page-search?)
|
|
|
+ (animated-modal "page-search" (page-search id format) true (util/react *slash-caret-pos))
|
|
|
+
|
|
|
+ (state/sub :editor/show-block-search?)
|
|
|
+ (animated-modal "block-search" (block-search id format) false (util/react *slash-caret-pos))
|
|
|
+
|
|
|
+ (state/sub :editor/show-template-search?)
|
|
|
+ (animated-modal "template-search" (template-search id format) true (util/react *slash-caret-pos))
|
|
|
+
|
|
|
+ (state/sub :editor/show-date-picker?)
|
|
|
+ (animated-modal "date-picker" (datetime-comp/date-picker id format nil) false (util/react *slash-caret-pos))
|
|
|
+
|
|
|
+ (state/sub :editor/show-input)
|
|
|
+ (animated-modal "input" (input id
|
|
|
+ (fn [command m pos]
|
|
|
+ (editor-handler/handle-command-input command id format m pos)))
|
|
|
+ true (util/react *slash-caret-pos))
|
|
|
+
|
|
|
+ (state/sub :editor/show-zotero)
|
|
|
+ (animated-modal "zotero-search" (zotero/zotero-search id) false (util/react *slash-caret-pos)))))
|
|
|
+
|
|
|
(rum/defcs box < rum/reactive
|
|
|
{:init (fn [state]
|
|
|
(assoc state ::heading-level (:heading-level (first (:rum/args state)))))
|
|
|
@@ -458,52 +501,7 @@
|
|
|
:class (get-editor-heading-class content)})
|
|
|
|
|
|
(mock-textarea)
|
|
|
-
|
|
|
- ;; TODO: how to render the transitions asynchronously?
|
|
|
- (transition-cp
|
|
|
- (commands id format)
|
|
|
- true
|
|
|
- *slash-caret-pos)
|
|
|
-
|
|
|
- (transition-cp
|
|
|
- (block-commands id format)
|
|
|
- true
|
|
|
- *angle-bracket-caret-pos)
|
|
|
-
|
|
|
- (transition-cp
|
|
|
- (page-search id format)
|
|
|
- true
|
|
|
- *slash-caret-pos)
|
|
|
-
|
|
|
- (transition-cp
|
|
|
- (block-search id format)
|
|
|
- false
|
|
|
- *slash-caret-pos)
|
|
|
-
|
|
|
- (transition-cp
|
|
|
- (template-search id format)
|
|
|
- true
|
|
|
- *slash-caret-pos)
|
|
|
-
|
|
|
- (when (state/sub :editor/show-date-picker?)
|
|
|
- (transition-cp
|
|
|
- (datetime-comp/date-picker id format nil)
|
|
|
- false
|
|
|
- *slash-caret-pos))
|
|
|
-
|
|
|
- (when (state/sub :editor/show-input)
|
|
|
- (transition-cp
|
|
|
- (input id
|
|
|
- (fn [command m pos]
|
|
|
- (editor-handler/handle-command-input command id format m pos)))
|
|
|
- true
|
|
|
- *slash-caret-pos))
|
|
|
-
|
|
|
- (when (state/sub :editor/show-zotero)
|
|
|
- (transition-cp
|
|
|
- (zotero/zotero-search id)
|
|
|
- false
|
|
|
- *slash-caret-pos))
|
|
|
+ (modals id format)
|
|
|
|
|
|
(when format
|
|
|
(image-uploader id format))]))
|