From 82ddd4c0796e241c9fd809caa541c85c9f6de600 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Thu, 13 May 2021 00:35:10 +0800 Subject: [PATCH] feat: add block preview use tippy for tooltip --- package.json | 6 +- resources/css/tooltip.css | 17 +-- src/main/frontend/components/block.cljs | 114 ++++++++++------- src/main/frontend/components/page.cljs | 155 ++++++++++++------------ src/main/frontend/format/block.cljs | 10 +- src/main/frontend/state.cljs | 4 + src/main/frontend/ui.cljs | 19 ++- yarn.lock | 57 +++++++-- 8 files changed, 213 insertions(+), 169 deletions(-) diff --git a/package.json b/package.json index 8c85925ca6a..c721c5c15df 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "dependencies": { "@excalidraw/excalidraw": "^0.4.2", "@kanru/rage-wasm": "^0.2.1", + "@tippyjs/react": "^4.2.5", "chokidar": "^3.5.1", "chrono-node": "^2.2.1", "codemirror": "^5.58.1", @@ -75,10 +76,11 @@ "jszip": "^3.5.0", "mldoc": "0.6.16", "path": "^0.12.7", - "react": "^17.0.1", - "react-dom": "^17.0.1", + "react": "^17.0.2", + "react-dom": "^17.0.2", "react-resize-context": "^3.0.0", "react-textarea-autosize": "^8.0.1", + "react-tippy": "^1.4.0", "react-transition-group": "^4.3.0", "url": "^0.11.0", "yargs-parser": "^20.2.4" diff --git a/resources/css/tooltip.css b/resources/css/tooltip.css index 6746aa8c209..2cb679bec92 100644 --- a/resources/css/tooltip.css +++ b/resources/css/tooltip.css @@ -1,16 +1 @@ -.Tooltip { - position:relative; -} - -.Tooltip__label {--arrow-size: 4px;visibility:hidden;width:10ch;background:#000;color:#fff;text-align:center;border-radius:4px;padding:4px;position:absolute;z-index:10;font-size:0.7rem;line-height:1.5;top:calc(100% + var(--arrow-size) + 3px);left:calc(-50% + var(--arrow-size) / 2 - 1px);word-wrap:break-word} -.Tooltip__label::after {content:"";border:var(--arrow-size) solid transparent;border-bottom-color:#000;position:absolute;bottom:100%;left:calc(50% - var(--arrow-size))} - -/* .Tooltip:not(:hover) {pointer-events:none} */ - -.Tooltip:hover .Tooltip__label { - visibility:visible -} - -.Tooltip__label:hover { - visibility:visible -} +.tippy-touch{cursor:pointer!important}.tippy-notransition{transition:none!important}.tippy-popper{max-width:400px;-webkit-perspective:800px;perspective:800px;z-index:9999;outline:0;transition-timing-function:cubic-bezier(.165,.84,.44,1);pointer-events:none}.tippy-popper.html-template{max-width:96%;max-width:calc(100% - 20px)}.tippy-popper[x-placement^=top] [x-arrow]{border-top:7px solid #333;border-right:7px solid transparent;border-left:7px solid transparent;bottom:-7px;margin:0 9px}.tippy-popper[x-placement^=top] [x-arrow].arrow-small{border-top:5px solid #333;border-right:5px solid transparent;border-left:5px solid transparent;bottom:-5px}.tippy-popper[x-placement^=top] [x-arrow].arrow-big{border-top:10px solid #333;border-right:10px solid transparent;border-left:10px solid transparent;bottom:-10px}.tippy-popper[x-placement^=top] [x-circle]{-webkit-transform-origin:0 33%;transform-origin:0 33%}.tippy-popper[x-placement^=top] [x-circle].enter{-webkit-transform:scale(1) translate(-50%,-55%);transform:scale(1) translate(-50%,-55%);opacity:1}.tippy-popper[x-placement^=top] [x-circle].leave{-webkit-transform:scale(.15) translate(-50%,-50%);transform:scale(.15) translate(-50%,-50%);opacity:0}.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-circle]{background-color:#fff}.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-arrow]{border-top:7px solid #fff;border-right:7px solid transparent;border-left:7px solid transparent}.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-arrow].arrow-small{border-top:5px solid #fff;border-right:5px solid transparent;border-left:5px solid transparent}.tippy-popper[x-placement^=top] .tippy-tooltip.light-theme [x-arrow].arrow-big{border-top:10px solid #fff;border-right:10px solid transparent;border-left:10px solid transparent}.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-circle]{background-color:rgba(0,0,0,.7)}.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-arrow]{border-top:7px solid rgba(0,0,0,.7);border-right:7px solid transparent;border-left:7px solid transparent}.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-arrow].arrow-small{border-top:5px solid rgba(0,0,0,.7);border-right:5px solid transparent;border-left:5px solid transparent}.tippy-popper[x-placement^=top] .tippy-tooltip.transparent-theme [x-arrow].arrow-big{border-top:10px solid rgba(0,0,0,.7);border-right:10px solid transparent;border-left:10px solid transparent}.tippy-popper[x-placement^=top] [data-animation=perspective]{-webkit-transform-origin:bottom;transform-origin:bottom}.tippy-popper[x-placement^=top] [data-animation=perspective].enter{opacity:1;-webkit-transform:translateY(-10px) rotateX(0);transform:translateY(-10px) rotateX(0)}.tippy-popper[x-placement^=top] [data-animation=perspective].leave{opacity:0;-webkit-transform:translateY(0) rotateX(90deg);transform:translateY(0) rotateX(90deg)}.tippy-popper[x-placement^=top] [data-animation=fade].enter{opacity:1;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=fade].leave{opacity:0;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=shift].enter{opacity:1;-webkit-transform:translateY(-10px);transform:translateY(-10px)}.tippy-popper[x-placement^=top] [data-animation=shift].leave{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}.tippy-popper[x-placement^=top] [data-animation=scale].enter{opacity:1;-webkit-transform:translateY(-10px) scale(1);transform:translateY(-10px) scale(1)}.tippy-popper[x-placement^=top] [data-animation=scale].leave{opacity:0;-webkit-transform:translateY(0) scale(0);transform:translateY(0) scale(0)}.tippy-popper[x-placement^=bottom] [x-arrow]{border-bottom:7px solid #333;border-right:7px solid transparent;border-left:7px solid transparent;top:-7px;margin:0 9px}.tippy-popper[x-placement^=bottom] [x-arrow].arrow-small{border-bottom:5px solid #333;border-right:5px solid transparent;border-left:5px solid transparent;top:-5px}.tippy-popper[x-placement^=bottom] [x-arrow].arrow-big{border-bottom:10px solid #333;border-right:10px solid transparent;border-left:10px solid transparent;top:-10px}.tippy-popper[x-placement^=bottom] [x-circle]{-webkit-transform-origin:0 -50%;transform-origin:0 -50%}.tippy-popper[x-placement^=bottom] [x-circle].enter{-webkit-transform:scale(1) translate(-50%,-45%);transform:scale(1) translate(-50%,-45%);opacity:1}.tippy-popper[x-placement^=bottom] [x-circle].leave{-webkit-transform:scale(.15) translate(-50%,-5%);transform:scale(.15) translate(-50%,-5%);opacity:0}.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-circle]{background-color:#fff}.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow]{border-bottom:7px solid #fff;border-right:7px solid transparent;border-left:7px solid transparent}.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow].arrow-small{border-bottom:5px solid #fff;border-right:5px solid transparent;border-left:5px solid transparent}.tippy-popper[x-placement^=bottom] .tippy-tooltip.light-theme [x-arrow].arrow-big{border-bottom:10px solid #fff;border-right:10px solid transparent;border-left:10px solid transparent}.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-circle]{background-color:rgba(0,0,0,.7)}.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-arrow]{border-bottom:7px solid rgba(0,0,0,.7);border-right:7px solid transparent;border-left:7px solid transparent}.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-arrow].arrow-small{border-bottom:5px solid rgba(0,0,0,.7);border-right:5px solid transparent;border-left:5px solid transparent}.tippy-popper[x-placement^=bottom] .tippy-tooltip.transparent-theme [x-arrow].arrow-big{border-bottom:10px solid rgba(0,0,0,.7);border-right:10px solid transparent;border-left:10px solid transparent}.tippy-popper[x-placement^=bottom] [data-animation=perspective]{-webkit-transform-origin:top;transform-origin:top}.tippy-popper[x-placement^=bottom] [data-animation=perspective].enter{opacity:1;-webkit-transform:translateY(10px) rotateX(0);transform:translateY(10px) rotateX(0)}.tippy-popper[x-placement^=bottom] [data-animation=perspective].leave{opacity:0;-webkit-transform:translateY(0) rotateX(-90deg);transform:translateY(0) rotateX(-90deg)}.tippy-popper[x-placement^=bottom] [data-animation=fade].enter{opacity:1;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=fade].leave{opacity:0;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=shift].enter{opacity:1;-webkit-transform:translateY(10px);transform:translateY(10px)}.tippy-popper[x-placement^=bottom] [data-animation=shift].leave{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}.tippy-popper[x-placement^=bottom] [data-animation=scale].enter{opacity:1;-webkit-transform:translateY(10px) scale(1);transform:translateY(10px) scale(1)}.tippy-popper[x-placement^=bottom] [data-animation=scale].leave{opacity:0;-webkit-transform:translateY(0) scale(0);transform:translateY(0) scale(0)}.tippy-popper[x-placement^=left] [x-arrow]{border-left:7px solid #333;border-top:7px solid transparent;border-bottom:7px solid transparent;right:-7px;margin:6px 0}.tippy-popper[x-placement^=left] [x-arrow].arrow-small{border-left:5px solid #333;border-top:5px solid transparent;border-bottom:5px solid transparent;right:-5px}.tippy-popper[x-placement^=left] [x-arrow].arrow-big{border-left:10px solid #333;border-top:10px solid transparent;border-bottom:10px solid transparent;right:-10px}.tippy-popper[x-placement^=left] [x-circle]{-webkit-transform-origin:50% 0;transform-origin:50% 0}.tippy-popper[x-placement^=left] [x-circle].enter{-webkit-transform:scale(1) translate(-50%,-50%);transform:scale(1) translate(-50%,-50%);opacity:1}.tippy-popper[x-placement^=left] [x-circle].leave{-webkit-transform:scale(.15) translate(-50%,-50%);transform:scale(.15) translate(-50%,-50%);opacity:0}.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-circle]{background-color:#fff}.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-arrow]{border-left:7px solid #fff;border-top:7px solid transparent;border-bottom:7px solid transparent}.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-arrow].arrow-small{border-left:5px solid #fff;border-top:5px solid transparent;border-bottom:5px solid transparent}.tippy-popper[x-placement^=left] .tippy-tooltip.light-theme [x-arrow].arrow-big{border-left:10px solid #fff;border-top:10px solid transparent;border-bottom:10px solid transparent}.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-circle]{background-color:rgba(0,0,0,.7)}.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-arrow]{border-left:7px solid rgba(0,0,0,.7);border-top:7px solid transparent;border-bottom:7px solid transparent}.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-arrow].arrow-small{border-left:5px solid rgba(0,0,0,.7);border-top:5px solid transparent;border-bottom:5px solid transparent}.tippy-popper[x-placement^=left] .tippy-tooltip.transparent-theme [x-arrow].arrow-big{border-left:10px solid rgba(0,0,0,.7);border-top:10px solid transparent;border-bottom:10px solid transparent}.tippy-popper[x-placement^=left] [data-animation=perspective]{-webkit-transform-origin:right;transform-origin:right}.tippy-popper[x-placement^=left] [data-animation=perspective].enter{opacity:1;-webkit-transform:translateX(-10px) rotateY(0);transform:translateX(-10px) rotateY(0)}.tippy-popper[x-placement^=left] [data-animation=perspective].leave{opacity:0;-webkit-transform:translateX(0) rotateY(-90deg);transform:translateX(0) rotateY(-90deg)}.tippy-popper[x-placement^=left] [data-animation=fade].enter{opacity:1;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=fade].leave{opacity:0;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=shift].enter{opacity:1;-webkit-transform:translateX(-10px);transform:translateX(-10px)}.tippy-popper[x-placement^=left] [data-animation=shift].leave{opacity:0;-webkit-transform:translateX(0);transform:translateX(0)}.tippy-popper[x-placement^=left] [data-animation=scale].enter{opacity:1;-webkit-transform:translateX(-10px) scale(1);transform:translateX(-10px) scale(1)}.tippy-popper[x-placement^=left] [data-animation=scale].leave{opacity:0;-webkit-transform:translateX(0) scale(0);transform:translateX(0) scale(0)}.tippy-popper[x-placement^=right] [x-arrow]{border-right:7px solid #333;border-top:7px solid transparent;border-bottom:7px solid transparent;left:-7px;margin:6px 0}.tippy-popper[x-placement^=right] [x-arrow].arrow-small{border-right:5px solid #333;border-top:5px solid transparent;border-bottom:5px solid transparent;left:-5px}.tippy-popper[x-placement^=right] [x-arrow].arrow-big{border-right:10px solid #333;border-top:10px solid transparent;border-bottom:10px solid transparent;left:-10px}.tippy-popper[x-placement^=right] [x-circle]{-webkit-transform-origin:-50% 0;transform-origin:-50% 0}.tippy-popper[x-placement^=right] [x-circle].enter{-webkit-transform:scale(1) translate(-50%,-50%);transform:scale(1) translate(-50%,-50%);opacity:1}.tippy-popper[x-placement^=right] [x-circle].leave{-webkit-transform:scale(.15) translate(-50%,-50%);transform:scale(.15) translate(-50%,-50%);opacity:0}.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-circle]{background-color:#fff}.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-arrow]{border-right:7px solid #fff;border-top:7px solid transparent;border-bottom:7px solid transparent}.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-arrow].arrow-small{border-right:5px solid #fff;border-top:5px solid transparent;border-bottom:5px solid transparent}.tippy-popper[x-placement^=right] .tippy-tooltip.light-theme [x-arrow].arrow-big{border-right:10px solid #fff;border-top:10px solid transparent;border-bottom:10px solid transparent}.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-circle]{background-color:rgba(0,0,0,.7)}.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-arrow]{border-right:7px solid rgba(0,0,0,.7);border-top:7px solid transparent;border-bottom:7px solid transparent}.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-arrow].arrow-small{border-right:5px solid rgba(0,0,0,.7);border-top:5px solid transparent;border-bottom:5px solid transparent}.tippy-popper[x-placement^=right] .tippy-tooltip.transparent-theme [x-arrow].arrow-big{border-right:10px solid rgba(0,0,0,.7);border-top:10px solid transparent;border-bottom:10px solid transparent}.tippy-popper[x-placement^=right] [data-animation=perspective]{-webkit-transform-origin:left;transform-origin:left}.tippy-popper[x-placement^=right] [data-animation=perspective].enter{opacity:1;-webkit-transform:translateX(10px) rotateY(0);transform:translateX(10px) rotateY(0)}.tippy-popper[x-placement^=right] [data-animation=perspective].leave{opacity:0;-webkit-transform:translateX(0) rotateY(90deg);transform:translateX(0) rotateY(90deg)}.tippy-popper[x-placement^=right] [data-animation=fade].enter{opacity:1;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=fade].leave{opacity:0;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=shift].enter{opacity:1;-webkit-transform:translateX(10px);transform:translateX(10px)}.tippy-popper[x-placement^=right] [data-animation=shift].leave{opacity:0;-webkit-transform:translateX(0);transform:translateX(0)}.tippy-popper[x-placement^=right] [data-animation=scale].enter{opacity:1;-webkit-transform:translateX(10px) scale(1);transform:translateX(10px) scale(1)}.tippy-popper[x-placement^=right] [data-animation=scale].leave{opacity:0;-webkit-transform:translateX(0) scale(0);transform:translateX(0) scale(0)}.tippy-popper .tippy-tooltip.transparent-theme{background-color:rgba(0,0,0,.7)}.tippy-popper .tippy-tooltip.transparent-theme[data-animatefill]{background-color:transparent}.tippy-popper .tippy-tooltip.light-theme{color:#26323d;box-shadow:0 4px 20px 4px rgba(0,20,60,.1),0 4px 80px -8px rgba(0,20,60,.2);background-color:#fff}.tippy-popper .tippy-tooltip.light-theme[data-animatefill]{background-color:transparent}.tippy-tooltip{position:relative;color:#fff;border-radius:4px;font-size:.95rem;padding:.4rem .8rem;text-align:center;will-change:transform;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#333}.tippy-tooltip--small{padding:.25rem .5rem;font-size:.8rem}.tippy-tooltip--big{padding:.6rem 1.2rem;font-size:1.2rem}.tippy-tooltip[data-animatefill]{overflow:hidden;background-color:transparent}.tippy-tooltip[data-interactive]{pointer-events:auto}.tippy-tooltip[data-inertia]{transition-timing-function:cubic-bezier(.53,2,.36,.85)}.tippy-tooltip [x-arrow]{position:absolute;width:0;height:0}.tippy-tooltip [x-circle]{position:absolute;will-change:transform;background-color:#333;border-radius:50%;width:130%;width:calc(110% + 2rem);left:50%;top:50%;z-index:-1;overflow:hidden;transition:all ease}.tippy-tooltip [x-circle]:before{content:"";padding-top:90%;float:left}@media (max-width:450px){.tippy-popper{max-width:96%;max-width:calc(100% - 20px)}} diff --git a/src/main/frontend/components/block.cljs b/src/main/frontend/components/block.cljs index 715438118d2..870ace30d77 100644 --- a/src/main/frontend/components/block.cljs +++ b/src/main/frontend/components/block.cljs @@ -330,6 +330,39 @@ (declare page-reference) +(rum/defc page-inner + [config page-name href redirect-page-name page-entity contents-page? children html-export? label] + [:a.page-ref + {:data-ref page-name + :href href + :on-click (fn [e] + (util/stop e) + (if (gobj/get e "shiftKey") + (when-let [page-entity (db/entity [:block/name redirect-page-name])] + (state/sidebar-add-block! + (state/get-current-repo) + (:db/id page-entity) + :page + {:page page-entity})) + (route-handler/redirect! {:to :page + :path-params {:name redirect-page-name}})) + (when (and contents-page? + (state/get-left-sidebar-open?)) + (ui-handler/close-left-sidebar!)))} + + (if (seq children) + (for [child children] + (if (= (first child) "Label") + (last child) + (let [{:keys [content children]} (last child) + page-name (subs content 2 (- (count content) 2))] + (page-reference html-export? page-name (assoc config :children children) nil)))) + (if (and label + (string? label) + (not (string/blank? label))) ; alias + label + (get page-entity :block/original-name page-name)))]) + (rum/defc page-cp [{:keys [html-export? label children contents-page?] :as config} page] (when-let [page-name (:block/name page)] @@ -349,37 +382,14 @@ page) href (if html-export? (util/encode-str page) - (rfe/href :page {:name redirect-page-name}))] - [:a.page-ref - {:data-ref page-name - :href href - :on-click (fn [e] - (util/stop e) - (if (gobj/get e "shiftKey") - (when-let [page-entity (db/entity [:block/name redirect-page-name])] - (state/sidebar-add-block! - (state/get-current-repo) - (:db/id page-entity) - :page - {:page page-entity})) - (route-handler/redirect! {:to :page - :path-params {:name redirect-page-name}})) - (when (and contents-page? - (state/get-left-sidebar-open?)) - (ui-handler/close-left-sidebar!)))} - - (if (seq children) - (for [child children] - (if (= (first child) "Label") - (last child) - (let [{:keys [content children]} (last child) - page-name (subs content 2 (- (count content) 2))] - (page-reference html-export? page-name (assoc config :children children) nil)))) - (if (and label - (string? label) - (not (string/blank? label))) ; alias - label - (get page-entity :block/original-name page-name)))]))) + (rfe/href :page {:name redirect-page-name})) + inner (page-inner config page-name href redirect-page-name page-entity contents-page? children html-export? label)] + inner + ;; (ui/tippy + ;; {:interactive true + ;; :html (page-preview page-name)} + ;; inner) + ))) (rum/defc asset-reference [title path] @@ -496,6 +506,7 @@ (util/format "{{{%s}}}" name))) (declare block-content) +(declare block-container) (rum/defc block-reference < rum/reactive [config id label] (when-not (string/blank? id) @@ -524,9 +535,12 @@ :span.block-ref (map-inline config title))))] (if label - (->elem - :span.block-ref {:title (:block/content block)} ; TODO: replace with a popup - (map-inline config label)) + (ui/tippy + {:html (block-container config block) + :interactive true} + (->elem + :span.block-ref + (map-inline config label))) title))] [:span.warning.mr-1 {:title "Block ref invalid"} (util/format "((%s))" id)])))) @@ -870,7 +884,6 @@ (<= (count url) 15) url :else (last (re-find id-regex url)))] - (prn {:id id}) (when-not (string/blank? id) (let [width (min (- (util/get-width) 96) 560) @@ -1097,7 +1110,6 @@ {:top 0} {:bottom 0}))}])) -(declare block-container) (defn block-checkbox [block class] (let [marker (:block/marker block) @@ -1163,20 +1175,28 @@ :style {:margin-right 3.5}} (string/upper-case marker)]))) +(rum/defc set-priority + [block priority] + [:ul + (for [p (remove #(= priority %) ["A" "B" "C"])] + [:a.mr-2.text-base.tooltip-priority {:priority p + :on-click (fn [] (editor-handler/set-priority block p))}])]) + +(rum/defc priority-text + [priority] + [:a.opacity-50.hover:opacity-100 + {:class "priority" + :href (rfe/href :page {:name priority}) + :style {:margin-right 3.5}} + (util/format "[#%s]" (str priority))]) + (defn priority-cp [{:block/keys [pre-block? priority] :as block}] - (when (and (not pre-block?) priority) - (ui/tooltip - [:ul - (for [p (remove #(= priority %) ["A" "B" "C"])] - [:a.mr-2.text-base.tooltip-priority {:priority p - :on-click (fn [] (editor-handler/set-priority block p))}])] - [:a.opacity-50.hover:opacity-100 - {:class "priority" - :href (rfe/href :page {:name priority}) - :style {:margin-right 3.5}} - (util/format "[#%s]" (str priority))]))) + (ui/tippy + {:interactive true + :html (set-priority block priority)} + (priority-text priority)))) (defn block-tags-cp [{:block/keys [pre-block? tags] :as block}] diff --git a/src/main/frontend/components/page.cljs b/src/main/frontend/components/page.cljs index e41613dacdc..319a9ea2e02 100644 --- a/src/main/frontend/components/page.cljs +++ b/src/main/frontend/components/page.cljs @@ -80,23 +80,26 @@ :sidebar? sidebar?}) (str page-name "-hiccup"))]) +(declare page) + (rum/defc page-blocks-cp < rum/reactive db-mixins/query - [repo page file-path page-name page-original-name encoded-page-name sidebar? journal? block? block-id format] + [repo page-e file-path page-name page-original-name encoded-page-name sidebar? journal? block? block-id format] (let [raw-page-blocks (get-blocks repo page-name page-original-name block? block-id) ;; grouped-blocks-by-file (into {} (for [[k v] (db-utils/group-by-file raw-page-blocks)] ;; [(:file/path (db-utils/entity (:db/id k))) v])) ;; raw-page-blocks (get grouped-blocks-by-file file-path raw-page-blocks) page-blocks (block-handler/with-dummy-block raw-page-blocks format (if (empty? raw-page-blocks) - {:block/page {:db/id (:db/id page)} - :block/file {:db/id (:db/id (:block/file page))}}) + {:block/page {:db/id (:db/id page-e)} + :block/file {:db/id (:db/id (:block/file page-e))}}) {:journal? journal? :page-name page-name}) hiccup-config {:id (if block? (str block-id) page-name) :sidebar? sidebar? :block? block? - :editor-box editor/box} + :editor-box editor/box + :page page} hiccup-config (common-handler/config-with-document-mode hiccup-config) hiccup (block/->hiccup page-blocks hiccup-config {})] (page-blocks-inner page-name page-blocks hiccup sidebar?))) @@ -130,7 +133,8 @@ (for [{:keys [title] :as query} queries] (rum/with-key (block/custom-query {:attr {:class "mt-10"} - :editor-box editor/box} query) + :editor-box editor/box + :page page} query) (str repo "-custom-query-" (:query query))))])))) (defn- delete-page! @@ -233,8 +237,9 @@ :did-update (fn [state] (ui-handler/scroll-and-highlight! state) state)} - [state {:keys [repo] :as option}] - (when-let [path-page-name (or (get-page-name state) + [state {:keys [repo page-name preview?] :as option}] + (when-let [path-page-name (or page-name + (get-page-name state) (state/get-current-page))] (let [current-repo (state/sub :git/current-repo) repo (or repo current-repo) @@ -297,74 +302,74 @@ (not sidebar?) (not config/publishing?)) - (let [contents? (= (string/lower-case (str page-name)) "contents") - links (fn [] (->> - [(when-not contents? - {:title (t :page/add-to-contents) - :options {:on-click (fn [] (page-handler/handle-add-page-to-contents! page-original-name))}}) - - (when-not contents? - {:title (t :page/rename) - :options {:on-click #(state/set-modal! (rename-page-dialog title page-name))}}) - - (when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))] - [{:title (t :page/open-in-finder) - :options {:on-click #(js/window.apis.showItemInFolder file-path)}} - {:title (t :page/open-with-default-app) - :options {:on-click #(js/window.apis.openPath file-path)}}]) - - (when-not contents? - {:title (t :page/delete) - :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}}) - - (when (state/get-current-page) - {:title (t :export) - :options {:on-click #(state/set-modal! export/export-page)}}) - - (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 developer-mode? - {:title "(Dev) Show page data" - :options {:on-click (fn [] - (let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))] - (println page-data) - (notification/show! - [:div - [:pre.code page-data] - [:br] - (ui/button "Copy to clipboard" - :on-click #(.writeText js/navigator.clipboard page-data))] - :success - false)))}})] - (flatten) - (remove nil?)))] - [:div {:style {:position "absolute" - :right 0 - :top 20}} - [:div.flex.flex-row - [:a.opacity-30.hover:opacity-100.page-op.mr-2 - {:title "Search in current page" - :on-click #(route-handler/go-to-search! :page)} - svg/search] - (when (not config/mobile?) - (presentation repo page)) - (ui/dropdown-with-links - (fn [{:keys [toggle-fn]}] - [:a.opacity-30.hover:opacity-100 - {:title "More options" - :on-click toggle-fn} - (svg/vertical-dots {:class (util/hiccup->class "opacity-30.hover:opacity-100.h-5.w-5")})]) - links - {:modal-class (util/hiccup->class - "origin-top-right.absolute.right-0.top-10.mt-2.rounded-md.shadow-lg.whitespace-no-wrap.dropdown-overflow-auto.page-drop-options") - :z-index 1})]])) + (let [contents? (= (string/lower-case (str page-name)) "contents") + links (fn [] (->> + [(when-not contents? + {:title (t :page/add-to-contents) + :options {:on-click (fn [] (page-handler/handle-add-page-to-contents! page-original-name))}}) + + (when-not contents? + {:title (t :page/rename) + :options {:on-click #(state/set-modal! (rename-page-dialog title page-name))}}) + + (when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))] + [{:title (t :page/open-in-finder) + :options {:on-click #(js/window.apis.showItemInFolder file-path)}} + {:title (t :page/open-with-default-app) + :options {:on-click #(js/window.apis.openPath file-path)}}]) + + (when-not contents? + {:title (t :page/delete) + :options {:on-click #(state/set-modal! (delete-page-dialog page-name))}}) + + (when (state/get-current-page) + {:title (t :export) + :options {:on-click #(state/set-modal! export/export-page)}}) + + (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 developer-mode? + {:title "(Dev) Show page data" + :options {:on-click (fn [] + (let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))] + (println page-data) + (notification/show! + [:div + [:pre.code page-data] + [:br] + (ui/button "Copy to clipboard" + :on-click #(.writeText js/navigator.clipboard page-data))] + :success + false)))}})] + (flatten) + (remove nil?)))] + [:div {:style {:position "absolute" + :right 0 + :top 20}} + [:div.flex.flex-row + [:a.opacity-30.hover:opacity-100.page-op.mr-2 + {:title "Search in current page" + :on-click #(route-handler/go-to-search! :page)} + svg/search] + (when (not config/mobile?) + (presentation repo page)) + (ui/dropdown-with-links + (fn [{:keys [toggle-fn]}] + [:a.opacity-30.hover:opacity-100 + {:title "More options" + :on-click toggle-fn} + (svg/vertical-dots {:class (util/hiccup->class "opacity-30.hover:opacity-100.h-5.w-5")})]) + links + {:modal-class (util/hiccup->class + "origin-top-right.absolute.right-0.top-10.mt-2.rounded-md.shadow-lg.whitespace-no-wrap.dropdown-overflow-auto.page-drop-options") + :z-index 1})]])) (when (and (not sidebar?) (not block?)) [:a {:on-click (fn [e] diff --git a/src/main/frontend/format/block.cljs b/src/main/frontend/format/block.cljs index 6e8fa6bbed9..c4d1629e094 100644 --- a/src/main/frontend/format/block.cljs +++ b/src/main/frontend/format/block.cljs @@ -109,10 +109,12 @@ (and (vector? block) (= "Link" (first block)) - (map? (second block)) - (= "id" (:protocol (second (:url (second block)))))) - - (:link (second (:url (second block)))) + (map? (second block))) + (if (= "id" (:protocol (second (:url (second block))))) + (:link (second (:url (second block)))) + (let [id (second (:url (second block)))] + (when (text/block-ref? id) + (text/block-ref-un-brackets! id)))) :else nil)] diff --git a/src/main/frontend/state.cljs b/src/main/frontend/state.cljs index e62c3bd3d23..e38bc04b349 100644 --- a/src/main/frontend/state.cljs +++ b/src/main/frontend/state.cljs @@ -756,6 +756,10 @@ (set-state! :ui/theme theme) (storage/set :ui/theme theme)) +(defn dark? + [] + (= "dark" (:ui/theme @state))) + (defn set-editing-block-dom-id! [block-dom-id] (set-state! :editor/block-dom-id block-dom-id)) diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index f7faa992f31..fa0af1cc52f 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -4,6 +4,7 @@ ["react-transition-group" :refer [TransitionGroup CSSTransition]] ["react-textarea-autosize" :as TextareaAutosize] ["react-resize-context" :as Resize] + ["react-tippy" :as react-tippy] [frontend.util :as util] [frontend.mixins :as mixins] [frontend.handler.notification :as notification-handler] @@ -23,6 +24,7 @@ (defonce textarea (r/adapt-class (gobj/get TextareaAutosize "default"))) (def resize-provider (r/adapt-class (gobj/get Resize "ResizeProvider"))) (def resize-consumer (r/adapt-class (gobj/get Resize "ResizeConsumer"))) +(def Tippy (r/adapt-class (gobj/get react-tippy "Tooltip"))) (rum/defc ls-textarea < rum/reactive [{:keys [on-change] :as props}] @@ -369,18 +371,6 @@ {:class (if on? (if small? "translate-x-4" "translate-x-5") "translate-x-0") :aria-hidden "true"}]]])) -(defn tooltip - ([label children] - (tooltip label children {})) - ([label children {:keys [label-style]}] - [:div.Tooltip {:style {:display "inline"}} - [:div (cond-> - {:class "Tooltip__label"} - label-style - (assoc :style label-style)) - label] - children])) - (defonce modal-show? (atom false)) (rum/defc modal-overlay [state] @@ -585,3 +575,8 @@ selected (assoc :selected selected)) label])]) + +(rum/defc tippy + [opts child] + (Tippy (merge {:arrow true} opts) + child)) diff --git a/yarn.lock b/yarn.lock index bd7ab4a2733..fe1007d743e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,6 +237,11 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" +"@popperjs/core@^2.8.3": + version "2.9.2" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353" + integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q== + "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz" @@ -301,6 +306,13 @@ hex-rgb "^4.1.0" postcss-selector-parser "^6.0.2" +"@tippyjs/react@^4.2.5": + version "4.2.5" + resolved "https://registry.yarnpkg.com/@tippyjs/react/-/react-4.2.5.tgz#9b5837db93a1cac953962404df906aef1a18e80d" + integrity sha512-YBLgy+1zznBNbx4JOoOdFXWMLXjBh9hLPwRtq3s8RRdrez2l3tPBRt2m2909wZd9S1KUeKjOOYYsnitccI9I3A== + dependencies: + tippy.js "^6.3.1" + "@types/expect@^1.20.4": version "1.20.4" resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz" @@ -4480,6 +4492,11 @@ plugin-error@1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" +popper.js@^1.11.1: + version "1.16.1" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" + integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz" @@ -5087,14 +5104,14 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -react-dom@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.1.tgz" - integrity sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug== +react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" - scheduler "^0.20.1" + scheduler "^0.20.2" react-is@^16.8.1: version "16.13.1" @@ -5120,6 +5137,13 @@ react-textarea-autosize@^8.0.1: use-composed-ref "^1.0.0" use-latest "^1.0.0" +react-tippy@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/react-tippy/-/react-tippy-1.4.0.tgz#e8a8b4085ec985e5c94fe128918b733b588a1465" + integrity sha512-r/hM5XK9Ztr2ZY7IWKuRmISTlUPS/R6ddz6PO2EuxCgW+4JBcGZRPU06XcVPRDCOIiio8ryBQFrXMhFMhsuaHA== + dependencies: + popper.js "^1.11.1" + react-transition-group@^4.3.0: version "4.4.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz" @@ -5130,10 +5154,10 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz" - integrity sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w== +react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -5482,10 +5506,10 @@ sax@~1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -scheduler@^0.20.1: - version "0.20.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz" - integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw== +scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" @@ -6137,6 +6161,13 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tippy.js@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.1.tgz#3788a007be7015eee0fd589a66b98fb3f8f10181" + integrity sha512-JnFncCq+rF1dTURupoJ4yPie5Cof978inW6/4S6kmWV7LL9YOSEVMifED3KdrVPEG+Z/TFH2CDNJcQEfaeuQww== + dependencies: + "@popperjs/core" "^2.8.3" + to-absolute-glob@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz"