From 0ff131302e6ebbdc4a1ffa7715b057c760a88a24 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Tue, 22 Mar 2022 22:21:58 -0400 Subject: [PATCH 01/79] feat: progress --- src/cljs/athens/views.cljs | 80 ++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index ec86fd1220..256f028477 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -1,39 +1,25 @@ (ns athens.views (:require - ["/components/Spinner/Spinner" :refer [Spinner]] - ["/components/utils/style/style" :refer [GlobalStyles]] - ["@material-ui/core/Snackbar" :as Snackbar] - ["@react-aria/overlays" :refer [OverlayProvider]] - [athens.config] - [athens.electron.db-modal :as db-modal] - [athens.electron.utils :as electron.utils] - [athens.style :refer [zoom]] - [athens.subs] - [athens.util :refer [get-os]] - [athens.views.app-toolbar :as app-toolbar] - [athens.views.athena :refer [athena-component]] - [athens.views.devtool :refer [devtool-component]] - [athens.views.help :refer [help-popup]] - [athens.views.left-sidebar :as left-sidebar] - [athens.views.pages.core :as pages] - [athens.views.right-sidebar :as right-sidebar] - [re-frame.core :as rf] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]])) - - -;; Styles - - -(def app-wrapper-style - {:display "grid" - :grid-template-areas - "'app-header app-header app-header' - 'left-sidebar main-content secondary-content' - 'devtool devtool devtool'" - :grid-template-columns "auto 1fr auto" - :grid-template-rows "auto 1fr auto" - :height "100vh"}) + ["/components/Spinner/Spinner" :refer [Spinner]] + ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [ChakraProvider Grid]] + ["@material-ui/core/Snackbar" :as Snackbar] + ["@react-aria/overlays" :refer [OverlayProvider]] + [athens.config] + [athens.electron.db-modal :as db-modal] + [athens.electron.utils :as electron.utils] + [athens.style :refer [zoom]] + [athens.subs] + [athens.util :refer [get-os]] + [athens.views.app-toolbar :as app-toolbar] + [athens.views.athena :refer [athena-component]] + [athens.views.devtool :refer [devtool-component]] + [athens.views.help :refer [help-popup]] + [athens.views.left-sidebar :as left-sidebar] + [athens.views.pages.core :as pages] + [athens.views.right-sidebar :as right-sidebar] + [re-frame.core :as rf] + [reagent.core :as r])) ;; Components @@ -72,10 +58,11 @@ electron? electron.utils/electron? modal (rf/subscribe [:modal])] (fn [] - [:> OverlayProvider + [:> ChakraProvider {:theme theme, + :bg "background.basement"} + [:> OverlayProvider [:div (merge {:style {:display "contents"}} (zoom)) - [:> GlobalStyles] [help-popup] [alert] (let [{:keys [msg type]} @(rf/subscribe [:db/snack-msg])] @@ -97,14 +84,21 @@ :else [:<> (when @modal [db-modal/window]) - [:div (use-style app-wrapper-style - {:class [(case os - :windows "os-windows" - :mac "os-mac" - :linux "os-linux") - (when electron? "is-electron")]}) + [:> Grid + {:gridTemplateColumns "auto 1fr auto" + :gridTemplateRows "auto 1fr auto" + :grid-template-areas + "'app-header app-header app-header' + 'left-sidebar main-content secondary-content' + 'devtool devtool devtool'" + :height "100vh" + :className [(case os + :windows "os-windows" + :mac "os-mac" + :linux "os-linux") + (when electron? "is-electron")]} [app-toolbar/app-toolbar] [left-sidebar/left-sidebar] [pages/view] [right-sidebar/right-sidebar] - [devtool-component]]])]]))) + [devtool-component]]])]]]))) From aa7730a8bff8824be7d0058af67852b53b1cb105 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 23 Mar 2022 00:04:12 -0400 Subject: [PATCH 02/79] feat: progress --- .clj-kondo/rewrite-clj/rewrite-clj/config.edn | 5 + package.json | 5 + resources/public/index.html | 1 - src/cljs/athens/components.cljs | 19 +- src/cljs/athens/electron/db_menu/core.cljs | 165 ++-- src/cljs/athens/electron/db_menu/db_icon.cljs | 1 + .../athens/electron/db_menu/db_list_item.cljs | 119 ++- src/cljs/athens/electron/db_modal.cljs | 173 ++-- src/cljs/athens/views.cljs | 2 +- src/cljs/athens/views/athena.cljs | 347 +++---- src/cljs/athens/views/blocks/content.cljs | 139 +-- src/cljs/athens/views/blocks/core.cljs | 54 +- src/cljs/athens/views/left_sidebar.cljs | 272 +++--- src/cljs/athens/views/right_sidebar.cljs | 190 ++-- src/js/components/AppToolbar/AppToolbar.tsx | 283 +++--- src/js/components/Icons/icons.ts | 2 + src/js/theme/index.js | 2 + src/js/theme/spacing.js | 19 + src/js/theme/theme.js | 152 +++ yarn.lock | 910 +++++++++++++++++- 20 files changed, 1862 insertions(+), 998 deletions(-) create mode 100644 .clj-kondo/rewrite-clj/rewrite-clj/config.edn create mode 100644 src/js/components/Icons/icons.ts create mode 100644 src/js/theme/index.js create mode 100644 src/js/theme/spacing.js create mode 100644 src/js/theme/theme.js diff --git a/.clj-kondo/rewrite-clj/rewrite-clj/config.edn b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn new file mode 100644 index 0000000000..19ecae96a0 --- /dev/null +++ b/.clj-kondo/rewrite-clj/rewrite-clj/config.edn @@ -0,0 +1,5 @@ +{:lint-as + {rewrite-clj.zip/subedit-> clojure.core/-> + rewrite-clj.zip/subedit->> clojure.core/->> + rewrite-clj.zip/edit-> clojure.core/-> + rewrite-clj.zip/edit->> clojure.core/->>}} diff --git a/package.json b/package.json index 868648192a..d9f9cbcc66 100644 --- a/package.json +++ b/package.json @@ -100,6 +100,9 @@ }, "dependencies": { "@babel/runtime": "^7.15.4", + "@chakra-ui/react": "^1.8.6", + "@emotion/react": "^11", + "@emotion/styled": "^11", "@geometricpanda/storybook-addon-badges": "^0.0.4", "@js-joda/core": "1.12.0", "@js-joda/locale_en-us": "3.1.1", @@ -125,6 +128,7 @@ "electron-updater": "^4.3.4", "electron-window-state": "^5.0.3", "emoji-picker-element": "^1.8.2", + "framer-motion": "^6", "highlight.js": "^11.1.0", "iconoir": "^1.0.0", "iconoir-react": "^2.1.0", @@ -137,6 +141,7 @@ "react-colorful": "^5.4.0", "react-day-picker": "^7.4.10", "react-dom": "17.0.1", + "react-focus-lock": "^2.8.1", "react-force-graph-2d": "^1.19.0", "react-highlight.js": "1.0.7", "react-hot-toast": "^2.1.1", diff --git a/resources/public/index.html b/resources/public/index.html index 2d291a3e0d..c7a0500c30 100644 --- a/resources/public/index.html +++ b/resources/public/index.html @@ -5,7 +5,6 @@ - diff --git a/src/cljs/athens/components.cljs b/src/cljs/athens/components.cljs index f13bdfb337..77655a6278 100644 --- a/src/cljs/athens/components.cljs +++ b/src/cljs/athens/components.cljs @@ -1,5 +1,6 @@ (ns athens.components (:require + ["@chakra-ui/react" :refer [Checkbox]] ["@material-ui/icons/Edit" :default Edit] [athens.db :as db] [athens.parse-renderer :refer [component]] @@ -29,25 +30,27 @@ TODO() - might be a good idea to keep an edit icon at top right for every component." [children] - [:span {:on-click (fn [e] - (.. e stopPropagation))} + [:span {:style {:display "contents"} + :on-click (fn [e] (.. e stopPropagation))} children]) (defmethod component :todo [_content uid] [span-click-stop - [:input {:type "checkbox" - :checked false - :on-change #(todo-on-click uid #"\{\{\[\[TODO\]\]\}\}" "{{[[DONE]]}}")}]]) + [:> Checkbox {:isChecked false + :verticalAlign "middle" + :transform "translateY(-2px)" + :onChange #(todo-on-click uid #"\{\{\[\[TODO\]\]\}\}" "{{[[DONE]]}}")}]]) (defmethod component :done [_content uid] [span-click-stop - [:input {:type "checkbox" - :checked true - :on-change #(todo-on-click uid #"\{\{\[\[DONE\]\]\}\}" "{{[[TODO]]}}")}]]) + [:> Checkbox {:isChecked true + :verticalAlign "middle" + :transform "translateY(-2px)" + :onChange #(todo-on-click uid #"\{\{\[\[DONE\]\]\}\}" "{{[[TODO]]}}")}]]) (defmethod component :youtube diff --git a/src/cljs/athens/electron/db_menu/core.cljs b/src/cljs/athens/electron/db_menu/core.cljs index e2b352feb4..268d028d21 100644 --- a/src/cljs/athens/electron/db_menu/core.cljs +++ b/src/cljs/athens/electron/db_menu/core.cljs @@ -1,124 +1,67 @@ (ns athens.electron.db-menu.core (:require - ["/components/Button/Button" :refer [Button]] - ["@material-ui/core/Popover" :as Popover] - ["@material-ui/icons/AddCircleOutline" :default AddCircleOutline] - [athens.electron.db-menu.db-icon :refer [db-icon]] - [athens.electron.db-menu.db-list-item :refer [db-list-item]] - [athens.electron.dialogs :as dialogs] - [athens.style :refer [color DEPTH-SHADOWS]] - [athens.views.dropdown :refer [menu-style menu-separator-style]] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]])) - - -;; ------------------------------------------------------------------- -;; --- material ui --- - -(def m-popover (r/adapt-react-class (.-default Popover))) - - -;; Style - -(def dropdown-style - {::stylefy/manual [[:.menu {:background (color :background-plus-2) - :color (color :body-text-color) - :border-radius "calc(0.25rem + 0.25rem)" ; Button corner radius + container padding makes "concentric" container radius - :padding "0.25rem" - :display "inline-flex" - :box-shadow [[(:64 DEPTH-SHADOWS) ", 0 0 0 1px rgba(0, 0, 0, 0.05)"]]}]]}) - - -(def db-menu-button-style - {:color (color :body-text-color :opacity-high) - :background "inherit" - :padding "0" - :align-items "stretch" - :justify-content "stretch" - :justify-items "stretch" - :width "1.75em" - :height "1.75em" - :border "1px solid transparent"}) - - -(def current-db-area-style - {:background "rgba(144, 144, 144, 0.05)" - :margin "-0.25rem -0.25rem 0.125rem" - :border-bottom [["1px solid " (color :border-color)]] - :padding "0.25rem"}) - - -(def current-db-tools-style - {:margin-left "2rem"}) - + ["@chakra-ui/react" :refer [Box IconButton VStack ButtonGroup PopoverTrigger ButtonGroup Popover PopoverContent Portal Button Divider]] + ["react-focus-lock" :default FocusLock] + [athens.electron.db-menu.db-icon :refer [db-icon]] + [athens.electron.db-menu.db-list-item :refer [db-list-item]] + [athens.electron.dialogs :as dialogs] + [re-frame.core :refer [dispatch subscribe]])) ;; Components (defn current-db-tools ([{:keys [db]} all-dbs] - [:div (use-style current-db-tools-style) - (if (:is-remote db) - [:<> - [:> Button "Import"] - [:> Button "Copy Link"] - [:> Button "Remove"]] - [:<> - [:> Button {:onClick #(dialogs/move-dialog!)} "Move"] - ;; [:> Button {:onClick "Rename"] - [:> Button {:onClick #(if (= 1 (count all-dbs)) - (js/alert "Can't remove last db from the list") - (dialogs/delete-dialog! db))} - "Delete"]])])) + (if (:is-remote db) + [:> ButtonGroup {:size "sm" :pl 10 :ml "auto" :width "100%"} + [:> Button "Import"] + [:> Button "Copy Link"] + [:> Button "Remove"]] + [:> ButtonGroup {:size "sm" :pl 10 :ml "auto" :width "100%"} + [:> Button {:onClick #(dialogs/move-dialog!)} "Move"] + [:> Button {:onClick #(if (= 1 (count all-dbs)) + (js/alert "Can't remove last db from the list") + (dialogs/delete-dialog! db))} + "Remove"]]))) (defn db-menu [] - (r/with-let [ele (r/atom nil)] - (let [all-dbs @(subscribe [:db-picker/all-dbs]) - active-db @(subscribe [:db-picker/selected-db]) - inactive-dbs (dissoc all-dbs (:id active-db)) - sync-status (if @(subscribe [:db/synced]) - :running - :synchronising)] - [:<> - ;; DB Icon + Dropdown toggle - [:> Button {:class [(when @ele "is-active")] - :on-click #(reset! ele (.-currentTarget %)) - :style db-menu-button-style} - [db-icon {:db active-db - :status sync-status}]] - ;; Dropdown menu - [m-popover - (merge (use-style dropdown-style) - {:style {:font-size "14px"} - :open (boolean @ele) - :anchorEl @ele - :onClose #(reset! ele nil) - :anchorOrigin #js{:vertical "bottom" - :horizontal "left"} - :marginThreshold 10 - :transformOrigin #js{:vertical "top" - :horizontal "left"} - :classes {:root "backdrop" - :paper "menu"}}) - [:div (use-style (merge menu-style - {:overflow "visible"})) - [:<> - ;; Show active DB first - [:div (use-style current-db-area-style) - [db-list-item {:db active-db - :is-current true - :key (:id active-db)}] - [current-db-tools {:db active-db} all-dbs]] + (let [all-dbs @(subscribe [:db-picker/all-dbs]) + active-db @(subscribe [:db-picker/selected-db]) + inactive-dbs (dissoc all-dbs (:id active-db)) + sync-status (if @(subscribe [:db/synced]) + :running + :synchronising)] + [:> Popover {:placement "bottom-start"} + [:> PopoverTrigger + [:> IconButton + ;; DB Icon + Dropdown toggle + [db-icon {:db active-db + :status sync-status}]]] + ;; Dropdown menu + [:> Portal + [:> PopoverContent {} + [:> FocusLock + [:> VStack {:align "stretch" + :overflowY "auto" + :spacing 2} + ;; Show active DB first + [:> Box + [db-list-item {:db active-db + :is-current true + :key (:id active-db)}] + [current-db-tools {:db active-db} all-dbs]] ;; Show all inactive DBs and a separator - (doall - (for [[key db] inactive-dbs] - [db-list-item {:db db - :is-current false - :key key}])) - [:hr (use-style menu-separator-style)] + [:> VStack + {:align "stretch" :spacing 0} + (doall + (for [[key db] inactive-dbs] + [:<> + [db-list-item {:db db + :is-current false + :key key}] + [:> Divider]]))] ;; Add DB control - [:> Button {:on-click #(dispatch [:modal/toggle])} - [:> AddCircleOutline] - [:span "Add Database"]]]]]]))) + [:> ButtonGroup {:p 2 :pt 0 :pl 10 :size "sm" :width "100%" :ml 10 :justifyContent "flex-start"} + [:> Button {:onClick #(dispatch [:modal/toggle])} + "Add Database"]]]]]]])) diff --git a/src/cljs/athens/electron/db_menu/db_icon.cljs b/src/cljs/athens/electron/db_menu/db_icon.cljs index 27fef1f938..91ae19ecbb 100644 --- a/src/cljs/athens/electron/db_menu/db_icon.cljs +++ b/src/cljs/athens/electron/db_menu/db_icon.cljs @@ -6,6 +6,7 @@ (def db-icon-style {:position "relative" + :flex "0 0 auto" :width "1.75em" :height "1.75em" ::stylefy/manual [[:text {:font-size "16px"}]]}) diff --git a/src/cljs/athens/electron/db_menu/db_list_item.cljs b/src/cljs/athens/electron/db_menu/db_list_item.cljs index 8b49b4dd36..d01932938d 100644 --- a/src/cljs/athens/electron/db_menu/db_list_item.cljs +++ b/src/cljs/athens/electron/db_menu/db_list_item.cljs @@ -1,75 +1,88 @@ (ns athens.electron.db-menu.db-list-item (:require + ["@chakra-ui/react" :refer [VStack Flex Text Button IconButton]] ["@material-ui/icons/Clear" :default Clear] ["@material-ui/icons/Link" :default Link] [athens.electron.db-menu.db-icon :refer [db-icon]] [athens.electron.dialogs :as dialogs] - [athens.style :refer [color]] [re-frame.core :refer [dispatch]] - [stylefy.core :as stylefy :refer [use-style]])) + )) -(def db-list-item-style - {:display "flex" - ::stylefy/manual [[:.icon {:flex "0 0 1.75em" - :font-size "inherit" - :margin "0 0.5em 0 0"}] - [:.body {:display "flex" - :text-align "start" - :flex "1 1 100%" - :padding "0.5rem 0.25rem 0.5rem 0.5rem" - :border-radius "0.25rem" - :font-weight "normal" - :background "inherit" - :color "inherit" - :appearance "none" - :border "none" - :line-height "1.1"} - [:.MuiSvgIcon-root {:opacity "50%"}] - ["&:hover" {:filter "brightness(110%)"}]] - [:.is-current] - [:.label {:display "block" - :overflow "hidden" - :flex "1 1 100%"}] - [:span {:display "block"}] - [:.name {:font-weight "600" - :color "inherit"}] - [:.path {:color (color :body-text-color :opacity-med) - :max-width "100%" - :overflow "hidden" - :text-overflow "ellipsis" - :font-size "12px" - :white-space "nowrap"} - [:svg {:display "inline-block" - :font-size "inherit" - :position "relative" - :top "0.2em" - :margin "auto 0.25em auto 0"}]]]}) - - -(defn db-list-item-content +(defn active-db [{:keys [db]}] - [:<> + [:> Flex {:gap 2 + :p 2 + :borderRadius "none" + :whiteSpace "nowrap" + :height "auto" + :align "stretch" + :justifyContent "stretch" + :textAlign "left"} [db-icon {:db db}] - [:div.label - [:span.name (:name db)] - [:span.path - {:title (:id db)} + [:> VStack {:align "stretch" + :flex "1 1 100%" + :overflow "hidden" + :spacing 0 + :textOverflow "ellipsis"} + [:> Text {:textOverflow "ellipsis" + :overflow "hidden" + :fontWeight "bold"} + (:name db)] + [:> Text {:textOverflow "ellipsis" + :size "sm" + :color "feature.secondary" + :overflow "hidden" + :title (:id db)} (when (:is-remote db) [:> Link]) (:id db)]]]) +(defn db-item + [{:keys [db on-click on-remove]}] + [:> Button {:onClick (when on-click on-click) + :whiteSpace "nowrap" + :isDisabled (not on-click) + :display "flex" + :gap 2 + :py 2 + :borderRadius "none" + :height "auto" + :align "stretch" + :justifyContent "stretch" + :textAlign "left"} + [db-icon {:db db}] + [:> VStack {:align "stretch" + :flex "1 1 100%" + :spacing 1 + :overflow "hidden" + :textOverflow "ellipsis"} + [:> Text {:textOverflow "ellipsis" + :fontWeight "bold" + :overflow "hidden"} (:name db)] + [:> Text {:textOverflow "ellipsis" + :size "sm" + :color "feature.secondary" + :overflow "hidden" + :title (:id db)} + (when (:is-remote db) + [:> Link]) + (:id db)]] + (if on-remove + [:> IconButton + {:onClick on-remove} + [:> Clear]])]) + + (defn db-list-item [{:keys [db is-current]}] (let [remove-db-click-handler (fn [e] (dialogs/delete-dialog! db) (.. e stopPropagation))] - [:div (use-style db-list-item-style) - (if is-current - [:div.body.is-current - [db-list-item-content {:db db}]] - [:button.body.button {:onClick #(dispatch [:db-picker/select-db db])} - [db-list-item-content {:db db}] - [:> Clear {:on-click remove-db-click-handler}]])])) + (if is-current + [active-db {:db db}] + [db-item {:db db + :on-click #(dispatch [:db-picker/select-db db]) + :on-remove remove-db-click-handler}]))) diff --git a/src/cljs/athens/electron/db_modal.cljs b/src/cljs/athens/electron/db_modal.cljs index 237470f197..514488275a 100644 --- a/src/cljs/athens/electron/db_modal.cljs +++ b/src/cljs/athens/electron/db_modal.cljs @@ -7,74 +7,21 @@ ["@material-ui/icons/Group" :default Group] ["@material-ui/icons/MergeType" :default MergeType] ["@material-ui/icons/Storage" :default Storage] + ["@chakra-ui/react" :refer [Box Text Modal ModalOverlay Divider VStack Heading ModalContent ModalHeader ModalFooter ModalBody ModalCloseButton ButtonGroup]] ["react-dom" :as react-dom] [athens.electron.dialogs :as dialogs] [athens.electron.utils :as utils] [athens.events :as events] - [athens.style :refer [color]] [athens.subs] [athens.util :refer [js-event->val]] - [athens.views.modal :refer [modal-style]] [athens.views.textinput :as textinput] [clojure.edn :as edn] [datascript.core :as d] [komponentit.modal :as modal] [re-frame.core :refer [subscribe dispatch] :as rf] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]])) + [reagent.core :as r])) -(def modal-contents-style - {:display "flex" - :padding "0 1rem 1.5rem 1rem" - :flex-direction "column" - :align-items "center" - :justify-content "flex-start" - :width "500px" - :height "17em" - ::stylefy/manual [[:p {:max-width "24rem" - :text-align "center"}] - [:button.toggle-button {:font-size "18px" - :align-self "flex-start" - :padding-left "0" - :margin-bottom "1rem"}] - [:code {:word-break "break-all"}] - [:.MuiTabs-indicator {:background-color "var(--link-color)"}]]}) - - -(def picker-style - {:display "grid" - :grid-auto-flow "column" - :grid-auto-columns "1fr" - :border-radius "0.5rem" - :flex "0 0 auto" - :font-size "1em" - :margin "0.25rem 0" - :align-self "stretch" - :overflow "hidden" - :transition "box-shadow 0.2s ease, filter 0.2s ease" - :background (color :background-color) - :padding "1px" - ::stylefy/manual [[:&:hover {}] - [:button {:text-align "center" - :appearance "none" - :border "0" - :border-radius "calc(0.5rem - 1px)" - :padding "0.5rem 0.5rem" - :color "inherit" - :display "flex" - :justify-content "center" - :align-items "center" - :position "relative" - :z-index "0" - :background "inherit"} - [:svg {:margin-inline-end "0.25em" :font-size "1.25em"}] - [:&:hover {:filter "contrast(105%)"}] - [:&:active {:filter "contrast(110%)"}] - [:&.active {:background (color :background-plus-2) - :z-index "5" - :box-shadow [["0 1px 5px" (color :shadow-color)]]}]]]}) - (defn file-cb [e transformed-db roam-db-filename] @@ -106,53 +53,66 @@ transformed-roam-db (r/atom nil) roam-db-filename (r/atom "")] (fn [] - [:div (use-style modal-style) - [modal/modal - - {:title [:div.modal__title - [:> MergeType] - [:h4 "Merge Roam DB"] - [:> Button {:on-click close-modal} - [:> Close]]] + [:> Modal {:isOpen open? + :onClose close-modal + :size "lg"} + [:> ModalOverlay] + [:> ModalContent + [:> ModalHeader + "Merge from Roam"] + [:> ModalCloseButton] + (if (nil? @transformed-roam-db) + (let [inputRef (atom nil)] + [:> ModalBody + [:input {:ref #(reset! inputRef %) + :style {:display "none"} + :type "file" + :accept ".edn" + :on-change #(file-cb % transformed-roam-db roam-db-filename)}] + [:> Heading {:size "md" :as "h2"} "How to merge from Roam"] + [:> Box {:position "relative" + :padding-bottom "56.25%" + :margin "1rem 0 0" + :borderRadius "8px" + :overflow "hidden" + :flex "1 1 100%" + :width "100%"} + [:iframe {:src "https://www.loom.com/embed/787ed48da52c4149b031efb8e17c0939?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true" + :frameBorder "0" + :webkitallowfullscreen "true" + :mozallowfullscreen "true" + :allowFullScreen true + :style {:position "absolute" + :top 0 + :left 0 + :width "100%" + :height "100%"}}]] + [:> ModalFooter + [:> ButtonGroup + [:> Button + {:onClick #(.click @inputRef)} + "Upload database"]]]]) + (let [roam-pages (roam-pages @transformed-roam-db) + shared-pages (events/get-shared-pages @transformed-roam-db)] + [:> ModalBody + [:> Text {:size "md"} (str "Your Roam DB had " (count roam-pages)) " pages. " (count shared-pages) " of these pages were also found in your Athens DB. Press Merge to continue merging your DB."] + [:> Divider {:my 4}] + [:> Heading {:size "md" :as "h3"} "Shared Pages"] + [:> VStack {:as "ol" + :align "stretch" + :maxHeight "400px" + :overflowY "auto"} + (for [x shared-pages] + ^{:key x} + [:li [:> Text (str "[[" x "]]")]])] + [:> ModalFooter + [:> ButtonGroup + [:> Button {:variant "outline" + :onClick (fn [] + (dispatch [:upload/roam-edn @transformed-roam-db @roam-db-filename]) + (close-modal))} - :content [:div (use-style (merge modal-contents-style)) - (if (nil? @transformed-roam-db) - [:<> - [:input {:style {:flex "0 0 auto"} :type "file" :accept ".edn" :on-change #(file-cb % transformed-roam-db roam-db-filename)}] - [:div {:style {:position "relative" - :padding-bottom "56.25%" - :margin "1em 0 0" - :flex "1 1 100%" - :width "100%"}} - [:iframe {:src "https://www.loom.com/embed/787ed48da52c4149b031efb8e17c0939" - :frameBorder "0" - :webkitallowfullscreen "true" - :mozallowfullscreen "true" - :allowFullScreen true - :style {:position "absolute" - :top 0 - :left 0 - :width "100%" - :height "100%"}}]]] - (let [roam-pages (roam-pages @transformed-roam-db) - shared-pages (events/get-shared-pages @transformed-roam-db)] - [:div {:style {:display "flex" :flex-direction "column"}} - [:h6 (str "Your Roam DB had " (count roam-pages)) " pages. " (count shared-pages) " of these pages were also found in your Athens DB. Press Merge to continue merging your DB."] - [:p {:style {:margin "10px 0 0 0"}} "Shared Pages"] - [:ol {:style {:max-height "400px" - :width "100%" - :overflow-y "auto"}} - (for [x shared-pages] - ^{:key x} - [:li (str "[[" x "]]")])] - [:> Button {:style {:align-self "center"} - :is-primary true - :on-click (fn [] - (dispatch [:upload/roam-edn @transformed-roam-db @roam-db-filename]) - (close-modal))} - "Merge"]]))] - - :on-close close-modal}]]))) + "Merge"]]]]))]]))) (defn open-local-comp @@ -164,7 +124,7 @@ "No DB Found At" "Current Location")] [:code {:style {:margin "1rem 0 2rem 0"}} (:id db)] - [:div (use-style {:display "flex" + [:div #_ (use-style {:display "flex" :justify-content "space-between" :align-items "center" :width "80%"}) @@ -177,6 +137,9 @@ "Move"]]]) + + + (defn create-new-local [state] [:<> @@ -263,19 +226,19 @@ (fn [] (.createPortal react-dom - (r/as-element [:div (use-style modal-style) + (r/as-element [:div #_ (use-style modal-style) [modal/modal {:title [:div.modal__title [:> Storage] [:h4 "Database"] (when-not @loading [:> Button {:on-click close-modal} [:> Close]])] - :content [:div (use-style modal-contents-style) + :content [:div #_ (use-style modal-contents-style) ;; TODO: this is hacky, we're just hiding the picker and forcing ;; tab 2 for the web client. Instead we should use Stuart's ;; redesigned DB picker. (when utils/electron? - [:div (use-style picker-style) + [:div #_ (use-style picker-style) [:button {:class (when (= 0 (:tab-value @state)) "active") :on-click (fn [] (swap! state assoc :tab-value 0))} [:> Folder] diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 256f028477..d75254d901 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -3,7 +3,7 @@ ["/components/Spinner/Spinner" :refer [Spinner]] ["/theme/theme" :refer [theme]] ["@chakra-ui/react" :refer [ChakraProvider Grid]] - ["@material-ui/core/Snackbar" :as Snackbar] + ["@material-ui/core/Snackbar" :as Snackbar] ["@react-aria/overlays" :refer [OverlayProvider]] [athens.config] [athens.electron.db-modal :as db-modal] diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index a667a8dc97..dd2cd646c5 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,88 +1,29 @@ (ns athens.views.athena (:require - ["@material-ui/icons/ArrowForward" :default ArrowForward] - ["@material-ui/icons/Close" :default Close] - ["@material-ui/icons/Create" :default Create] - [athens.common.utils :as utils] - [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] - [athens.router :as router] - [athens.style :refer [color DEPTH-SHADOWS OPACITIES ZINDICES]] - [athens.subs] - [athens.util :refer [scroll-into-view]] - [clojure.string :as str] - [garden.selectors :as selectors] - [goog.dom :refer [getElement]] - [goog.events :as events] - [re-frame.core :as rf :refer [subscribe dispatch]] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style use-sub-style]]) + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay IconButton Input]] + ["@material-ui/icons/ArrowForward" :default ArrowForward] + ["@material-ui/icons/Close" :default Close] + ["@material-ui/icons/Create" :default Create] + [athens.common.utils :as utils] + [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] + [athens.router :as router] + [athens.style :refer [color OPACITIES]] + [athens.subs] + [athens.util :refer [scroll-into-view]] + [clojure.string :as str] + [goog.dom :refer [getElement]] + [goog.events :as events] + [re-frame.core :as rf :refer [subscribe dispatch]] + [reagent.core :as r] + [stylefy.core :as stylefy :refer [use-style use-sub-style]]) (:import - (goog.events - KeyCodes))) + (goog.events + KeyCodes))) ;; Styles -(def container-style - {:width "49rem" - :max-width "calc(100vw - 1rem)" - :border-radius "0.25rem" - :box-shadow [[(:64 DEPTH-SHADOWS) ", 0 0 0 1px " (color :body-text-color :opacity-lower)]] - :display "flex" - :flex-direction "column" - :background (color :background-plus-1) - :position "fixed" - :overflow "hidden" - :max-height "60vh" - :z-index (:zindex-modal ZINDICES) - :top "40%" - :left "50%" - :transform "translate(-50%, -50%)" - ;; Styling for the states of the custom search-cancel button, which depend on the input contents - ::stylefy/manual [[(selectors/+ :input :button) {:opacity 0}] - ;; Using ':valid' here as a proxy for "has contents", i.e. "button should appear" - [(selectors/+ :input:valid :button) {:opacity 1}]]}) - - -(def athena-input-style - {:width "100%" - :border 0 - :font-size "2.375rem" - :font-weight "300" - :line-height "1.3" - :letter-spacing "-0.03em" - :border-radius "0.25rem 0.25rem 0 0" - :background (color :background-plus-2) - :color (color :body-text-color) - :caret-color (color :link-color) - :padding "1.5rem 4rem 1.5rem 1.5rem" - :cursor "text" - ::stylefy/mode {:focus {:outline "none"} - "::placeholder" {:color (color :body-text-color :opacity-low)} - "::-webkit-search-cancel-button" {:display "none"}}}) ; We replace the button elsewhere - - - -(def search-cancel-button-style - {:background "none" - :color "inherit" - :position "absolute" - :transition "opacity 0.1s ease, background 0.1s ease" - :cursor "pointer" - :border 0 - :right "2rem" - :place-items "center" - :place-content "center" - :height "2.5rem" - :width "2.5rem" - :border-radius "1000px" - :display "flex" - :transform "translate(0%, -50%)" - :top "50%" - ::stylefy/manual [[:&:hover :&:focus {:background (color :background-plus-1)}]]}) - - (def results-list-style {:background (color :background-color) :overflow-y "auto" @@ -152,11 +93,11 @@ [query txt] (let [query-pattern (re-case-insensitive (str "((?<=" query ")|(?=" query "))"))] (doall - (map-indexed (fn [i part] - (if (re-find query-pattern part) - [:span.result-highlight (use-style result-highlight-style {:key i}) part] - part)) - (str/split txt query-pattern))))) + (map-indexed (fn [i part] + (if (re-find query-pattern part) + [:span.result-highlight (use-style result-highlight-style {:key i}) part] + part)) + (str/split txt query-pattern))))) (defn create-search-handler @@ -169,10 +110,10 @@ (reset! state {:index 0 :query query :results (vec - (concat - [(search-exact-node-title query)] - (search-in-node-title query 20 true) - (search-in-block-content query)))})))) + (concat + [(search-exact-node-title query)] + (search-in-node-title query 20 true) + (search-in-block-content query)))})))) (defn key-down-handler @@ -182,9 +123,6 @@ {:keys [index query results]} @state item (get results index)] (cond - (= key KeyCodes.ESC) - (dispatch [:athena/toggle]) - (= KeyCodes.ENTER key) (cond ;; if page doesn't exist, create and open (and (zero? index) (nil? item)) @@ -268,120 +206,145 @@ (when no-query? [:div (use-style results-list-style) (doall - (for [[i x] (map-indexed list recent-items)] - (when x - (let [{:keys [query :node/title :block/string]} x] - [:div (use-style result-style {:key i - :on-click (fn [e] - (rf/dispatch [:reporting/navigation {:source :athena - :target :page - :pane :main-pane}]) - (router/navigate-page title e))}) - [:h4.title (use-sub-style result-style :title) (highlight-match query title)] - (when string - [:span.preview (use-sub-style result-style :preview) (highlight-match query string)]) - [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class ArrowForward)]]]))))])])) + (for [[i x] (map-indexed list recent-items)] + (when x + (let [{:keys [query :node/title :block/string]} x] + [:div (use-style result-style {:key i + :on-click (fn [e] + (rf/dispatch [:reporting/navigation {:source :athena + :target :page + :pane :main-pane}]) + (router/navigate-page title e))}) + [:h4.title (use-sub-style result-style :title) (highlight-match query title)] + (when string + [:span.preview (use-sub-style result-style :preview) (highlight-match query string)]) + [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class ArrowForward)]]]))))])])) (defn search-results-el [{:keys [results query index]}] [:div (use-style results-list-style) (doall - (for [[i x] (map-indexed list results) - :let [block-uid (:block/uid x) - parent (:block/parent x) - title (or (:node/title parent) (:node/title x)) - uid (or (:block/uid parent) (:block/uid x)) - string (:block/string x)]] - (if (nil? x) - ^{:key i} - [:div (use-style result-style - {:on-click (fn [e] - (let [block-uid (utils/gen-block-uid) - shift? (.-shiftKey e)] - (dispatch [:athena/toggle]) - (dispatch [:page/new {:title query - :block-uid block-uid}]) - (dispatch [:reporting/page.create {:source :athena - :count 1}]) - (dispatch [:reporting/navigation {:source :athena - :target (if parent - (str "block/" block-uid) - (str "page/" title)) - :pane (if shift? - :right-pane - :main-pane)}]))) - :class (when (= i index) "selected")}) - - [:div (use-style result-body-style) - [:h4.title (use-sub-style result-style :title) - [:b "Create Page: "] - query]] - [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class Create)]]] - - [:div (use-style result-style - {:key i - :on-click (fn [e] - (let [selected-page {:node/title title - :block/uid uid - :block/string string - :query query} - shift? (.-shiftKey e)] - (dispatch [:athena/toggle]) - (dispatch [:athena/update-recent-items selected-page]) - (dispatch [:reporting/navigation {:source :athena - :target (if parent - :block - :page) - :pane (if shift? - :right-pane - :main-pane)}]) - (if parent - (router/navigate-uid block-uid) - (router/navigate-page title e)))) - - :class (when (= i index) "selected")}) - [:div (use-style result-body-style) - - [:h4.title (use-sub-style result-style :title) (highlight-match query title)] - (when string - [:span.preview (use-sub-style result-style :preview) (highlight-match query string)])] - [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class ArrowForward)]]])))]) + (for [[i x] (map-indexed list results) + :let [block-uid (:block/uid x) + parent (:block/parent x) + title (or (:node/title parent) (:node/title x)) + uid (or (:block/uid parent) (:block/uid x)) + string (:block/string x)]] + (if (nil? x) + ^{:key i} + [:div (use-style result-style + {:on-click (fn [e] + (let [block-uid (utils/gen-block-uid) + shift? (.-shiftKey e)] + (dispatch [:athena/toggle]) + (dispatch [:page/new {:title query + :block-uid block-uid}]) + (dispatch [:reporting/page.create {:source :athena + :count 1}]) + (dispatch [:reporting/navigation {:source :athena + :target (if parent + (str "block/" block-uid) + (str "page/" title)) + :pane (if shift? + :right-pane + :main-pane)}]))) + :class (when (= i index) "selected")}) + + [:div (use-style result-body-style) + [:h4.title (use-sub-style result-style :title) + [:b "Create Page: "] + query]] + [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class Create)]]] + + [:div (use-style result-style + {:key i + :on-click (fn [e] + (let [selected-page {:node/title title + :block/uid uid + :block/string string + :query query} + shift? (.-shiftKey e)] + (dispatch [:athena/toggle]) + (dispatch [:athena/update-recent-items selected-page]) + (dispatch [:reporting/navigation {:source :athena + :target (if parent + :block + :page) + :pane (if shift? + :right-pane + :main-pane)}]) + (if parent + (router/navigate-uid block-uid) + (router/navigate-page title e)))) + + :class (when (= i index) "selected")}) + [:div (use-style result-body-style) + + [:h4.title (use-sub-style result-style :title) (highlight-match query title)] + (when string + [:span.preview (use-sub-style result-style :preview) (highlight-match query string)])] + [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class ArrowForward)]]])))]) (defn athena-component [] - (let [ref (atom nil) - athena-open? (rf/subscribe [:athena/open]) - handle-click-outside (fn [e] - (when (and @athena-open? - (not (.. @ref (contains (.. e -target))))) - (dispatch [:athena/toggle]))) + (let [athena-open? (rf/subscribe [:athena/open]) state (r/atom {:index 0 :query nil :results []}) search-handler (create-search-handler state)] - (r/create-class - {:display-name "athena" - ;; NOTE: this mouse listener stuff can go away with mechanism combining overlay and react portals - :component-did-mount (fn [_this] (events/listen js/document "mousedown" handle-click-outside)) - :component-will-unmount (fn [_this] (events/unlisten js/document "mousedown" handle-click-outside)) - :reagent-render - (fn [] - (when @athena-open? - [:div.athena (use-style container-style - {:ref #(reset! ref %)}) - [:header {:style {:position "relative"}} - [:input (use-style athena-input-style - {:type "search" - :id "athena-input" - :auto-focus true - :required true - :placeholder "Find or Create Page" - :on-change (fn [e] (search-handler (.. e -target -value))) - :on-key-down (fn [e] (key-down-handler e state))})] - [:button (use-style search-cancel-button-style - {:on-click #(set! (.-value (getElement "athena-input")) %)}) - [:> Close]]] - [results-el state] - [search-results-el @state]]))}))) + (fn [] + (when @athena-open? + [:> Modal {:maxHeight "60vh" + :display "flex" + :_focus {:outline "none"} + :closeOnEsc true + :isOpen @athena-open? + :onClose #(dispatch [:athena/toggle])} + [:> ModalOverlay {:_focus {:outline "none"}}] + [:> ModalContent + {:width "49rem" + :_focus {:outline "none"} + :bg "background.upper" + :maxWidth "calc(100vw - 4rem)"} + [:> Input + {:type "search" + :width "100%" + :border 0 + :fontSize "2.375rem" + :fontWeight "300" + :lineHeight "1.3" + :letterSpacing "-0.03em" + :borderRadius "0.25rem 0.25rem 0 0" + :color "inherit" + :height "auto" + :padding "1.5rem 4rem 1.5rem 1.5rem" + :cursor "text" + :id "athena-input" + :auto-focus true + :required true + :_focus {:outline "none"} + :sx {"::-webkit-search-cancel-button" {:display "none"}} + :placeholder "Find or Create Page" + :onChange (fn [e] (search-handler (.. e -target -value))) + :onKeyDown (fn [e] (key-down-handler e state))}] + [:> IconButton {:background "none" + :color "inherit" + :position "absolute" + :transition "opacity 0.1s ease, background 0.1s ease" + :cursor "pointer" + :border 0 + :right "2rem" + :placeItems "center" + :placeContent "center" + :height "2.5rem" + :width "2.5rem" + :borderRadius "1000px" + :display "flex" + :transform "translate(0%, -50%)" + :top "50%" + :onClick #(set! (.-value (getElement "athena-input")) nil)} + [:> Close]]] + [results-el state] + [search-results-el @state]])))) diff --git a/src/cljs/athens/views/blocks/content.cljs b/src/cljs/athens/views/blocks/content.cljs index 3d3a6977fb..7e4e1c5437 100644 --- a/src/cljs/athens/views/blocks/content.cljs +++ b/src/cljs/athens/views/blocks/content.cljs @@ -1,22 +1,23 @@ (ns athens.views.blocks.content (:require - [athens.config :as config] - [athens.db :as db] - [athens.events.selection :as select-events] - [athens.parse-renderer :refer [parse-and-render]] - [athens.style :as style] - [athens.subs.selection :as select-subs] - [athens.util :as util] - [athens.views.blocks.internal-representation :as internal-representation] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [clojure.edn :as edn] - [clojure.set :as set] - [clojure.string :as str] - [garden.selectors :as selectors] - [goog.events :as goog-events] - [komponentit.autosize :as autosize] - [re-frame.core :as rf] - [stylefy.core :as stylefy]) + ["@chakra-ui/react" :refer [Box]] + [athens.config :as config] + [athens.db :as db] + [athens.events.selection :as select-events] + [athens.parse-renderer :refer [parse-and-render]] + [athens.style :as style] + [athens.subs.selection :as select-subs] + [athens.util :as util] + [athens.views.blocks.internal-representation :as internal-representation] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [clojure.edn :as edn] + [clojure.set :as set] + [clojure.string :as str] + [garden.selectors :as selectors] + [goog.events :as goog-events] + [komponentit.autosize :as autosize] + [re-frame.core :as rf] + [stylefy.core :as stylefy]) (:import (goog.events EventType))) @@ -24,8 +25,41 @@ ;; Styles + +(def block-inner-content-style {"textarea" {:display "block" + :lineHeight 0 + :appeareance "none" + :cursor "text" + :resize "none" + :transform "translate3d(0,0,0)" + :color "inherit" + :outline "none" + :overflow "hidden" + :padding "0" + :background "background.basement" + :grid-area "main" + :min-height "100%" + :caret-color "link" + :margin "0" + :font-size "inherit" + :border-radius "0.25rem" + :border "0" + :opacity "0" + :font-family "inherit"} + "&:hover:not(.is-editing) textarea" {:lineHeight "2"} + "&.is-editing" {:zIndex 3 + :lineHeight "inherit" + :opacity 1} + "span.text-run" {:pointerEvents "none" + "& > a" {:position "relative" + :zIndex 2 + :pointerEvents "all"}} + "span" {:gridArea "main"}}) + + (def block-content-style {:display "grid" + :color "foreground.primary" :grid-template-areas "'main'" :align-items "stretch" :justify-content "stretch" @@ -34,29 +68,13 @@ :z-index 2 :flex-grow "1" :word-break "break-word" - ::stylefy/manual [[:textarea {:display "block" + ::stylefy/manual [#_ [:textarea {:display "block" :line-height 0 :-webkit-appearance "none" :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :outline "none" - :overflow "hidden" - :padding "0" - :background (style/color :background-minus-1) - :grid-area "main" - :min-height "100%" - :caret-color (style/color :link-color) - :margin "0" - :font-size "inherit" - :border-radius "0.25rem" - :box-shadow (str "-0.25rem 0 0 0" (style/color :background-minus-1)) - :border "0" - :opacity "0" - :font-family "inherit"}] - [:&:hover [:textarea [(selectors/& (selectors/not :.is-editing)) {:line-height 2}]]] - [:.is-editing {:z-index 3 + :resize "none"}] + #_ [:&:hover [:textarea [(selectors/& (selectors/not :.is-editing)) {:line-height 2}]]] + #_ [:.is-editing {:z-index 3 :line-height "inherit" :opacity "1"}] [:span.text-run @@ -107,35 +125,6 @@ ;; Images [:img {:border-radius "0.25rem" :max-width "calc(100% - 0.25rem)"}] - ;; Checkboxes - ;; TODO: Refactor these complicated styles into clip paths or SVGs - ;; or something nicer than this - [:input [:& (selectors/attr= :type :checkbox) {:appearance "none" - :border-radius "0.25rem" - :cursor "pointer" - :color (style/color :link-color) - :margin-inline-end "0.25rem" - :position "relative" - :top "0.13em" - :width "1rem" - :height "1rem" - :transition "color 0.05s ease, transform 0.05s ease, box-shadow 0.05s ease" - :transform "scale(1)" - :box-shadow "inset 0 0 0 1px"} - [:&:after {:content "''" - :position "absolute" - :top "45%" - :left "20%" - :width "30%" - :height "50%" - :border-width "0 2px 2px 0" - :border-style "solid" - :opacity 0 - :transform "rotate(45deg) translate(-40%, -50%)"}] - [:&:checked {:background (style/color :link-color)} - [:&:after {:opacity 1 - :color (style/color :background-color)}]] - [:&:active {:transform "scale(0.9)"}]]] [:h1 :h2 :h3 :h4 :h5 :h6 {:margin "0" :color (style/color :body-text-color :opacity-higher) @@ -399,9 +388,21 @@ 2 "1.7em" 3 "1.3em" "1em")] - [:div {:class ["block-content"] - :style {:font-size font-size} - :on-click (fn [e] (.. e stopPropagation) (rf/dispatch [:editing/uid uid]))} + [:> Box {:class ["block-content"] + :display "grid" + :background "background.floor" + :color "foreground.primary" + :gridTemplateAreas "'main'" + :alignItems "stretch" + :justifyContent "stretch" + :position "relative" + :overflow "visible" + :zIndex 2 + :flexGrow 1 + :wordBreak "break-word" + :fontSize font-size + :sx block-inner-content-style + :on-click (fn [e] (.. e stopPropagation) (rf/dispatch [:editing/uid uid]))} ;; NOTE: komponentit forces reflow, likely a performance bottle neck ;; When block is in editing mode or the editing DOM elements are rendered (when (or (:show-editable-dom @state) @editing?) diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index 9c8fca98a4..95db613549 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -1,32 +1,32 @@ (ns athens.views.blocks.core (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Block/components/Toggle" :refer [Toggle]] - ["/components/Button/Button" :refer [Button]] - [athens.common.logging :as log] - [athens.db :as db] - [athens.electron.images :as images] - [athens.electron.utils :as electron.utils] - [athens.events.selection :as select-events] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.self-hosted.presence.views :as presence] - [athens.style :as style] - [athens.subs.selection :as select-subs] - [athens.util :as util :refer [mouse-offset vertical-center specter-recursive-path]] - [athens.views.blocks.autocomplete-search :as autocomplete-search] - [athens.views.blocks.autocomplete-slash :as autocomplete-slash] - [athens.views.blocks.bullet :refer [bullet-drag-start bullet-drag-end]] - [athens.views.blocks.content :as content] - [athens.views.blocks.context-menu :as context-menu] - [athens.views.blocks.drop-area-indicator :as drop-area-indicator] - [athens.views.breadcrumbs :as breadcrumbs] - [com.rpl.specter :as s] - [goog.functions :as gfns] - [re-frame.core :as rf] - [reagent.core :as r] - [stylefy.core :as stylefy])) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Block/components/Toggle" :refer [Toggle]] + ["/components/Button/Button" :refer [Button]] + [athens.common.logging :as log] + [athens.db :as db] + [athens.electron.images :as images] + [athens.electron.utils :as electron.utils] + [athens.events.selection :as select-events] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.self-hosted.presence.views :as presence] + [athens.style :as style] + [athens.subs.selection :as select-subs] + [athens.util :as util :refer [mouse-offset vertical-center specter-recursive-path]] + [athens.views.blocks.autocomplete-search :as autocomplete-search] + [athens.views.blocks.autocomplete-slash :as autocomplete-slash] + [athens.views.blocks.bullet :refer [bullet-drag-start bullet-drag-end]] + [athens.views.blocks.content :as content] + [athens.views.blocks.context-menu :as context-menu] + [athens.views.blocks.drop-area-indicator :as drop-area-indicator] + [athens.views.breadcrumbs :as breadcrumbs] + [com.rpl.specter :as s] + [goog.functions :as gfns] + [re-frame.core :as rf] + [reagent.core :as r] + [stylefy.core :as stylefy])) ;; Styles diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index c5a522bb04..f885afcb15 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -1,186 +1,130 @@ (ns athens.views.left-sidebar (:require - [athens.reactive :as reactive] - [athens.router :as router] - [athens.style :refer [color OPACITIES]] - [athens.util :as util] - [re-frame.core :as rf] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style use-sub-style]])) - - -;; Styles - - -(def left-sidebar-style - {:width 0 - :grid-area "left-sidebar" - :height "100%" - :display "flex" - :flex-direction "column" - :overflow-x "hidden" - :overflow-y "auto" - ::stylefy/supports {"overflow-y: overlay" - {:overflow-y "overlay"}} - :transition "width 0.5s ease" - ::stylefy/sub-styles {:top-line {:margin-bottom "2.5rem" - :display "flex" - :flex "0 0 auto" - :justify-content "space-between"} - :footer {:flex "0 0 auto" - :margin "auto 2rem 0" - :align-self "stretch" - :display "grid" - :grid-auto-flow "column" - :grid-template-columns "1fr auto auto" - :grid-gap "0.25rem"} - :small-icon {:font-size "16px"} - :large-icon {:font-size "22px"}} - ::stylefy/manual [[:&.is-open {:width "18rem"}] - [:&.is-closed {:width "0"}]]}) - - -(def left-sidebar-content-style - {:width "18rem" - :height "100%" - :display "flex" - :flex-direction "column" - :padding "7.5rem 0 1rem" - :transition "opacity 0.5s ease" - :opacity 0 - ::stylefy/manual [[:&.is-open {:opacity 1}] - [:&.is-closed {:opacity 0}]]}) - - -(def shortcuts-list-style - {:flex "1 1 100%" - :display "flex" - :list-style "none" - :flex-direction "column" - :padding "0 2rem" - :margin "0 0 2rem" - :overflow-y "auto" - ::stylefy/supports {"overflow-y: overlay" - {:overflow-y "overlay"}} - ::stylefy/sub-styles {:heading {:flex "0 0 auto" - :opacity (:opacity-med OPACITIES) - :line-height "1" - :margin "0 0 0.25rem" - :font-size "inherit"}}}) - - -(def shortcut-style - {:color (color :link-color) - :cursor "pointer" - :display "flex" - :flex "0 0 auto" - :padding "0.25rem 0" - :transition "opacity 0.05s ease" - ::stylefy/mode [[:hover {:opacity (:opacity-high OPACITIES)}]]}) - - -(def notional-logotype-style - {:font-family "IBM Plex Serif" - :font-size "18px" - :opacity (:opacity-med OPACITIES) - :letter-spacing "-0.05em" - :font-weight "bold" - :text-decoration "none" - :justify-self "flex-start" - :color (color :header-text-color) - :transition "opacity 0.05s ease" - ::stylefy/mode [[:hover {:opacity (:opacity-high OPACITIES)}]]}) - - -(def version-style - {:color "inherit" - :text-decoration "none" - :opacity 0.3 - :font-size "clamp(12px, 100%, 14px)" - ::stylefy/mode [[:hover {:opacity (:opacity-high OPACITIES)}]]}) + ["@chakra-ui/react" :refer [VStack HStack Heading Button Link Flex Box]] + ["framer-motion" :refer [AnimatePresence motion]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.util :as util] + [re-frame.core :as rf] + [reagent.core :as r])) ;; Components +(def expanded-sidebar-width "18rem") (defn shortcut-component [_] (let [drag (r/atom nil)] (fn [[order title]] - [:li - [:a (use-style (merge shortcut-style - (case @drag - :above {:border-top [["1px" "solid" (color :link-color)]]} - :below {:border-bottom [["1px" "solid" (color :link-color)]]} - {})) - {:on-click (fn [e] - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :left-sidebar - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page title e))) - :draggable true - :on-drag-over (fn [e] - (.. e preventDefault) - (let [offset (util/mouse-offset e) - middle-y (util/vertical-center (.. e -target)) - ;; find closest li because sometimes event.target is anchor tag - ;; if nextSibling is null, then target is last li and therefore end of list - closest-li (.. e -target (closest "li")) - next-sibling (.. closest-li -nextElementSibling) - last-child? (nil? next-sibling)] - (cond - (> middle-y (:y offset)) (reset! drag :above) - (and (< middle-y (:y offset)) last-child?) (reset! drag :below)))) - :on-drag-start (fn [e] - (set! (.. e -dataTransfer -dropEffect) "move") - (.. e -dataTransfer (setData "text/plain" order))) - :on-drag-end (fn [_]) - :on-drag-leave (fn [_] (reset! drag nil)) - :on-drop (fn [e] - (let [source-order (js/parseInt (.. e -dataTransfer (getData "text/plain")))] - (prn source-order order) - (cond - (= source-order order) nil - (and (= source-order - (dec order)) - (= @drag :above)) nil - (= @drag :below) (rf/dispatch [:left-sidebar/drop source-order order :after]) - :else (rf/dispatch [:left-sidebar/drop source-order order :before]))) - (reset! drag nil))}) + [:> Flex {:as "li" + :align "stretch" + :border "1px solid transparent" + :borderTopColor (when (:above @drag) "brand") + :borderBottomColor (when (:below @drag) "brand")} + [:> Button {:variant "link" + :borderWidth "1px" + :p "1rem" + :py "0.5rem" + :mx "1rem" + :flex "1" + :border "none" + :justifyContent "flex-start" + :bg "background.floor" + :boxShadow "0 0 0 0.25rem transparent" + :_focus {:outline "none"} + :_hover {:bg "background.upper"} + :onClick (fn [e] + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :left-sidebar + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page title e))) + :draggable true + :on-drag-over (fn [e] + (.. e preventDefault) + (let [offset (util/mouse-offset e) + middle-y (util/vertical-center (.. e -target)) + ;; find closest li because sometimes event.target is anchor tag + ;; if nextSibling is null, then target is last li and therefore end of list + closest-li (.. e -target (closest "li")) + next-sibling (.. closest-li -nextElementSibling) + last-child? (nil? next-sibling)] + (cond + (> middle-y (:y offset)) (reset! drag :above) + (and (< middle-y (:y offset)) last-child?) (reset! drag :below)))) + :on-drag-start (fn [e] + (set! (.. e -dataTransfer -dropEffect) "move") + (.. e -dataTransfer (setData "text/plain" order))) + :on-drag-end (fn [_]) + :on-drag-leave (fn [_] (reset! drag nil)) + :on-drop (fn [e] + (let [source-order (js/parseInt (.. e -dataTransfer (getData "text/plain")))] + (prn source-order order) + (cond + (= source-order order) nil + (and (= source-order + (dec order)) + (= @drag :above)) nil + (= @drag :below) (rf/dispatch [:left-sidebar/drop source-order order :after]) + :else (rf/dispatch [:left-sidebar/drop source-order order :before]))) + (reset! drag nil))} title]]))) - (defn left-sidebar [] (let [open? (rf/subscribe [:left-sidebar/open]) shortcuts (reactive/get-reactive-shortcuts)] (fn [] - [:div (use-style left-sidebar-style - {:class (if @open? - "is-open" - "is-closed")}) - [:div (use-style left-sidebar-content-style - {:class (if @open? - "is-open" - "is-closed")}) + [:> AnimatePresence {:initial false} + (when @open? + [:> (.-div motion) + {:style {:display "flex" + :flex-direction "column" + :height "100%" + :paddingTop "7rem" + :paddingBottom "2rem" + :alignItems "stretch" + :gridArea "left-sidebar" + :overflow "hidden"} + :initial {:width 0 + :opacity 0} + :animate {:width expanded-sidebar-width + :opacity 1} + :exit {:width 0 + :opacity 0}} ;; SHORTCUTS - [:ol (use-style shortcuts-list-style) - [:h2 (use-sub-style shortcuts-list-style :heading) - "Shortcuts"] - (doall - (for [sh shortcuts] - ^{:key (str "left-sidebar-" (second sh))} - [shortcut-component sh]))] + [:> VStack {:as "ol" + :align "stretch" + :width expanded-sidebar-width + :py "1rem" + :spacing "0.25rem" + :overflowY "overlay" + :sx {:listStyle "none"}} + [:> Heading {:as "h2" + :px "2rem" + :pb "1rem" + :size "md" + :color "feature.secondary"} + "Shortcuts"] + (doall + (for [sh shortcuts] + ^{:key (str "left-sidebar-" (second sh))} + [shortcut-component sh]))] ;; LOGO + BOTTOM BUTTONS - [:footer (use-sub-style left-sidebar-style :footer) - [:a (use-style notional-logotype-style {:href "https://github.com/athensresearch/athens/issues/new/choose" :target "_blank"}) "Athens"] - [:h5 (use-style {:align-self "center"}) - [:a (use-style version-style {:href "https://github.com/athensresearch/athens/blob/master/CHANGELOG.md" - :target "_blank"}) - (athens.util/athens-version)]]]]]))) - + [:> HStack {:as "footer" + :width expanded-sidebar-width + :px "2rem" + :mt "auto"} + [:> Link {:fontWeight "bold" + :href "https://github.com/athensresearch/athens/issues/new/choose" + :target "_blank"} + "Athens"] + [:> Link {:color "foreground.secondary" + :href "https://github.com/athensresearch/athens/blob/master/CHANGELOG.md" + :target "_blank"} + (athens.util/athens-version)]]])]))) diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 5cbea23ae0..e22c439257 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,5 +1,7 @@ (ns athens.views.right-sidebar (:require + ["@chakra-ui/react" :refer [VStack HStack Heading Link Flex Box]] + ["framer-motion" :refer [AnimatePresence motion]] ["/components/Button/Button" :refer [Button]] ["@material-ui/icons/BubbleChart" :default BubbleChart] ["@material-ui/icons/ChevronRight" :default ChevronRight] @@ -19,56 +21,6 @@ ;; Styles - -(def sidebar-style - {:justify-self "stretch" - :overflow "hidden" - :width "0" - :grid-area "secondary-content" - :display "flex" - :justify-content "space-between" - :padding-top "2.75rem" - :transition-property "width, border, background" - :transition-duration "0.35s" - :transition-timing-function "ease-out" - :box-shadow [["0 -100px 0 " (color :background-minus-1) ", inset 1px 0 " (color :background-minus-1)]] - ::stylefy/manual [[:svg {:color (color :body-text-color :opacity-high)}] - [:&.is-closed {:width "0"}] - [:&.is-open {:width "32vw"}] - ["::-webkit-scrollbar" {:background (color :background-minus-1) - :width "0.5rem" - :height "0.5rem"}] - ["::-webkit-scrollbar-corner" {:background (color :background-minus-1)}] - ["::-webkit-scrollbar-thumb" {:background (color :background-plus-1) - :border-radius "0.5rem"}]]}) - - -(def sidebar-content-style - {:display "flex" - :flex "1 1 32vw" - :flex-direction "column" - :margin-left "0" - :overflow-y "auto" - ::stylefy/supports {"overflow-y: overlay" - {:overflow-y "overlay"}} - ::stylefy/manual [[:&.is-closed {:margin-left "-32vw" - :opacity 0}] - [:&.is-open {:opacity 1}]]}) - - -(def sidebar-section-heading-style - {:font-size "14px" - :display "flex" - :flex-direction "row" - :align-items "center" - :min-height "2.75rem" - :padding "0.5rem 1rem 0.25rem 1.5rem" - ::stylefy/manual [[:h1 {:font-size "inherit" - :margin "0 auto 0 0" - :line-height "1" - :color (color :body-text-color :opacity-med)}]]}) - - (def sidebar-item-style {:display "flex" :flex "0 0 auto" @@ -151,26 +103,6 @@ [:&.is-open [:h2 {:font-weight "500"}]]]}) -(def panel-drag-handle-style - {:cursor "col-resize" - :height "100%" - :position "absolute" - :top 0 - :width "1px" - :z-index (:zindex-fixed ZINDICES) - :background-color (color :border-color) - ::stylefy/manual [[:&:after {:content "''" - :position "absolute" - :background (color :link-color) - :transition "opacity 0.2s ease" - :top 0 - :bottom 0 - :left 0 - :right "-4px" - :opacity 0}] - [:&:hover:after {:opacity 0.5}] - [:&.is-dragging:after {:opacity 1}]]}) - (def empty-message-style {:align-self "center" @@ -218,53 +150,81 @@ (swap! state assoc :dragging false) (dispatch [:right-sidebar/set-width (:width @state)])))] (r/create-class - {:display-name "right-sidebar" - :component-did-mount (fn [] - (js/document.addEventListener "mousemove" move-handler) - (js/document.addEventListener "mouseup" mouse-up-handler)) - :component-will-unmount (fn [] - (js/document.removeEventListener "mousemove" move-handler) - (js/document.removeEventListener "mouseup" mouse-up-handler)) - :reagent-render (fn [open? items _] - [:div (merge (use-style sidebar-style - {:class ["right-sidebar" (if open? "is-open" "is-closed")]}) - {:style (cond-> {} - (:dragging @state) (assoc :transition-duration "0s") - open? (assoc :width (str (:width @state) "vw")))}) - [:div (use-style panel-drag-handle-style - {:on-mouse-down #(swap! state assoc :dragging true) - :class (when (:dragging @state) "is-dragging")})] - [:div (use-style sidebar-content-style {:class [(if open? "is-open" "is-closed") "right-sidebar-content"]}) - ;; [:header (use-style sidebar-section-heading-style)] ;; Waiting on additional sidebar contents - ;; [:h1 "Pages and Blocks"]] - ;; [:> Button [:> FilterList]] - (if (empty? items) - [empty-message] - (doall - (for [[uid {:keys [open node/title block/string is-graph?]}] items] - ^{:key uid} - [:article (use-style sidebar-item-style) - [:header (use-style sidebar-item-heading-style {:class (when open "is-open")}) - [:> Button (use-style sidebar-item-toggle-style - {:on-click #(dispatch [:right-sidebar/toggle-item uid]) - :class (when open "is-open")}) - [:> ChevronRight]] - [:h2 - (cond - is-graph? [:<> [:> BubbleChart] [parse-renderer/parse-and-render title uid]] - title [:<> [:> Description] [parse-renderer/parse-and-render title uid]] - :else [:<> [:> FiberManualRecord] [parse-renderer/parse-and-render string uid]])] - [:div {:class "controls"} + {:display-name "right-sidebar" + :component-did-mount (fn [] + (js/document.addEventListener "mousemove" move-handler) + (js/document.addEventListener "mouseup" mouse-up-handler)) + :component-will-unmount (fn [] + (js/document.removeEventListener "mousemove" move-handler) + (js/document.removeEventListener "mouseup" mouse-up-handler)) + :reagent-render (fn [open? items _] + [:> AnimatePresence {:initial false} + (when open? + [:> (.-div motion) + {:style {:display "flex" + :flex-direction "column" + :height "100%" + :paddingTop "2.75rem" + :alignItems "stretch" + :justifySelf "stretch" + :justifyContent "space-between" + :position "relative" + :gridArea "secondary-content" + :overflow "hidden"} + :initial {:width 0 + :opacity 0} + :animate {:width (str (:width @state) "vw") + :opacity 1} + :exit {:width 0 + :opacity 0}} + [:> Box {:role "separator" + :aria-orientation "vertical" + :cursor "col-resize" + :position "absolute" + :top 0 + :height "100%" + :width "1px" + :zIndex 1 + :bg "separator.border" + :_hover {:bg "link"} + :_active {:bg "link"} + :_after {:content "''" + :position "absolute" + :inset "-4px"} + :on-mouse-down #(swap! state assoc :dragging true) + :class (when (:dragging @state) "is-dragging")}] + [:> Flex {:flexDirection "column" + :bg "background.upper" + :height "100%" + :width (str (:width @state) "vw") + :overflowY "overlay"} + (if (empty? items) + [empty-message] + (doall + (for [[uid {:keys [open node/title block/string is-graph?]}] items] + ^{:key uid} + [:article (use-style sidebar-item-style) + [:header (use-style sidebar-item-heading-style {:class (when open "is-open")}) + [:> Button (use-style sidebar-item-toggle-style + {:on-click #(dispatch [:right-sidebar/toggle-item uid]) + :class (when open "is-open")}) + [:> ChevronRight]] + [:h2 + (cond + is-graph? [:<> [:> BubbleChart] [parse-renderer/parse-and-render title uid]] + title [:<> [:> Description] [parse-renderer/parse-and-render title uid]] + :else [:<> [:> FiberManualRecord] [parse-renderer/parse-and-render string uid]])] + [:div {:class "controls"} ;; [:> Button [:> DragIndicator]] ;; [:hr] - [:> Button {:on-click #(dispatch [:right-sidebar/close-item uid])} - [:> Close]]]] - (when open - [:div (use-style sidebar-item-container-style) - (cond - is-graph? [graph/page uid] - title [node-page/page [:block/uid uid]] - :else [block-page/page [:block/uid uid]])])])))]])}))) + [:> Button {:on-click #(dispatch [:right-sidebar/close-item uid])} + [:> Close]]]] + (when open + [:div (use-style sidebar-item-container-style) + (cond + is-graph? [graph/page uid] + title [node-page/page [:block/uid uid]] + :else [block-page/page [:block/uid uid]])])])))]])])}))) (defn right-sidebar diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index f708956718..35e318be20 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -1,80 +1,74 @@ import React from 'react'; -import styled from 'styled-components'; -import { BubbleChart, ChevronLeft, ChevronRight, FileCopy, Help, Menu as MenuIcon, MergeType, Search, Settings, Storage, Today, ToggleOff, ToggleOn, VerticalSplit } from '@material-ui/icons'; +import { + BubbleChart, + ChevronLeft, + ChevronRight, + FileCopy, + Help, + Menu as MenuIcon, + MergeType, + Search, + Settings, + Storage, + Today, + ToggleOff, + ToggleOn, + VerticalSplit +} from '@material-ui/icons'; -import { Button } from '@/Button'; -import { WindowButtons } from './components/WindowButtons'; - -const AppToolbarWrapper = styled.header` - background: var(--color-background); - grid-area: app-header; - justify-content: flex-start; - background-clip: padding-box; - background: var(--background-plus-1); - color: var(--body-text-color---opacity-high); - border-bottom: 1px solid transparent; - align-items: center; - display: grid; - height: 48px; - padding-left: 10px; - grid-template-columns: auto 1fr auto; - transition: border-color 1s ease; - z-index: var(--zindex-sticky); - grid-auto-flow: column; - -webkit-app-region: drag; - - .is-fullscreen & { - height: 44px; - } - - svg { - font-size: 20px; - } - - &:hover { - transition: border-color 0.15s ease; - border-bottom-color: var(--body-text-color---opacity-lower); - } - - button { - justify-self: flex-start; - -webkit-app-region: no-drag; - } - - .os-windows & { - background: var(--background-minus-1); - padding-left: 10px; - } +import { + Tooltip, + Flex, + Button, + HStack, + Divider, + IconButton, + ButtonGroup +} from '@chakra-ui/react'; - .os-mac & { - background: var(--background-color---opacity-high); - color: var(--body-text-color---opacity-med); - padding-left: 88px; - padding-right: 22px; - height: 52px; - border-top-left-radius: 12px; - border-top-right-radius: 12px; - backdrop-filter: blur(20px); - position: absolute; - top: 0; - left: 0; - right: 0; +import { WindowButtons } from './components/WindowButtons'; - .is-fullscreen & { - padding-left: 22px; - } - } -`; +const AppToolbarWrapper = ({ children }) => + {children} +; export interface AppToolbarProps extends React.HTMLAttributes, DatabaseMenuProps, PresenceDetailsProps { /** @@ -187,77 +181,78 @@ export const AppToolbar = (props: AppToolbarProps): React.ReactElement => { ...rest } = props; - return ( - - {databaseMenu} - - {isElectron && ( - <> - - - - ) - } - - - - Find or create a page - - - {presenceDetails} - - - - - - - - {isElectron && (os === 'windows' || os === 'linux') && ( - )} - ); + return ( + + + + {databaseMenu} + + + + + + {isElectron && ( + <> + + + + + + + + ) + } + + + + + + + {presenceDetails} + + + + {isThemeDark ? : } + + + + + + + + + + {isElectron && (os === 'windows' || os === 'linux') && ( + )} + ); }; - -AppToolbar.Separator = styled.hr` - border: 0; - margin-inline: 0.125rem; - margin-block: 0; - block-size: auto; -`; - -AppToolbar.MainControls = styled.div` - display: grid; - grid-auto-flow: column; - grid-gap: 0.25rem; - align-items: center; -`; - -AppToolbar.SecondaryControls = styled(AppToolbar.MainControls)` - justify-self: flex-end; - margin-left: auto; - - button { - color: inherit; - background: inherit; - } -`; diff --git a/src/js/components/Icons/icons.ts b/src/js/components/Icons/icons.ts new file mode 100644 index 0000000000..52064b3180 --- /dev/null +++ b/src/js/components/Icons/icons.ts @@ -0,0 +1,2 @@ +import createIcon from '@chakra-ui/react'; + diff --git a/src/js/theme/index.js b/src/js/theme/index.js new file mode 100644 index 0000000000..76aed6f668 --- /dev/null +++ b/src/js/theme/index.js @@ -0,0 +1,2 @@ +import { theme } from './theme' +export { theme }; \ No newline at end of file diff --git a/src/js/theme/spacing.js b/src/js/theme/spacing.js new file mode 100644 index 0000000000..5c76f2bcd0 --- /dev/null +++ b/src/js/theme/spacing.js @@ -0,0 +1,19 @@ + +const scale = [ 0.25, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 20, 24, 28 ]; + +const cssSize = (n) => `${n / 2}rem`; + +const makeSpace = (initial) => { + const space = initial; + + scale.forEach(scale => { + space[ `${scale}` ] = cssSize(scale); + }) + return space; +} + +export const spacing = { + space: makeSpace({ + px: '1px' + }) +} diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js new file mode 100644 index 0000000000..50fe729cb1 --- /dev/null +++ b/src/js/theme/theme.js @@ -0,0 +1,152 @@ +import { extendTheme } from '@chakra-ui/react' +import { spacing } from './spacing' + + +const colors = { + // Old theme values + linkLight: "#0071DB", + highlightLight: "#F9A132", + textHighlightLight: "#ffdb8a", + warningLight: "#D20000", + + backgroundPlus2Light: "#fff", + backgroundPlus1Light: "#fbfbfb", + backgroundColorLight: "#F6F6F6", + backgroundMinus1Light: "#FAF8F6", + backgroundMinus2Light: "#EFEDEB", + + backgroundMinu2Dark: "#151515", + backgroundMinus1Dark: "#111", + backgroundColorDark: "#1A1A1A", + backgroundPlus1Dark: "#222", + backgroundPlus2Dark: "#333", + + confirmationLight: "#009E23", + headerLight: "#322F38", + bodyLight: "#433F38", + borderLight: "hsla(32, 81%, 10: 0.08)", + errorLight: "#fd5243", + shadowLight: "#000", + + linkDark: "#0071DB", + highlightDark: "#FBBE63", + textHighlightDark: "#FBBE63", + warningDark: "#DE3C21", + confirmationDark: "#189E36", + headerDark: "#BABABA", + bodyDark: "#AAA", + borderDark: "hsla(32, 81%, 90%, 0.08)", + errorDark: "#fd5243", + shadowDark: "#000" +} + +const semanticTokens = { + colors: { + transparent: 'transparent', + brand: { + default: 'linkLight', + _dark: 'linkDark' + }, + "separator.border": { + default: 'borderLight', + _dark: 'borderDark' + }, + "separator.divider": { + default: 'borderLight', + _dark: 'borderDark' + }, + "background.floor": { + default: 'backgroundColorLight', + _dark: 'backgroundColorDark' + }, + "background.basement": { + default: 'backgroundMinus1Light', + _dark: 'backgroundMinus1Dark' + }, + "background.upper": { + default: 'backgroundPlus1Light', + _dark: 'backgroundPlus1Dark' + }, + "background.attic": { + default: 'backgroundPlus2Light', + _dark: 'backgroundPlus2Dark' + }, + "foreground.primary": { + default: 'bodyLight', + _dark: 'bodyDark' + }, + "foreground.secondary": { + default: 'headerLight', + _dark: 'headerDark' + }, + error: { + default: 'errorLight', + _dark: 'errorDark' + }, + warning: { + default: 'warningLight', + _dark: 'warningDark' + }, + confirmation: { + default: 'confirmationLight', + _dark: 'confirmationDark' + }, + headerText: { + default: 'headerLight', + _dark: 'headerDark' + }, + textHighlight: { + default: 'textHighlightLight', + _dark: 'textHighlightDark' + }, + highlight: { + default: 'highlightLight', + _dark: 'highlightDark' + }, + link: { + default: 'linkLight', + _dark: 'linkDark' + } + } +} + +const components = { + Button: { + baseStyle: { + color: 'feature.primary', + } + }, + Tooltip: { + baseStyle: { + bg: 'feature.primary', + px: "8px", + py: "2px", + borderRadius: "sm", + fontWeight: "medium", + fontSize: "sm", + boxShadow: "md", + maxW: "320px", + zIndex: "tooltip", + } + } +} + +const config = { + initialColorMode: 'dark', + useSystemColorMode: true, +} + +const styles = { + global: { + 'html, body': { + bg: 'background.floor', + color: 'feature.foreground', + } + } +} + +const sizes = { + ...spacing +} + +export const theme = extendTheme({ config, colors, semanticTokens, spacing, sizes, components, styles }); diff --git a/yarn.lock b/yarn.lock index bc5fe94aca..7c4d0a3a71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -487,6 +487,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz#afe37a45f39fce44a3d50a7958129ea5b1a5c074" integrity sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ== +"@babel/helper-plugin-utils@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + "@babel/helper-remap-async-to-generator@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6" @@ -973,6 +978,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-syntax-jsx@^7.12.13": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" + integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-jsx@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201" @@ -1660,6 +1672,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.13", "@babel/runtime@^7.13.10": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.7": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" @@ -1774,6 +1793,556 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@chakra-ui/accordion@1.4.9": + version "1.4.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/accordion/-/accordion-1.4.9.tgz#0c5dd7d55c94f583b135583697f212506085e572" + integrity sha512-ZrfrLwAu6p9B41sZ+iEWjfPW/mn2TdUDXv165qr1O355619e2Btjb01x3IYoN4GlE2iF7GOVjC5uYGNyLpBlZg== + dependencies: + "@chakra-ui/descendant" "2.1.3" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/transition" "1.4.7" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/alert@1.3.7": + version "1.3.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/alert/-/alert-1.3.7.tgz#f36020ffc3b2c26be67025c56bccbf0639a81a67" + integrity sha512-fFpJYBpHOIK/BX4BVl/xafYiDBUW+Bq/gUYDOo4iAiO4vHgxo74oa+yOwSRNlNjAgIX7pi2ridsYQALKyWyxxQ== + dependencies: + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/anatomy@1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/anatomy/-/anatomy-1.3.0.tgz#38a40dd6f2bb076fe8bebe8fb8e4769ea005e03d" + integrity sha512-vj/lcHkCuq/dtbl69DkNsftZTnrGEegB90ODs1B6rxw8iVMdDSYkthPPFAkqzNs4ppv1y2IBjELuVzpeta1OHA== + dependencies: + "@chakra-ui/theme-tools" "^1.3.6" + +"@chakra-ui/avatar@1.3.9": + version "1.3.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/avatar/-/avatar-1.3.9.tgz#6e4eae5901428e90d2aa9ef8938a775959794d9f" + integrity sha512-QhtVuFRXhV7X5iMCHI1lXOA0U2hJnpKC9uIEB80EkBuNYJDEz/y8ViOQPRivMVU//wymwLcbvjDCZd1urMjVYQ== + dependencies: + "@chakra-ui/image" "1.1.8" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/breadcrumb@1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/breadcrumb/-/breadcrumb-1.3.6.tgz#fe22e162c37add5830bd1292172bb11d859c6f35" + integrity sha512-iXxienBO6RUnJEcDvyDWyRt+mzPyl7/b6N8i0vrjGKGLpgtayJFvIdo33tFcvx6TCy7V9hiE3HTtZnNomWdR6A== + dependencies: + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/button@1.5.8": + version "1.5.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/button/-/button-1.5.8.tgz#57945201a971fab38d1a700e62f6d840f6d9ad5c" + integrity sha512-harZywey/6OclxIB5p/Ge/coeGKZWoqmu7JjXlbwTUd3U9IQiOVo/zekY1JscCSz2oZoVBCvoKZVt3on5dPwmA== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/spinner" "1.2.6" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/checkbox@1.6.8": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/checkbox/-/checkbox-1.6.8.tgz#b1dd32db34f4b2fda7ebe522f2eb580690f5f434" + integrity sha512-CYmJbMA9BXb6ArKmXIAuQ22aQ97HgtslbJlqRKsV/FmZuk1DXF1dcVXzqeInhe5HacQ8z/+SmSqL9Q3fjswKag== + dependencies: + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + "@chakra-ui/visually-hidden" "1.1.6" + +"@chakra-ui/clickable@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/clickable/-/clickable-1.2.6.tgz#7f3deef71580acf47c2395cac2c1734f43418a3f" + integrity sha512-89SsrQwwwAadcl/bN8nZqqaaVhVNFdBXqQnxVy1t07DL5ezubmNb5SgFh9LDznkm9YYPQhaGr3W6HFro7iAHMg== + dependencies: + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/close-button@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/close-button/-/close-button-1.2.7.tgz#6f3073618ae777d7e36a80fb17bc00aaa790e7a5" + integrity sha512-cYTxfgrIlPU4IZm1sehZXxx/TNQBk9c3LBPvTpywEM8GVRGINh4YLq8WiMaPtO+TDNBnKoWS/jS4IHnR+abADw== + dependencies: + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/color-mode@1.4.6": + version "1.4.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/color-mode/-/color-mode-1.4.6.tgz#6532086b0030934a5b18ba2b7117b8077b989064" + integrity sha512-gCO8Z/jv68jXop94MUQNzigl7JXICAgZQUUqLaKhdy1h2zatVDIPFfjwwjnsgM97G0BxQaNBOC87+PD2UYjzHw== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-env" "1.1.6" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/control-box@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/control-box/-/control-box-1.1.6.tgz#15a40a2cab525799988ae53948b61eed81a7f177" + integrity sha512-EUcq5f854puG6ZA6wAWl4107OPl8+bj4MMHJCa48BB0qec0U8HCEtxQGnFwJmaYLalIAjMfHuY3OwO2A3Hi9hA== + dependencies: + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/counter@1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/counter/-/counter-1.2.8.tgz#18ea2139db00ba9400eb31d58b95eb62471a93e2" + integrity sha512-lVuK+ycKxEE0G4Jkl8A6GWdXUFAih89KA1IkkhQG6NwqdGzbgouTInwBLg1Sm5uwgQ5QqSr9S42QyDoleUyF0g== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/css-reset@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/css-reset/-/css-reset-1.1.3.tgz#da65507ea1d69ed309bc34619881e23b5004ec7d" + integrity sha512-AgfrE7bRTJvNi/4zIfacI/kBHmHmHEIeQtHwCvk/0qM9V2gK1VM3ctYlnibf7BTh17F/UszweOGRb1lHSPfWjw== + +"@chakra-ui/descendant@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/descendant/-/descendant-2.1.3.tgz#6198ccce207b3d8697dedefff6886f18ca13b5ce" + integrity sha512-aNYNv99gEPENCdw2N5y3FvL5wgBVcLiOzJ2TxSwb4EVYszbgBZ8Ry1pf7lkoSfysdxD0scgy2cVyxO8TsYTU4g== + dependencies: + "@chakra-ui/react-utils" "^1.2.3" + +"@chakra-ui/editable@1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/editable/-/editable-1.4.0.tgz#9c6f277d6ae2e1883fd72b1ec492df3659d62390" + integrity sha512-QH5ZMCK/U3pQINtSPiqxxA5XCdiXKBfAI1+siiuSqKtmCriltcArEU4groQn/bm7EY6UJIr/MV3azSDeeBIsaQ== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/focus-lock@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/focus-lock/-/focus-lock-1.2.6.tgz#ecdc9688651c55c67f9059720f0885ea7c02b979" + integrity sha512-ZJNE1oNdUM1aGWuCJ+bxFa/d3EwxzfMWzTKzSvKDK50GWoUQQ10xFTT9nY/yFpkcwhBvx1KavxKf44mIhIbSog== + dependencies: + "@chakra-ui/utils" "1.10.4" + react-focus-lock "2.5.2" + +"@chakra-ui/form-control@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/form-control/-/form-control-1.5.9.tgz#ab74441162aaaa09e455ad7fc5921ac3af5ea493" + integrity sha512-JuUB9dHXFqTYm+Z+cOULk56AcrX9y3eaied0j/KGdPwtIjS2kkjulq7A8sJJdsle4M6XleMinjW+1KO2PMExQg== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/hooks@1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@chakra-ui/hooks/-/hooks-1.8.5.tgz#db6dc4a7992c7d48cfec5cd796f6a1eb19143eb7" + integrity sha512-/UrBfUG7NLxuU/09gy2qQfEH+H5SPBUaUiFtokRlq887D/32JQ3XksZdF78RKMCM/0bbZuIjqUkuN/wO9kAbSw== + dependencies: + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + compute-scroll-into-view "1.0.14" + copy-to-clipboard "3.3.1" + +"@chakra-ui/icon@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-2.0.5.tgz#d57f53e6a2c7ae1bae7292a1778fd466c02e2e29" + integrity sha512-ZrqRvCCIxGr4qFd/r1pmtd9tobRmv8KAxV7ygFoc/t4vOSKTcVIjhE12gsI3FzgvXM15ZFVwsxa1zodwgo5neQ== + dependencies: + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/image@1.1.8": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/image/-/image-1.1.8.tgz#f77bb1f1333b8a6d3b056c4f076f4a55f5e44f2f" + integrity sha512-ffO5lyTfGXxaFr9Bdkrb+GahjXsqeph8R1jXYFYwLjos+/sZZJmHJz/cjyoKjKPd6J7puKVZ6Cxz+Ej6PJlQcA== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/input@1.4.4": + version "1.4.4" + resolved "https://registry.yarnpkg.com/@chakra-ui/input/-/input-1.4.4.tgz#da350861dc89c4d6d5219f39a177ba0f9d549bdb" + integrity sha512-A1TYz8lOdSVuMnWRnR7Y+cddnnr5d2o1Vvd8Im09WW2j09xy06xD/EaFy8dI51Ab0ACldglVs66qx5dO7WoV0w== + dependencies: + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/layout@1.7.7": + version "1.7.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/layout/-/layout-1.7.7.tgz#646fd689f9d54ce5cb4f71ec68dbf314b30699ab" + integrity sha512-HuZ/Zv9xWzLip263tX2Vt0oaqwaS6Srw78Sdl3DiGSifN8x+ooEAxmeDAIaU2PO21YX+f6s+9A738NAtSM2R+Q== + dependencies: + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/live-region@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/live-region/-/live-region-1.1.6.tgz#135461a19ae2d479eefb012376ffa0f500b83b16" + integrity sha512-9gPQHXf7oW0jXyT5R/JzyDMfJ3hF70TqhN8bRH4fMyfNr2Se+SjztMBqCrv5FS5rPjcCeua+e0eArpoB3ROuWQ== + dependencies: + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/media-query@2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@chakra-ui/media-query/-/media-query-2.0.4.tgz#25e8074a19613d4ccce880a1f92c8e733708b079" + integrity sha512-kn6g/L0IFFUHz2v4yiCsBnhg9jUeA7525Z+AWl+BPtvryi7i9J+AJ27y/QAge7vUGy4dwDeFyxOZTs2oZ9/BsA== + dependencies: + "@chakra-ui/react-env" "1.1.6" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/menu@1.8.9": + version "1.8.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/menu/-/menu-1.8.9.tgz#689ecaa35df7c97cad3a4649c533f9493b374fc5" + integrity sha512-rvQQU56nQoaz+IZXyamKaAU/87IiGIDrX9wEONHth7QDT/93whnFNYPtUMHMzILz0oliysBey4dlmtRzk5vUpQ== + dependencies: + "@chakra-ui/clickable" "1.2.6" + "@chakra-ui/descendant" "2.1.3" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/popper" "2.4.3" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/transition" "1.4.7" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/modal@1.10.10": + version "1.10.10" + resolved "https://registry.yarnpkg.com/@chakra-ui/modal/-/modal-1.10.10.tgz#dfdf932f333d83c4125fb2416ce811808dab1c28" + integrity sha512-/OLnZhhGXQEaCqtrCCf2nu27mVxT/3Kd+NBNMKGZ4X70Dm6HD3x1Zrsto2hVo8l3kLEPRpkfpXhKu61doMc8zw== + dependencies: + "@chakra-ui/close-button" "1.2.7" + "@chakra-ui/focus-lock" "1.2.6" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/portal" "1.3.8" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/transition" "1.4.7" + "@chakra-ui/utils" "1.10.4" + aria-hidden "^1.1.1" + react-remove-scroll "2.4.1" + +"@chakra-ui/number-input@1.4.5": + version "1.4.5" + resolved "https://registry.yarnpkg.com/@chakra-ui/number-input/-/number-input-1.4.5.tgz#4ffa67857266639f2cb90fd01f8f1cf56d8d7112" + integrity sha512-jxOvJUEuXZXQrOgMGZ+rPNjSrIoV7MSb7CPt3C1jVuiumr/GgNu54awmrky3Zj4ikj68rREEUXAGKBgm9oU3nQ== + dependencies: + "@chakra-ui/counter" "1.2.8" + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/pin-input@1.7.8": + version "1.7.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/pin-input/-/pin-input-1.7.8.tgz#326b2b5686e7fe0a47237595426fb5158d337d3d" + integrity sha512-P4uJBVKDxTetQhj+s0L7TbUTTqbcHwkLpo4bGUEdQpHMfGFlJgGu0wFT5Z8O0fw+vGNfguFfkqkVRRgK8FkHlA== + dependencies: + "@chakra-ui/descendant" "2.1.3" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/popover@1.11.7": + version "1.11.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/popover/-/popover-1.11.7.tgz#e9682a789a52c03187feb74220241ff81ce1cbde" + integrity sha512-TjMZlpBomIuGuQgGQi2rTSVFwFbc9HdJSU3anyFyDQb4ZnunyqaIEMoqFdj/dK8tDdWIatozKjX6AzSimmSvLg== + dependencies: + "@chakra-ui/close-button" "1.2.7" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/popper" "2.4.3" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/popper@2.4.3": + version "2.4.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/popper/-/popper-2.4.3.tgz#fcdc917d13a56b9d44868c78a009e4dd692697a2" + integrity sha512-TGzFnYt3mtIVkIejtYIAu4Ka9DaYLzMR4NgcqI6EtaTvgK7Xep+6RTiY/Nq+ZT3l/eaNUwqHRFoNrDUg1XYasA== + dependencies: + "@chakra-ui/react-utils" "1.2.3" + "@popperjs/core" "^2.9.3" + +"@chakra-ui/portal@1.3.8": + version "1.3.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/portal/-/portal-1.3.8.tgz#128045d236de26c0872f2b78600ecba0ab960285" + integrity sha512-rpSu/RdtlKfOBzw11qHs91IwUTffUfppBz33PfOFNZpDGmO0+6pWkz40I16eSgYtQigZRQG1spz6Ul7tsh+1ag== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/progress@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/progress/-/progress-1.2.6.tgz#4a3a40e826c8c72160d3c8ff411e86244e280ebc" + integrity sha512-thaHRIYTVktgV78vJMNwzfCX+ickhSpn2bun6FtGVUphFx4tjV+ggz+IGohm6AH2hapskoR1mQU2iNZb6BK0hQ== + dependencies: + "@chakra-ui/theme-tools" "1.3.6" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/provider@1.7.12": + version "1.7.12" + resolved "https://registry.yarnpkg.com/@chakra-ui/provider/-/provider-1.7.12.tgz#da7571adea7a0dc2899083b7e2774477858a2d69" + integrity sha512-SSq4z4nMjCbqdGrRkbxzR4o96uRah1HnSFui3lM2263zJN7fyezqiseRboID+i7eIUCBWHMLdsabARAD8t1tDQ== + dependencies: + "@chakra-ui/css-reset" "1.1.3" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/portal" "1.3.8" + "@chakra-ui/react-env" "1.1.6" + "@chakra-ui/system" "1.11.2" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/radio@1.4.10": + version "1.4.10" + resolved "https://registry.yarnpkg.com/@chakra-ui/radio/-/radio-1.4.10.tgz#a554af383f768ec372e31c5cdd7d1ffe89dcd9b3" + integrity sha512-TgqBgfezypC4do1Vj4iBp4kptXVWdnhASJ97VFuau2QQPT6zKl3Ke2di+XLhH3CZNCDHpvU/KxQNJ6bfj5GMGg== + dependencies: + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + "@chakra-ui/visually-hidden" "1.1.6" + +"@chakra-ui/react-env@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-env/-/react-env-1.1.6.tgz#9915b02fd1f8ca62ccf578eaec793f1c4dea78b0" + integrity sha512-L90LNvCfe04FTkN9OPok/o2e60zLJNBH8Im/5dUHvqy7dXLXok8ZDad5vEL46XmGbhe7O8fbxhG6FmAYdcCHrQ== + dependencies: + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/react-utils@1.2.3", "@chakra-ui/react-utils@^1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@chakra-ui/react-utils/-/react-utils-1.2.3.tgz#3356c9299bc8faada8fac6c5886ca65ec95bb5be" + integrity sha512-r8pUwCVVB7UPhb0AiRa9ZzSp4xkMz64yIeJ4O4aGy4WMw7TRH4j4QkbkE1YC9tQitrXrliOlvx4WWJR4VyiGpw== + dependencies: + "@chakra-ui/utils" "^1.10.4" + +"@chakra-ui/react@^1.8.6": + version "1.8.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/react/-/react-1.8.6.tgz#e37b9df24fa2ec7d91d2baaa00fd617e3a1bd80c" + integrity sha512-FEh/KG0uPeNOMQuIlyPfGjHvGB7LN1AAhkdFefqzNt0zNy8Giv4p1PKY7wdCh5QEFor++A83L1wIWvTGQVJ2vQ== + dependencies: + "@chakra-ui/accordion" "1.4.9" + "@chakra-ui/alert" "1.3.7" + "@chakra-ui/avatar" "1.3.9" + "@chakra-ui/breadcrumb" "1.3.6" + "@chakra-ui/button" "1.5.8" + "@chakra-ui/checkbox" "1.6.8" + "@chakra-ui/close-button" "1.2.7" + "@chakra-ui/control-box" "1.1.6" + "@chakra-ui/counter" "1.2.8" + "@chakra-ui/css-reset" "1.1.3" + "@chakra-ui/editable" "1.4.0" + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/image" "1.1.8" + "@chakra-ui/input" "1.4.4" + "@chakra-ui/layout" "1.7.7" + "@chakra-ui/live-region" "1.1.6" + "@chakra-ui/media-query" "2.0.4" + "@chakra-ui/menu" "1.8.9" + "@chakra-ui/modal" "1.10.10" + "@chakra-ui/number-input" "1.4.5" + "@chakra-ui/pin-input" "1.7.8" + "@chakra-ui/popover" "1.11.7" + "@chakra-ui/popper" "2.4.3" + "@chakra-ui/portal" "1.3.8" + "@chakra-ui/progress" "1.2.6" + "@chakra-ui/provider" "1.7.12" + "@chakra-ui/radio" "1.4.10" + "@chakra-ui/react-env" "1.1.6" + "@chakra-ui/select" "1.2.9" + "@chakra-ui/skeleton" "1.2.12" + "@chakra-ui/slider" "1.5.9" + "@chakra-ui/spinner" "1.2.6" + "@chakra-ui/stat" "1.2.7" + "@chakra-ui/switch" "1.3.8" + "@chakra-ui/system" "1.11.2" + "@chakra-ui/table" "1.3.6" + "@chakra-ui/tabs" "1.6.8" + "@chakra-ui/tag" "1.2.7" + "@chakra-ui/textarea" "1.2.9" + "@chakra-ui/theme" "1.14.0" + "@chakra-ui/toast" "1.5.7" + "@chakra-ui/tooltip" "1.4.9" + "@chakra-ui/transition" "1.4.7" + "@chakra-ui/utils" "1.10.4" + "@chakra-ui/visually-hidden" "1.1.6" + +"@chakra-ui/select@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/select/-/select-1.2.9.tgz#5e4943d26f4ddcb0dce359c4fb82e08ab503a389" + integrity sha512-f8cRy3whXFYviuKGfugPnvXTGarPVt2ux5pffipmliYOhfaJ8O2OtdmNJ/od4WaeGStUH13x12GsEqVw2LBKOg== + dependencies: + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/skeleton@1.2.12": + version "1.2.12" + resolved "https://registry.yarnpkg.com/@chakra-ui/skeleton/-/skeleton-1.2.12.tgz#870857f6511a380a6539f9e71d9e565611bc5ebc" + integrity sha512-buHqfKw24+EQXFGHlSRq2obHxZgz0FUKSFNMlQS3tMoFwBkLRO/jAQfjj9KKR5b0m2qu1qLBmwFHJLih1+bnzg== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/media-query" "2.0.4" + "@chakra-ui/system" "1.11.2" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/slider@1.5.9": + version "1.5.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/slider/-/slider-1.5.9.tgz#c4fea8487f26c35bf78ae0489e62e0b8542ec147" + integrity sha512-m9n/BpnD/hEDS9q3T17ezgTFWDdvCocPzxQXzLLDN2Z2xOgwyLTQVLk4iB1yROvLCUl7Ig9C4+a4/7fivm+IHw== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/spinner@1.2.6": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/spinner/-/spinner-1.2.6.tgz#d85fb3d763a69d40570b591507c5087dba38e6c4" + integrity sha512-GoUCccN120fGRVgUtfuwcEjeoaxffB+XsgpxX7jhWloXf8b6lkqm68bsxX4Ybb2vGN1fANI98/45JmrnddZO/A== + dependencies: + "@chakra-ui/utils" "1.10.4" + "@chakra-ui/visually-hidden" "1.1.6" + +"@chakra-ui/stat@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/stat/-/stat-1.2.7.tgz#e173171d80f9e756966604e620987bbd7590d291" + integrity sha512-m76jumFW1N+mCG4ytrUz9Mh09nZtS4OQcADEvOslfdI5StwwuzasTA1tueaelPzdhBioMwFUWL05Fr1fXbPJ/Q== + dependencies: + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/utils" "1.10.4" + "@chakra-ui/visually-hidden" "1.1.6" + +"@chakra-ui/styled-system@1.18.1": + version "1.18.1" + resolved "https://registry.yarnpkg.com/@chakra-ui/styled-system/-/styled-system-1.18.1.tgz#a09638b2add9795dc442e47f322240a34ef5e543" + integrity sha512-uhWMNAfkk1DFAQ4nKu+t23WBQ1/XSJq8Y3sBZJQpvopfwOcarbVvEiM5voSUWPA7pkpD/BprGM7zjIRockUcmw== + dependencies: + "@chakra-ui/utils" "1.10.4" + csstype "^3.0.9" + +"@chakra-ui/switch@1.3.8": + version "1.3.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/switch/-/switch-1.3.8.tgz#1d86794bc28f3b88d62ed202e6bd678108583d13" + integrity sha512-xcsq4G9YUNRSp0F+XBDjeGZFlJeEdGJptuixk6PZjqRJYUyH+k2bk1bJ2Bv2bjvmkDCojI42MkvWTLHrOqp41A== + dependencies: + "@chakra-ui/checkbox" "1.6.8" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/system@1.11.2": + version "1.11.2" + resolved "https://registry.yarnpkg.com/@chakra-ui/system/-/system-1.11.2.tgz#7c8aae2758260d3a238e8c0410c17af1fe1cd5af" + integrity sha512-s4HGYVo86XuSav5PLfuVT26Y+l3ca/nQVF6QxS6YCNiUxdBlahlzsZz3yMz3MKp11voljnY8vj4z4dvOd2sjUQ== + dependencies: + "@chakra-ui/color-mode" "1.4.6" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/styled-system" "1.18.1" + "@chakra-ui/utils" "1.10.4" + react-fast-compare "3.2.0" + +"@chakra-ui/table@1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/table/-/table-1.3.6.tgz#e271676dc03cd4c684e4041df2cf394d86a28510" + integrity sha512-7agZAgAeDFKviqStvixqnLAH54+setzhx67EztioZTr5Xu+6hQ4rotfJbu8L4i587pcbNg98kCEXEkidjw0XRQ== + dependencies: + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/tabs@1.6.8": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@chakra-ui/tabs/-/tabs-1.6.8.tgz#7ef8cf667e9fb1280b673e4fb0e2dc4415f05af9" + integrity sha512-f1kM9VhAXqKzTAVRoPRIINNiUgvBcadP9m5GtjAgE4DzCrQKnTDImjIkFhXlMvWEmB5ynXZcCGlsgIZ2A9Hs9g== + dependencies: + "@chakra-ui/clickable" "1.2.6" + "@chakra-ui/descendant" "2.1.3" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/tag@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/tag/-/tag-1.2.7.tgz#5861a92e83e63825f6fe563921d2704e921b585f" + integrity sha512-RKrKOol4i/CnpFfo3T9LMm1abaqM+5Bs0soQLbo1iJBbBACY09sWXrQYvveQ2GYzU/OrAUloHqqmKjyVGOlNtg== + dependencies: + "@chakra-ui/icon" "2.0.5" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/textarea@1.2.9": + version "1.2.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/textarea/-/textarea-1.2.9.tgz#5d73b6be994b3488eecf037a54e7136682d3b5b0" + integrity sha512-HHeUdBA2JrH/S4PopcpOjRmBWKv4wpxQ+Q4mD03UBznyFARZe3XFJOnxhAPdpB/ZadbdgiyXK27TR0uzaqlONw== + dependencies: + "@chakra-ui/form-control" "1.5.9" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/theme-tools@1.3.6", "@chakra-ui/theme-tools@^1.3.6": + version "1.3.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme-tools/-/theme-tools-1.3.6.tgz#2e5b5c192efd685c158e940a5cedcb0eb51f8602" + integrity sha512-Wxz3XSJhPCU6OwCHEyH44EegEDQHwvlsx+KDkUDGevOjUU88YuNqOVkKtgTpgMLNQcsrYZ93oPWZUJqqCVNRew== + dependencies: + "@chakra-ui/utils" "1.10.4" + "@ctrl/tinycolor" "^3.4.0" + +"@chakra-ui/theme@1.14.0": + version "1.14.0" + resolved "https://registry.yarnpkg.com/@chakra-ui/theme/-/theme-1.14.0.tgz#0aa1d602db8256e09b2e7f172108dea4a79748b1" + integrity sha512-zKy/8JSbiCP0QeBsLzdub7aBnfX2k0qp5vD+RA+mxPEiykEvPGg+TwryxRM5KMZK1Zdgg95aH+9mwiGe9tJt3A== + dependencies: + "@chakra-ui/anatomy" "1.3.0" + "@chakra-ui/theme-tools" "1.3.6" + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/toast@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/toast/-/toast-1.5.7.tgz#d0ffccd13f925967353fb65a590f2ac8f88332db" + integrity sha512-vM88vX2jTfSwOXWqcj9o9pm+msojJS0cG0Pe/wSuYP+D274SdE8oB2OFqJyijsQ7WQq/P6BIlgquzUcS4smu9A== + dependencies: + "@chakra-ui/alert" "1.3.7" + "@chakra-ui/close-button" "1.2.7" + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/theme" "1.14.0" + "@chakra-ui/transition" "1.4.7" + "@chakra-ui/utils" "1.10.4" + "@reach/alert" "0.13.2" + +"@chakra-ui/tooltip@1.4.9": + version "1.4.9" + resolved "https://registry.yarnpkg.com/@chakra-ui/tooltip/-/tooltip-1.4.9.tgz#0fa875ee50fd9a4f9b3c93d5d841a222b739afd7" + integrity sha512-W1GVMFWkLLBfiFsOddhr7oWr2rTKqSy2xxMkR5MuomNaqORW4tvjN/wNSLMUuUHVxtWM+iRQkslE5r6k5/1HAw== + dependencies: + "@chakra-ui/hooks" "1.8.5" + "@chakra-ui/popper" "2.4.3" + "@chakra-ui/portal" "1.3.8" + "@chakra-ui/react-utils" "1.2.3" + "@chakra-ui/utils" "1.10.4" + "@chakra-ui/visually-hidden" "1.1.6" + +"@chakra-ui/transition@1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@chakra-ui/transition/-/transition-1.4.7.tgz#c8f3248d54fbf7e661e620acf3a3292832c88805" + integrity sha512-2sbMoKB/enp6Qbte3DD6zwBHyO4YAUSgvSr3wn7DAy4hz9kRZHPuUf/N+i9QZ0whL2koXLgdZvV6RNtSTShq4g== + dependencies: + "@chakra-ui/utils" "1.10.4" + +"@chakra-ui/utils@1.10.4", "@chakra-ui/utils@^1.10.4": + version "1.10.4" + resolved "https://registry.yarnpkg.com/@chakra-ui/utils/-/utils-1.10.4.tgz#40a32d4efd8684b2e7432a40b285796383eacfd3" + integrity sha512-AM91VQQxw8F4F1WDA28mqKY6NFIOuzc2Ekkna88imy2OiqqmYH0xkq8J16L2qj4cLiLozpYqba3C79pWioy6FA== + dependencies: + "@types/lodash.mergewith" "4.6.6" + css-box-model "1.2.1" + framesync "5.3.0" + lodash.mergewith "4.6.2" + +"@chakra-ui/visually-hidden@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@chakra-ui/visually-hidden/-/visually-hidden-1.1.6.tgz#7a546a5aebe4779c8f18d65b1f0e56249720f28d" + integrity sha512-Xzy5bA0UA+IyMgwJizQYSEdgz8cC/tHdmFB3CniXzmpKTSK8mJddeEBl+cGbXHBzxEUhH7xF1eaS41O+0ezWEQ== + dependencies: + "@chakra-ui/utils" "1.10.4" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -1782,6 +2351,11 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@ctrl/tinycolor@^3.4.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz#c3c5ae543c897caa9c2a68630bed355be5f9990f" + integrity sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ== + "@develar/schema-utils@~2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz#3ece22c5838402419a6e0425f85742b961d9b6c6" @@ -1822,6 +2396,24 @@ dir-compare "^2.4.0" fs-extra "^9.0.1" +"@emotion/babel-plugin@^11.7.1": + version "11.7.2" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" + integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + "@emotion/cache@^10.0.27": version "10.0.29" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" @@ -1832,6 +2424,17 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" +"@emotion/cache@^11.7.1": + version "11.7.1" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" + integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "4.0.13" + "@emotion/core@^10.1.1": version "10.1.1" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" @@ -1858,18 +2461,43 @@ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== -"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.6", "@emotion/is-prop-valid@^0.8.8": +"@emotion/is-prop-valid@0.8.8", "@emotion/is-prop-valid@^0.8.2", "@emotion/is-prop-valid@^0.8.6", "@emotion/is-prop-valid@^0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA== dependencies: "@emotion/memoize" "0.7.4" +"@emotion/is-prop-valid@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.1.2.tgz#34ad6e98e871aa6f7a20469b602911b8b11b3a95" + integrity sha512-3QnhqeL+WW88YjYbQL5gUIkthuMw7a0NGbZ7wfFVk2kg/CK5w8w5FFa0RzWjyY1+sujN0NWbtSHH6OJmWHtJpQ== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/memoize@0.7.4": version "0.7.4" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb" integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw== +"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + +"@emotion/react@^11": + version "11.8.2" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.8.2.tgz#e51f5e6372e22e82780836c9288da19af4b51e70" + integrity sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.7.1" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.1.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + "@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16": version "0.11.16" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad" @@ -1881,11 +2509,27 @@ "@emotion/utils" "0.11.3" csstype "^2.5.7" +"@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + "@emotion/sheet@0.9.4": version "0.9.4" resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5" integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA== +"@emotion/sheet@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" + integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== + "@emotion/styled-base@^10.0.27": version "10.0.31" resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a" @@ -1904,12 +2548,23 @@ "@emotion/styled-base" "^10.0.27" babel-plugin-emotion "^10.0.27" +"@emotion/styled@^11": + version "11.8.1" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.8.1.tgz#856f6f63aceef0eb783985fa2322e2bf66d04e17" + integrity sha512-OghEVAYBZMpEquHZwuelXcRjRJQOVayvbmNR0zr174NHdmMgrNkLC6TljKC5h9lZLkN5WGrdUcrKlOJ4phhoTQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/is-prop-valid" "^1.1.2" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.1.0" + "@emotion/stylis@0.8.5", "@emotion/stylis@^0.8.4": version "0.8.5" resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04" integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ== -"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4": +"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5": version "0.7.5" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== @@ -1919,7 +2574,12 @@ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924" integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw== -"@emotion/weak-memoize@0.2.5": +"@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" + integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== + +"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5": version "0.2.5" resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== @@ -2318,6 +2978,21 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.3.tgz#8b68da1ebd7fc603999cf6ebee34a4899a14b88e" integrity sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ== +"@popperjs/core@^2.9.3": + version "2.11.4" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.4.tgz#d8c7b8db9226d2d7664553a0741ad7d0397ee503" + integrity sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg== + +"@reach/alert@0.13.2": + version "0.13.2" + resolved "https://registry.yarnpkg.com/@reach/alert/-/alert-0.13.2.tgz#71c4a848d51341f1d6d9eaae060975391c224870" + integrity sha512-LDz83AXCrClyq/MWe+0vaZfHp1Ytqn+kgL5VxG7rirUvmluWaj/snxzfNPWn0Ma4K2YENmXXRC/iHt5X95SqIg== + dependencies: + "@reach/utils" "0.13.2" + "@reach/visually-hidden" "0.13.2" + prop-types "^15.7.2" + tslib "^2.1.0" + "@reach/router@^1.3.4": version "1.3.4" resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" @@ -2328,6 +3003,23 @@ prop-types "^15.6.1" react-lifecycles-compat "^3.0.4" +"@reach/utils@0.13.2": + version "0.13.2" + resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.13.2.tgz#87e8fef8ebfe583fa48250238a1a3ed03189fcc8" + integrity sha512-3ir6cN60zvUrwjOJu7C6jec/samqAeyAB12ZADK+qjnmQPdzSYldrFWwDVV5H0WkhbYXR3uh+eImu13hCetNPQ== + dependencies: + "@types/warning" "^3.0.0" + tslib "^2.1.0" + warning "^4.0.3" + +"@reach/visually-hidden@0.13.2": + version "0.13.2" + resolved "https://registry.yarnpkg.com/@reach/visually-hidden/-/visually-hidden-0.13.2.tgz#ee21de376a7e57e60dc92d95a671073796caa17e" + integrity sha512-sPZwNS0/duOuG0mYwE5DmgEAzW9VhgU3aIt1+mrfT/xiT9Cdncqke+kRBQgU708q/Ttm9tWsoHni03nn/SuPTQ== + dependencies: + prop-types "^15.7.2" + tslib "^2.1.0" + "@react-aria/checkbox@^3.2.3": version "3.2.3" resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.2.3.tgz#be7f1f881e6d0fb554b5b20b9243e31e222207d5" @@ -3893,6 +4585,18 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/lodash.mergewith@4.6.6": + version "4.6.6" + resolved "https://registry.yarnpkg.com/@types/lodash.mergewith/-/lodash.mergewith-4.6.6.tgz#c4698f5b214a433ff35cb2c75ee6ec7f99d79f10" + integrity sha512-RY/8IaVENjG19rxTZu9Nukqh0W2UrYgmBj5sdns4hWRZaV8PqR7wIKHFKzvOTjo4zVRV7sVI+yFhAJql12Kfqg== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.180" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.180.tgz#4ab7c9ddfc92ec4a887886483bc14c79fb380670" + integrity sha512-XOKXa1KIxtNXgASAnwj7cnttJxS4fksBRywK/9LzRV5YxrF80BXZIGeQSuoESQ/VkUj30Ae0+YcuHc15wJCB2g== + "@types/markdown-to-jsx@^6.11.3": version "6.11.3" resolved "https://registry.yarnpkg.com/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz#cdd1619308fecbc8be7e6a26f3751260249b020e" @@ -4067,6 +4771,11 @@ resolved "https://registry.yarnpkg.com/@types/verror/-/verror-1.10.4.tgz#805c0612b3a0c124cf99f517364142946b74ba3b" integrity sha512-OjJdqx6QlbyZw9LShPwRW+Kmiegeg3eWNI41MQQKaG3vjdU2L9SRElntM51HmHBY1cu7izxQJ1lMYioQh3XMBg== +"@types/warning@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" + integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= + "@types/webpack-env@^1.16.0": version "1.16.2" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.16.2.tgz#8db514b059c1b2ae14ce9d7bb325296de6a9a0fa" @@ -4589,6 +5298,13 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-hidden@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254" + integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA== + dependencies: + tslib "^1.0.0" + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -4863,7 +5579,7 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: +babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== @@ -5937,6 +6653,11 @@ compression@^1.7.4: safe-buffer "5.1.2" vary "~1.1.2" +compute-scroll-into-view@1.0.14: + version "1.0.14" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.14.tgz#80e3ebb25d6aa89f42e533956cb4b16a04cfe759" + integrity sha512-mKDjINe3tc6hGelUMNDzuhorIUZ7kS7BwyY0r2wQd2HOH2tRuJykiC06iSEX8y1TuhNzvz4GcJnK16mM2J1NMQ== + compute-scroll-into-view@^1.0.17: version "1.0.17" resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab" @@ -6256,7 +6977,7 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-to-clipboard@^3.3.1: +copy-to-clipboard@3.3.1, copy-to-clipboard@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== @@ -6442,6 +7163,13 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== +css-box-model@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" @@ -6514,6 +7242,11 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== +csstype@^3.0.9: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" @@ -6837,6 +7570,11 @@ detect-newline@^3.1.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -7944,6 +8682,20 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +focus-lock@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.10.2.tgz#561c62bae8387ecba1dd8e58a6df5ec29835c644" + integrity sha512-DSaI/UHZ/02sg1P616aIWgToQcrKKBmcCvomDZ1PZvcJFj350PnWhSJxJ76T3e5/GbtQEARIACtbrdlrF9C5kA== + dependencies: + tslib "^2.0.3" + +focus-lock@^0.9.1: + version "0.9.2" + resolved "https://registry.yarnpkg.com/focus-lock/-/focus-lock-0.9.2.tgz#9d30918aaa99b1b97677731053d017f82a540d5b" + integrity sha512-YtHxjX7a0IC0ZACL5wsX8QdncXofWpGPNoVMuI/nZUrPGp6LmNI6+D5j0pPj+v8Kw5EpweA+T5yImK0rnWf7oQ== + dependencies: + tslib "^2.0.3" + follow-redirects@^1.0.0: version "1.14.7" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" @@ -8049,6 +8801,33 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" +framer-motion@^6: + version "6.2.8" + resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.2.8.tgz#02abb529191af7e2df444185fe27e932215b715d" + integrity sha512-4PtBWFJ6NqR350zYVt9AsFDtISTqsdqna79FvSYPfYDXuuqFmiKtZdkTnYPslnsOMedTW0pEvaQ7eqjD+sA+HA== + dependencies: + framesync "6.0.1" + hey-listen "^1.0.8" + popmotion "11.0.3" + style-value-types "5.0.0" + tslib "^2.1.0" + optionalDependencies: + "@emotion/is-prop-valid" "^0.8.2" + +framesync@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/framesync/-/framesync-5.3.0.tgz#0ecfc955e8f5a6ddc8fdb0cc024070947e1a0d9b" + integrity sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA== + dependencies: + tslib "^2.1.0" + +framesync@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/framesync/-/framesync-6.0.1.tgz#5e32fc01f1c42b39c654c35b16440e07a25d6f20" + integrity sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA== + dependencies: + tslib "^2.1.0" + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -8216,6 +8995,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -8731,6 +9515,11 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hey-listen@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/hey-listen/-/hey-listen-1.0.8.tgz#8e59561ff724908de1aa924ed6ecc84a56a9aa68" + integrity sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q== + highlight.js@^10.1.1, highlight.js@~10.7.0: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" @@ -8755,7 +9544,7 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -10171,6 +10960,11 @@ lodash.ismatch@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= +lodash.mergewith@4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" @@ -11545,6 +12339,16 @@ polished@^4.0.5, polished@^4.1.3: dependencies: "@babel/runtime" "^7.14.0" +popmotion@11.0.3: + version "11.0.3" + resolved "https://registry.yarnpkg.com/popmotion/-/popmotion-11.0.3.tgz#565c5f6590bbcddab7a33a074bb2ba97e24b0cc9" + integrity sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA== + dependencies: + framesync "6.0.1" + hey-listen "^1.0.8" + style-value-types "5.0.0" + tslib "^2.1.0" + popper.js@1.16.1-lts: version "1.16.1-lts" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" @@ -11953,6 +12757,13 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-clientside-effect@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3" + integrity sha512-2bL8qFW1TGBHozGGbVeyvnggRpMjibeZM2536AKNENLECutp2yfs44IL8Hmpn8qjFQ2K7A9PnYf3vc7aQq/cPA== + dependencies: + "@babel/runtime" "^7.12.13" + react-codemirror2@^7.2.1: version "7.2.1" resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-7.2.1.tgz#38dab492fcbe5fb8ebf5630e5bb7922db8d3a10c" @@ -12056,11 +12867,35 @@ react-error-overlay@^6.0.9: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== -react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: +react-fast-compare@3.2.0, react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== +react-focus-lock@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.5.2.tgz#f1e4db5e25cd8789351f2bd5ebe91e9dcb9c2922" + integrity sha512-WzpdOnEqjf+/A3EH9opMZWauag7gV0BxFl+EY4ElA4qFqYsUsBLnmo2sELbN5OC30S16GAWMy16B9DLPpdJKAQ== + dependencies: + "@babel/runtime" "^7.0.0" + focus-lock "^0.9.1" + prop-types "^15.6.2" + react-clientside-effect "^1.2.5" + use-callback-ref "^1.2.5" + use-sidecar "^1.0.5" + +react-focus-lock@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.8.1.tgz#a28f06a4ef5eab7d4ef0d859512772ec1331d529" + integrity sha512-4kb9I7JIiBm0EJ+CsIBQ+T1t5qtmwPRbFGYFQ0t2q2qIpbFbYTHDjnjJVFB7oMBtXityEOQehblJPjqSIf3Amg== + dependencies: + "@babel/runtime" "^7.0.0" + focus-lock "^0.10.2" + prop-types "^15.6.2" + react-clientside-effect "^1.2.5" + use-callback-ref "^1.2.5" + use-sidecar "^1.0.5" + react-force-graph-2d@^1.19.0: version "1.23.6" resolved "https://registry.yarnpkg.com/react-force-graph-2d/-/react-force-graph-2d-1.23.6.tgz#0fa29348a30d3a71c6ed7f79d5af51eac66a6c18" @@ -12155,6 +12990,25 @@ react-refresh@^0.8.3: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== +react-remove-scroll-bar@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz#d4d545a7df024f75d67e151499a6ab5ac97c8cdd" + integrity sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg== + dependencies: + react-style-singleton "^2.1.0" + tslib "^1.0.0" + +react-remove-scroll@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.4.1.tgz#e0af6126621083a5064591d367291a81b2d107f5" + integrity sha512-K7XZySEzOHMTq7dDwcHsZA6Y7/1uX5RsWhRXVYv8rdh+y9Qz2nMwl9RX/Mwnj/j7JstCGmxyfyC0zbVGXYh3mA== + dependencies: + react-remove-scroll-bar "^2.1.0" + react-style-singleton "^2.1.0" + tslib "^1.0.0" + use-callback-ref "^1.2.3" + use-sidecar "^1.0.1" + react-sizeme@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-3.0.1.tgz#4d12f4244e0e6a0fb97253e7af0314dc7c83a5a0" @@ -12165,6 +13019,15 @@ react-sizeme@^3.0.1: shallowequal "^1.1.0" throttle-debounce "^3.0.1" +react-style-singleton@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66" + integrity sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^1.0.0" + react-syntax-highlighter@^13.5.3: version "13.5.3" resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz#9712850f883a3e19eb858cf93fad7bb357eea9c6" @@ -13557,6 +14420,14 @@ style-to-object@0.3.0, style-to-object@^0.3.0: dependencies: inline-style-parser "0.1.1" +style-value-types@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/style-value-types/-/style-value-types-5.0.0.tgz#76c35f0e579843d523187989da866729411fc8ad" + integrity sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA== + dependencies: + hey-listen "^1.0.8" + tslib "^2.1.0" + styled-components@5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.2.1.tgz#6ed7fad2dc233825f64c719ffbdedd84ad79101a" @@ -13589,6 +14460,11 @@ styled-components@^5.3.0: shallowequal "^1.1.0" supports-color "^5.5.0" +stylis@4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" @@ -13787,6 +14663,11 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tiny-invariant@^1.0.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" @@ -13967,7 +14848,7 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.0.0, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -14327,6 +15208,11 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +use-callback-ref@^1.2.3, use-callback-ref@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" + integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== + use-composed-ref@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/use-composed-ref/-/use-composed-ref-1.1.0.tgz#9220e4e94a97b7b02d7d27eaeab0b37034438bbc" @@ -14346,6 +15232,14 @@ use-latest@^1.0.0: dependencies: use-isomorphic-layout-effect "^1.0.0" +use-sidecar@^1.0.1, use-sidecar@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" + integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== + dependencies: + detect-node-es "^1.1.0" + tslib "^1.9.3" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" From dcb81a286cfc4fc225a00524e6d9cd7fb436b786 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 23 Mar 2022 10:06:29 -0400 Subject: [PATCH 03/79] misc improvements --- src/cljs/athens/electron/db_menu/core.cljs | 16 ++-- .../athens/electron/db_menu/db_list_item.cljs | 15 ++-- src/cljs/athens/views.cljs | 80 +++++++++---------- src/cljs/athens/views/athena.cljs | 5 +- src/js/components/AppToolbar/AppToolbar.tsx | 70 +++++++++++----- src/js/theme/theme.js | 21 +++++ 6 files changed, 129 insertions(+), 78 deletions(-) diff --git a/src/cljs/athens/electron/db_menu/core.cljs b/src/cljs/athens/electron/db_menu/core.cljs index 268d028d21..c3eab93cd4 100644 --- a/src/cljs/athens/electron/db_menu/core.cljs +++ b/src/cljs/athens/electron/db_menu/core.cljs @@ -34,7 +34,10 @@ :synchronising)] [:> Popover {:placement "bottom-start"} [:> PopoverTrigger - [:> IconButton + [:> IconButton {:p 0 + :bg "background.floor" + :_hover {:bg "background.upper"} + :_active {:bg "background.upper"}} ;; DB Icon + Dropdown toggle [db-icon {:db active-db :status sync-status}]]] @@ -46,11 +49,11 @@ :overflowY "auto" :spacing 2} ;; Show active DB first - [:> Box - [db-list-item {:db active-db - :is-current true - :key (:id active-db)}] - [current-db-tools {:db active-db} all-dbs]] + [:> Box + [db-list-item {:db active-db + :is-current true + :key (:id active-db)}] + [current-db-tools {:db active-db} all-dbs]] ;; Show all inactive DBs and a separator [:> VStack {:align "stretch" :spacing 0} @@ -62,6 +65,7 @@ :key key}] [:> Divider]]))] ;; Add DB control + [:> Divider] [:> ButtonGroup {:p 2 :pt 0 :pl 10 :size "sm" :width "100%" :ml 10 :justifyContent "flex-start"} [:> Button {:onClick #(dispatch [:modal/toggle])} "Add Database"]]]]]]])) diff --git a/src/cljs/athens/electron/db_menu/db_list_item.cljs b/src/cljs/athens/electron/db_menu/db_list_item.cljs index d01932938d..059dab7028 100644 --- a/src/cljs/athens/electron/db_menu/db_list_item.cljs +++ b/src/cljs/athens/electron/db_menu/db_list_item.cljs @@ -1,12 +1,11 @@ (ns athens.electron.db-menu.db-list-item (:require - ["@chakra-ui/react" :refer [VStack Flex Text Button IconButton]] - ["@material-ui/icons/Clear" :default Clear] - ["@material-ui/icons/Link" :default Link] - [athens.electron.db-menu.db-icon :refer [db-icon]] - [athens.electron.dialogs :as dialogs] - [re-frame.core :refer [dispatch]] - )) + ["@chakra-ui/react" :refer [VStack Flex Text Button IconButton]] + ["@material-ui/icons/Clear" :default Clear] + ["@material-ui/icons/Link" :default Link] + [athens.electron.db-menu.db-icon :refer [db-icon]] + [athens.electron.dialogs :as dialogs] + [re-frame.core :refer [dispatch]])) (defn active-db @@ -31,7 +30,7 @@ (:name db)] [:> Text {:textOverflow "ellipsis" :size "sm" - :color "feature.secondary" + :color "foreground.secondary" :overflow "hidden" :title (:id db)} (when (:is-remote db) diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index d75254d901..33ac249792 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -58,47 +58,47 @@ electron? electron.utils/electron? modal (rf/subscribe [:modal])] (fn [] - [:> ChakraProvider {:theme theme, - :bg "background.basement"} - [:> OverlayProvider - [:div (merge {:style {:display "contents"}} - (zoom)) - [help-popup] - [alert] - (let [{:keys [msg type]} @(rf/subscribe [:db/snack-msg])] - [m-snackbar - {:message msg - :open (boolean msg)} - [:span - {:style {:background-color (case type - :success "green" - "red") - :padding "10px 20px" - :color "white"}} - msg]]) - [athena-component] - (cond - (and @loading @modal) [db-modal/window] + [:div (merge {:style {:display "contents"}} + (zoom)) + [:> ChakraProvider {:theme theme, + :bg "background.basement"} + [:> OverlayProvider + [help-popup] + [alert] + (let [{:keys [msg type]} @(rf/subscribe [:db/snack-msg])] + [m-snackbar + {:message msg + :open (boolean msg)} + [:span + {:style {:background-color (case type + :success "green" + "red") + :padding "10px 20px" + :color "white"}} + msg]]) + [athena-component] + (cond + (and @loading @modal) [db-modal/window] - @loading [:> Spinner] + @loading [:> Spinner] - :else [:<> - (when @modal [db-modal/window]) - [:> Grid - {:gridTemplateColumns "auto 1fr auto" - :gridTemplateRows "auto 1fr auto" - :grid-template-areas - "'app-header app-header app-header' + :else [:<> + (when @modal [db-modal/window]) + [:> Grid + {:gridTemplateColumns "auto 1fr auto" + :gridTemplateRows "auto 1fr auto" + :grid-template-areas + "'app-header app-header app-header' 'left-sidebar main-content secondary-content' 'devtool devtool devtool'" - :height "100vh" - :className [(case os - :windows "os-windows" - :mac "os-mac" - :linux "os-linux") - (when electron? "is-electron")]} - [app-toolbar/app-toolbar] - [left-sidebar/left-sidebar] - [pages/view] - [right-sidebar/right-sidebar] - [devtool-component]]])]]]))) + :height "100vh" + :className [(case os + :windows "os-windows" + :mac "os-mac" + :linux "os-linux") + (when electron? "is-electron")]} + [app-toolbar/app-toolbar] + [left-sidebar/left-sidebar] + [pages/view] + [right-sidebar/right-sidebar] + [devtool-component]]])]]]))) diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index dd2cd646c5..4b5089928c 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -298,14 +298,13 @@ (when @athena-open? [:> Modal {:maxHeight "60vh" :display "flex" - :_focus {:outline "none"} + :outline "none" :closeOnEsc true :isOpen @athena-open? :onClose #(dispatch [:athena/toggle])} - [:> ModalOverlay {:_focus {:outline "none"}}] + [:> ModalOverlay] [:> ModalContent {:width "49rem" - :_focus {:outline "none"} :bg "background.upper" :maxWidth "calc(100vw - 4rem)"} [:> Input diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index 35e318be20..13468a9e89 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -28,6 +28,19 @@ import { import { WindowButtons } from './components/WindowButtons'; +const toolbarButtonStyle = { + background: 'background.floor', + _hover: { + bg: 'background.upper' + }, + _active: { + bg: 'link' + } +} + +const ToolbarButton = ({ children, ...props }) => +const ToolbarIconButton = ({ children, ...props }) => {children} + const AppToolbarWrapper = ({ children }) => { {databaseMenu} - - + {isElectron && ( <> - + - + onClick={handlePressHistoryForward}> + + ) } - - - - + {presenceDetails} - - - + + + {isThemeDark ? : } - - + + - - + diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js index 50fe729cb1..19cf1e20be 100644 --- a/src/js/theme/theme.js +++ b/src/js/theme/theme.js @@ -1,4 +1,5 @@ import { extendTheme } from '@chakra-ui/react' +import { red } from '@material-ui/core/colors' import { spacing } from './spacing' @@ -111,6 +112,26 @@ const semanticTokens = { } const components = { + Popover: { + baseStyle: { + content: { + bg: 'background.upper', + shadow: '0 0.5rem 1rem rgba(0, 0, 0, 0.15)' + } + } + }, + Modal: { + baseStyle: { + dialogContainer: { + _focus: { + outline: 'none' + } + }, + dialog: { + bg: 'background.upper' + } + } + }, Button: { baseStyle: { color: 'feature.primary', From d18c2498339753222db4403aba6a9ff585c8205f Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 23 Mar 2022 14:37:51 -0400 Subject: [PATCH 04/79] feat: improved table --- src/cljs/athens/views/pages/all_pages.cljs | 136 ++++++-------------- src/js/components/AppToolbar/AppToolbar.tsx | 9 +- src/js/theme/theme.js | 57 ++++++-- 3 files changed, 95 insertions(+), 107 deletions(-) diff --git a/src/cljs/athens/views/pages/all_pages.cljs b/src/cljs/athens/views/pages/all_pages.cljs index 4e524f9bfe..938fe357a6 100644 --- a/src/cljs/athens/views/pages/all_pages.cljs +++ b/src/cljs/athens/views/pages/all_pages.cljs @@ -1,80 +1,14 @@ (ns athens.views.pages.all-pages (:require + ["@chakra-ui/react" :refer [Table Thead Tr Th Tbody Td Button]] ["@material-ui/icons/ArrowDropDown" :default ArrowDropDown] ["@material-ui/icons/ArrowDropUp" :default ArrowDropUp] [athens.common-db :as common-db] [athens.dates :as dates] [athens.db :as db] [athens.router :as router] - [athens.style :as style :refer [color OPACITIES]] [clojure.string :refer [lower-case]] - [garden.selectors :as selectors] - [re-frame.core :as rf] - [stylefy.core :as stylefy :refer [use-style]])) - - -;; Styles - - -(def page-style - {:display "flex" - :margin "5rem auto" - :flex-basis "100%" - :max-width "70rem"}) - - -(def table-style - {:flex "1 1 100%" - :margin "0 2rem" - :text-align "left" - :border-collapse "collapse" - ::stylefy/manual [[:tbody {:vertical-align "top"} - [:tr {:transition "background 0.1s ease"} - [:td {:border-top (str "1px solid " (color :border-color)) - :transition "box-shadow 0.1s ease"} - [:&.title {:color (color :link-color) - :width "15vw" - :cursor "pointer" - :min-width "10em" - :word-break "break-word" - :font-weight "500" - :font-size "1.3125em" - :line-height "1.28"}] - [:&.links {:font-size "1em" - :text-align "center"}] - [:&.body-preview {:word-break "break-word" - :overflow "hidden" - :text-overflow "ellipsis" - :display "-webkit-box" - :-webkit-mask "linear-gradient(to bottom, #fff calc(100% - 1em), transparent)" - :-webkit-line-clamp "3" - :-webkit-box-orient "vertical"} - [:span:empty {:display "none"}] - [(selectors/+ :span :span) - [:&:before {:content "'•'" - :margin-inline "0.5em" - :opacity (:opacity-low OPACITIES)}]]] - [:&.date {:text-align "right" - :opacity (:opacity-high OPACITIES) - :font-size "0.75em" - :min-width "9em"}] - [:&:first-child {:border-radius "0.5rem 0 0 0.5rem" - :box-shadow "-1rem 0 transparent"}] - [:&:last-child {:border-radius "0 0.5rem 0.5rem 0" - :box-shadow "1rem 0 transparent"}]] - [:&:hover {:background-color (color :background-minus-1 :opacity-med) - :border-radius "0.5rem"} - [:td [:&:first-child {:box-shadow [["-1rem 0 " (color :background-minus-1 :opacity-med)]]}]] - [:td [:&:last-child {:box-shadow [["1rem 0 " (color :background-minus-1 :opacity-med)]]}]]]]] - [:td :th {:padding "0.5rem"}] - [:th {:opacity (:opacity-med OPACITIES) - :user-select "none"} - [:&.sortable {:cursor "pointer"} - [:.wrap-label {:display "flex" - :align-items "center"}] - [:&.date - [:.wrap-label {:flex-direction "row-reverse"}]] - [:&:hover {:opacity 1}]]]]}) + [re-frame.core :as rf])) ;; Sort state and logic @@ -129,17 +63,18 @@ ;; Components (defn- sortable-header - ([column-id label] - (sortable-header column-id label {:date? false})) - ([column-id label {:keys [date?]}] + ([column-id label width] (let [sorted-by @(rf/subscribe [:all-pages/sorted-by]) growing? @(rf/subscribe [:all-pages/sort-order-ascending?])] - [:th {:on-click #(rf/dispatch [:all-pages/sort-by column-id]) - :class ["sortable" (when date? "date")]} - [:div.wrap-label - [:h5 label] + [:> Th {:width width} + [:> Button {:onClick #(rf/dispatch [:all-pages/sort-by column-id]) + :size "sm" + :variant "link"} + label (when (= sorted-by column-id) - (if growing? [:> ArrowDropUp] [:> ArrowDropDown]))]]))) + (if growing? + [:> ArrowDropUp] + [:> ArrowDropDown]))]]))) (defn page @@ -147,30 +82,35 @@ (let [all-pages (common-db/get-all-pages @db/dsdb)] (fn [] (let [sorted-pages @(rf/subscribe [:all-pages/sorted all-pages])] - [:div (use-style page-style) - [:table (use-style table-style) - [:thead - [:tr + [:> Table {:variant "striped" + :margin "5rem auto" + :border "2rem solid transparent" + :flex-basis "100%" + :max-width "70rem"} + [:> Thead + [:> Tr [sortable-header :title "Title"] - [sortable-header :links-count "Links"] - [sortable-header :modified "Modified" {:date? true}] - [sortable-header :created "Created" {:date? true}]]] - [:tbody + [sortable-header :links-count "Links" :width "10rem"] + [sortable-header :modified "Modified" {:date? true} :width "20rem"] + [sortable-header :created "Created" {:date? true} :width "20rem"]]] + [:> Tbody (doall (for [{:keys [block/uid node/title block/_refs] modified :edit/time created :create/time} sorted-pages] - [:tr {:key uid} - [:td {:class "title" - :on-click (fn [e] - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :all-pages - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page title e)))} - title] - [:td {:class "links"} (count _refs)] - [:td {:class "date"} (dates/date-string modified)] - [:td {:class "date"} (dates/date-string created)]]))]]])))) + [:> Tr {:key uid} + [:> Td + [:> Button {:variant "link" + :color "link" + :onClick (fn [e] + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :all-pages + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page title e)))} + title]] + [:> Td {:color "foreground.secondary"} (count _refs)] + [:> Td {:color "foreground.secondary"} (dates/date-string modified)] + [:> Td {:color "foreground.secondary"} (dates/date-string created)]]))]])))) diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index 13468a9e89..6bad53dfb1 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -31,7 +31,7 @@ import { WindowButtons } from './components/WindowButtons'; const toolbarButtonStyle = { background: 'background.floor', _hover: { - bg: 'background.upper' + bg: 'background.attic' }, _active: { bg: 'link' @@ -247,8 +247,15 @@ export const AppToolbar = (props: AppToolbarProps): React.ReactElement => { } + pl="0.5rem" isActive={isCommandBarOpen} onClick={handlePressCommandBar} + border="1px solid" + borderColor="background.attic" + _active={{ + bg: 'link', + borderColor: "link" + }} > Find or create a page diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js index 19cf1e20be..8f796e9362 100644 --- a/src/js/theme/theme.js +++ b/src/js/theme/theme.js @@ -5,6 +5,8 @@ import { spacing } from './spacing' const colors = { // Old theme values + + // light theme linkLight: "#0071DB", highlightLight: "#F9A132", textHighlightLight: "#ffdb8a", @@ -16,12 +18,6 @@ const colors = { backgroundMinus1Light: "#FAF8F6", backgroundMinus2Light: "#EFEDEB", - backgroundMinu2Dark: "#151515", - backgroundMinus1Dark: "#111", - backgroundColorDark: "#1A1A1A", - backgroundPlus1Dark: "#222", - backgroundPlus2Dark: "#333", - confirmationLight: "#009E23", headerLight: "#322F38", bodyLight: "#433F38", @@ -29,10 +25,18 @@ const colors = { errorLight: "#fd5243", shadowLight: "#000", - linkDark: "#0071DB", + // dark theme + backgroundMinu2Dark: "#151515", + backgroundMinus1Dark: "#111", + backgroundColorDark: "#1A1A1A", + backgroundPlus1Dark: "#222", + backgroundPlus2Dark: "#333", + + linkDark: "#498eda", highlightDark: "#FBBE63", textHighlightDark: "#FBBE63", warningDark: "#DE3C21", + confirmationDark: "#189E36", headerDark: "#BABABA", bodyDark: "#AAA", @@ -48,6 +52,7 @@ const semanticTokens = { default: 'linkLight', _dark: 'linkDark' }, + // separator colors "separator.border": { default: 'borderLight', _dark: 'borderDark' @@ -56,6 +61,7 @@ const semanticTokens = { default: 'borderLight', _dark: 'borderDark' }, + // background colors "background.floor": { default: 'backgroundColorLight', _dark: 'backgroundColorDark' @@ -72,6 +78,7 @@ const semanticTokens = { default: 'backgroundPlus2Light', _dark: 'backgroundPlus2Dark' }, + // foreground colors "foreground.primary": { default: 'bodyLight', _dark: 'bodyDark' @@ -80,6 +87,7 @@ const semanticTokens = { default: 'headerLight', _dark: 'headerDark' }, + // status colors error: { default: 'errorLight', _dark: 'errorDark' @@ -92,6 +100,7 @@ const semanticTokens = { default: 'confirmationLight', _dark: 'confirmationDark' }, + // other colors headerText: { default: 'headerLight', _dark: 'headerDark' @@ -149,6 +158,38 @@ const components = { maxW: "320px", zIndex: "tooltip", } + }, + Table: { + baseStyle: { + border: 'separator.divider', + }, + variants: { + striped: { + td: { + border: 'none', + }, + thead: { + th: { + border: 'none' + } + }, + tbody: { + tr: { + "&:nth-of-type(odd)": { + td: { + background: "background.upper", + "&:first-of-type": { + borderLeftRadius: "lg" + }, + "&:last-of-type": { + borderRightRadius: "lg" + } + }, + }, + }, + }, + } + } } } @@ -161,7 +202,7 @@ const styles = { global: { 'html, body': { bg: 'background.floor', - color: 'feature.foreground', + color: 'foreground.primary', } } } From e9020c4afd8f941767d6892cca50fa6a8ff71ffa Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 24 Mar 2022 21:33:39 -0400 Subject: [PATCH 05/79] improvement: more work everywhere --- src/cljs/athens/electron/db_modal.cljs | 225 +++++------- src/cljs/athens/views.cljs | 1 + src/cljs/athens/views/athena.cljs | 202 ++++++----- .../views/blocks/autocomplete_search.cljs | 75 ++-- .../views/blocks/autocomplete_slash.cljs | 22 +- src/cljs/athens/views/blocks/content.cljs | 173 +++------ src/cljs/athens/views/blocks/core.cljs | 156 ++++---- .../athens/views/blocks/textarea_keydown.cljs | 13 +- src/cljs/athens/views/dropdown.cljs | 71 ---- src/cljs/athens/views/help.cljs | 273 ++++++-------- src/cljs/athens/views/left_sidebar.cljs | 31 +- src/cljs/athens/views/modal.cljs | 46 --- src/cljs/athens/views/pages/all_pages.cljs | 60 ++-- src/cljs/athens/views/pages/block_page.cljs | 49 +-- src/cljs/athens/views/pages/daily_notes.cljs | 30 +- src/cljs/athens/views/pages/graph.cljs | 12 +- src/cljs/athens/views/pages/node_page.cljs | 224 +++++------- src/cljs/athens/views/right_sidebar.cljs | 39 +- src/js/components/AppToolbar/AppToolbar.tsx | 48 ++- src/js/components/Block/components/Anchor.tsx | 335 ++++++++++++------ src/js/components/Block/components/Toggle.tsx | 1 + src/js/theme/theme.js | 157 +++++++- 22 files changed, 1126 insertions(+), 1117 deletions(-) delete mode 100644 src/cljs/athens/views/modal.cljs diff --git a/src/cljs/athens/electron/db_modal.cljs b/src/cljs/athens/electron/db_modal.cljs index 514488275a..3646db61ca 100644 --- a/src/cljs/athens/electron/db_modal.cljs +++ b/src/cljs/athens/electron/db_modal.cljs @@ -1,23 +1,13 @@ (ns athens.electron.db-modal (:require - ["/components/Button/Button" :refer [Button]] - ["@material-ui/icons/AddBox" :default AddBox] - ["@material-ui/icons/Close" :default Close] - ["@material-ui/icons/Folder" :default Folder] - ["@material-ui/icons/Group" :default Group] - ["@material-ui/icons/MergeType" :default MergeType] - ["@material-ui/icons/Storage" :default Storage] - ["@chakra-ui/react" :refer [Box Text Modal ModalOverlay Divider VStack Heading ModalContent ModalHeader ModalFooter ModalBody ModalCloseButton ButtonGroup]] - ["react-dom" :as react-dom] + ["@chakra-ui/react" :refer [VStack FormControl FormLabel Input Button Box Tabs Tab TabList TabPanel TabPanels Text Modal ModalOverlay Divider VStack Heading ModalContent ModalHeader ModalFooter ModalBody ModalCloseButton ButtonGroup]] [athens.electron.dialogs :as dialogs] [athens.electron.utils :as utils] [athens.events :as events] [athens.subs] [athens.util :refer [js-event->val]] - [athens.views.textinput :as textinput] [clojure.edn :as edn] [datascript.core :as d] - [komponentit.modal :as modal] [re-frame.core :refer [subscribe dispatch] :as rf] [reagent.core :as r])) @@ -55,6 +45,7 @@ (fn [] [:> Modal {:isOpen open? :onClose close-modal + :closeOnOverlayClick false :size "lg"} [:> ModalOverlay] [:> ModalContent @@ -107,59 +98,66 @@ [:li [:> Text (str "[[" x "]]")]])] [:> ModalFooter [:> ButtonGroup - [:> Button {:variant "outline" - :onClick (fn [] + [:> Button {:onClick (fn [] (dispatch [:upload/roam-edn @transformed-roam-db @roam-db-filename]) (close-modal))} "Merge"]]]]))]]))) + +(defn form-container + [content footer] + [:<> + [:> Box {:p 5 :pt 4} + content] + [:> ModalFooter {:borderTop "1px solid" + :borderColor "separator.divider" + :p 2 + :pr 5} footer]]) + + + (defn open-local-comp [loading db] - [:<> - [:h5 {:style {:align-self "flex-start" - :margin-top "2em"}} - (if @loading - "No DB Found At" - "Current Location")] - [:code {:style {:margin "1rem 0 2rem 0"}} (:id db)] - [:div #_ (use-style {:display "flex" - :justify-content "space-between" - :align-items "center" - :width "80%"}) - [:> Button {:is-primary true - :on-click #(dialogs/open-dialog!)} + [form-container + [:> FormControl {:isReadOnly true} + [:> FormLabel (if @loading + "No DB Found At" + "Current Location")] + [:> Text {:as "output" + :borderRadius "md" + :cursor "default" + :bg "background.floor" + :color "foreground.secondary" + :py 1.5 + :px 2.5 + :display "flex"} + (:id db)]] + [:> ButtonGroup + [:> Button {:onClick #(dialogs/open-dialog!)} "Open"] - [:> Button {:disabled @loading - :is-primary true - :on-click #(dialogs/move-dialog!)} + [:> Button {:isDisabled @loading + :onClick #(dialogs/move-dialog!)} "Move"]]]) - + (defn create-new-local [state] - [:<> - [:div {:style {:display "flex" - :justify-content "space-between" - :width "100%" - :margin-top "2em" - :margin-bottom "1em"}} - [:h5 "Database Name"] - [textinput/textinput {:value (:input @state) - :placeholder "DB Name" - :on-change #(swap! state assoc :input (js-event->val %))}]] - [:div {:style {:display "flex" - :justify-content "space-between" - :width "100%"}} - [:h5 "New Location"] - [:> Button {:is-primary true - :disabled (clojure.string/blank? (:input @state)) - :on-click #(dialogs/create-dialog! (:input @state))} - "Browse"]]]) + [form-container + [:> FormControl + [:> FormLabel "Name"] + [:> Input {:value (:input @state) + :onChange #(swap! state assoc :input (js-event->val %))}]] + [:> ButtonGroup + [:> Button {:value (:input @state) + :isDisabled (clojure.string/blank? (:input @state)) + :onClick #(dialogs/create-dialog! (:input @state))} + "Choose folder"]]]) + (defn join-remote-comp @@ -168,47 +166,28 @@ address (r/atom "localhost:3010") password (r/atom "")] (fn [] - [:<> + [form-container (->> - [:div {:style {:width "100%" :margin-top "10px"}} - [:h5 "Database Name"] - [:div {:style {:margin "5px 0" - :display "flex" - :justify-content "space-between"}} - [textinput/textinput {:style {:flex-grow 1 - :padding "5px"} - :type "text" - :value @name - :placeholder "DB name" - :on-change #(reset! name (js-event->val %))}]] - [:h5 "Remote Address"] - [:div {:style {:margin "5px 0" - :display "flex" - :justify-content "space-between"}} - [textinput/textinput {:style {:flex-grow 1 - :padding "5px"} - :type "text" - :value @address - :placeholder "Remote server address" - :on-change #(reset! address (js-event->val %))}]] - [:h5 "Password"] - [:div {:style {:margin "5px 0" - :display "flex" - :justify-content "space-between"}} - [textinput/textinput {:style {:flex-grow 1 - :padding "5px"} - :type "password" - :value @password - :placeholder "Password" - :disabled false - :on-change #(reset! password (js-event->val %))}]]] - doall) - [:> Button {:is-primary true - :style {:margin-top "0.5rem"} - :disabled (or (clojure.string/blank? @name) - (clojure.string/blank? @address)) - :on-click #(rf/dispatch [:db-picker/add-and-select-db (utils/self-hosted-db @name @address @password)])} - "Join"]]))) + [:> VStack {:spacing 4} + [:> FormControl + [:> FormLabel "Database name"] + [:> Input {:value @name + :onChange #(swap! name assoc :input (js-event->val %))}]] + [:> FormControl + [:> FormLabel "Remote address"] + [:> Input {:value @address + :onChange #(reset! address (js-event->val %))}]] + [:> FormControl {:flexDirection "row"} + [:> FormLabel "Password"] + [:> Input {:value @password + :type "password" + :onChange #(reset! password (js-event->val %))}]]] + doall) + [:> ButtonGroup + [:> Button {:isDisabled (or (clojure.string/blank? @name) + (clojure.string/blank? @address)) + :onClick #(rf/dispatch [:db-picker/add-and-select-db (utils/self-hosted-db @name @address @password)])} + "Join"]]]))) (defn window @@ -219,46 +198,34 @@ close-modal (fn [] (when-not @loading (dispatch [:modal/toggle]))) - el (.. js/document (querySelector "#app")) selected-db @(subscribe [:db-picker/selected-db]) - state (r/atom {:input "" - :tab-value (if utils/electron? 0 2)})] + state (r/atom {:input ""})] (fn [] - (.createPortal - react-dom - (r/as-element [:div #_ (use-style modal-style) - [modal/modal - {:title [:div.modal__title - [:> Storage] - [:h4 "Database"] - (when-not @loading - [:> Button {:on-click close-modal} [:> Close]])] - :content [:div #_ (use-style modal-contents-style) - ;; TODO: this is hacky, we're just hiding the picker and forcing - ;; tab 2 for the web client. Instead we should use Stuart's - ;; redesigned DB picker. - (when utils/electron? - [:div #_ (use-style picker-style) - [:button {:class (when (= 0 (:tab-value @state)) "active") - :on-click (fn [] (swap! state assoc :tab-value 0))} - [:> Folder] - [:span "Open"]] - [:button {:class (when (= 1 (:tab-value @state)) "active") - :on-click (fn [] (swap! state assoc :tab-value 1))} - [:> AddBox] - [:span "New"]] - [:button {:class (when (= 2 (:tab-value @state)) "active") - :on-click (fn [] (swap! state assoc :tab-value 2))} - [:> Group] - [:span "Join"]]]) - (cond - (= 2 (:tab-value @state)) - [join-remote-comp] - - (= 1 (:tab-value @state)) - [create-new-local state] - - (= 0 (:tab-value @state)) - [open-local-comp loading selected-db])] - :on-close close-modal}]]) - el)))) + [:> Modal {:isOpen loading + :motionPreset "scale" + :onClose close-modal} + [:> ModalOverlay] + [:> ModalContent + [:> ModalHeader + "Add Database"] + (when-not @loading + [:> ModalCloseButton]) + [:> ModalBody {:display "contents"} + ;; TODO: this is hacky, we're just hiding the picker and forcing + ;; tab 2 for the web client. Instead we should use Stuart's + ;; redesigned DB picker. + [:> Tabs {:isFitted true + :display "contents" + :defaultIndex (if utils/electron? 0 2)} + (when utils/electron? + [:> TabList + [:> Tab "Open Local"] + [:> Tab "Join Remote"] + [:> Tab "Create New"]]) + [:> TabPanels {:display "contents"} + [:> TabPanel {:display "contents"} + [open-local-comp loading selected-db]] + [:> TabPanel {:display "contents"} + [join-remote-comp]] + [:> TabPanel {:display "contents"} + [create-new-local state]]]]]]]))) diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 33ac249792..ea7f77a8cc 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -88,6 +88,7 @@ {:gridTemplateColumns "auto 1fr auto" :gridTemplateRows "auto 1fr auto" :grid-template-areas + "'app-header app-header app-header' 'left-sidebar main-content secondary-content' 'devtool devtool devtool'" diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 4b5089928c..0218956f10 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,6 +1,6 @@ (ns athens.views.athena (:require - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay IconButton Input]] + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Box Heading Text]] ["@material-ui/icons/ArrowForward" :default ArrowForward] ["@material-ui/icons/Close" :default Close] ["@material-ui/icons/Create" :default Create] @@ -171,7 +171,7 @@ input-el (.. e -target) ;; Get the result list container which is the last element child ;; of the whole athena component - result-el (.. input-el (closest "div.athena") -lastElementChild) + result-el (.. input-el (closest "section.athena-modal") -lastElementChild) ;; Get next element in the result list next-el (nth (array-seq (.. result-el -children)) cur-index)] ;; Check if next el is beyond the bounds of the result list and scroll if so @@ -183,7 +183,7 @@ (swap! state update :index #(if (= % (dec (count results))) 0 (inc %))) (let [cur-index (:index @state) input-el (.. e -target) - result-el (.. input-el (closest "div.athena") -lastElementChild) + result-el (.. input-el (closest "section.athena-modal") -lastElementChild) next-el (nth (array-seq (.. result-el -children)) cur-index)] (scroll-into-view next-el result-el (zero? cur-index)))) @@ -192,14 +192,35 @@ ;; Components +(defn result-el + [{:keys [title preview prefix icon query on-click active?]}] + [:> Button {:borderRadius "none" + :justifyContent "flex-start" + :px 6 + :py 10 + :isActive active? + :onClick on-click} + [:div (use-style result-body-style) + [:> Heading {:as "h4" :size "sm"} prefix (highlight-match query title)] + (when preview + [:> Text {:color "foreground.secondary"} (highlight-match query preview)])] + icon]) + (defn results-el [state] (let [no-query? (str/blank? (:query @state)) recent-items @(subscribe [:athena/get-recent])] - [:<> [:div (use-style results-heading-style) - [:h5 (if no-query? "Recent" "Results")] - [:span (use-style hint-style) + [:<> [:> HStack {:fontSize "sm" + :px 6 + :py 2 + :color "foreground.secondary" + :borderTop "1px solid" + :borderColor "separator.divider" + :justifyContent "space-between"} + [:> Heading {:size "xs"} + (if no-query? "Recent" "Results")] + [:> Text "Press " [:kbd "shift + enter"] " to open in right sidebar."]] @@ -209,21 +230,23 @@ (for [[i x] (map-indexed list recent-items)] (when x (let [{:keys [query :node/title :block/string]} x] - [:div (use-style result-style {:key i - :on-click (fn [e] - (rf/dispatch [:reporting/navigation {:source :athena - :target :page - :pane :main-pane}]) - (router/navigate-page title e))}) - [:h4.title (use-sub-style result-style :title) (highlight-match query title)] - (when string - [:span.preview (use-sub-style result-style :preview) (highlight-match query string)]) - [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class ArrowForward)]]]))))])])) + [result-el {:key i + :title title + :query query + :preview string + :on-click (fn [e] + (rf/dispatch [:reporting/navigation {:source :athena + :target :page + :pane :main-pane}]) + (router/navigate-page title e))}]))))])])) + (defn search-results-el [{:keys [results query index]}] - [:div (use-style results-list-style) + [:> VStack {:overflow-y "overlay" + :spacing 0 + :align "stretch"} (doall (for [[i x] (map-indexed list results) :let [block-uid (:block/uid x) @@ -233,58 +256,41 @@ string (:block/string x)]] (if (nil? x) ^{:key i} - [:div (use-style result-style - {:on-click (fn [e] - (let [block-uid (utils/gen-block-uid) - shift? (.-shiftKey e)] - (dispatch [:athena/toggle]) - (dispatch [:page/new {:title query - :block-uid block-uid}]) - (dispatch [:reporting/page.create {:source :athena - :count 1}]) - (dispatch [:reporting/navigation {:source :athena - :target (if parent - (str "block/" block-uid) - (str "page/" title)) - :pane (if shift? - :right-pane - :main-pane)}]))) - :class (when (= i index) "selected")}) - - [:div (use-style result-body-style) - [:h4.title (use-sub-style result-style :title) - [:b "Create Page: "] - query]] - [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class Create)]]] - - [:div (use-style result-style - {:key i - :on-click (fn [e] - (let [selected-page {:node/title title - :block/uid uid - :block/string string - :query query} - shift? (.-shiftKey e)] - (dispatch [:athena/toggle]) - (dispatch [:athena/update-recent-items selected-page]) - (dispatch [:reporting/navigation {:source :athena - :target (if parent - :block - :page) - :pane (if shift? - :right-pane - :main-pane)}]) - (if parent - (router/navigate-uid block-uid) - (router/navigate-page title e)))) - - :class (when (= i index) "selected")}) - [:div (use-style result-body-style) - - [:h4.title (use-sub-style result-style :title) (highlight-match query title)] - (when string - [:span.preview (use-sub-style result-style :preview) (highlight-match query string)])] - [:span.link-leader (use-sub-style result-style :link-leader) [(r/adapt-react-class ArrowForward)]]])))]) + [result-el {:key i + :title query + :prefix "Create page " + :preview nil + :query query + :active? (= i index) + :on-click (fn [e] + (rf/dispatch [:athena/toggle]) + (rf/dispatch [:right-sidebar/open-page (:node/title x) e]) + (rf/dispatch [:reporting/navigation {:source :athena + :target :page + :pane :right-pane}]))}] + [result-el {:key i + :title title + :query query + :preview string + :active? (= i index) + :on-click (fn [e] + (let [selected-page {:node/title title + :block/uid uid + :block/string string + :query query} + shift? (.-shiftKey e)] + (dispatch [:athena/toggle]) + (dispatch [:athena/update-recent-items selected-page]) + (dispatch [:reporting/navigation {:source :athena + :target (if parent + :block + :page) + :pane (if shift? + :right-pane + :main-pane)}]) + (if parent + (router/navigate-uid block-uid) + (router/navigate-page title e))))}])))]) (defn athena-component @@ -303,10 +309,10 @@ :isOpen @athena-open? :onClose #(dispatch [:athena/toggle])} [:> ModalOverlay] - [:> ModalContent - {:width "49rem" - :bg "background.upper" - :maxWidth "calc(100vw - 4rem)"} + [:> ModalContent {:width "49rem" + :class "athena-modal" + :bg "background.upper" + :maxWidth "calc(100vw - 4rem)"} [:> Input {:type "search" :width "100%" @@ -315,35 +321,35 @@ :fontWeight "300" :lineHeight "1.3" :letterSpacing "-0.03em" - :borderRadius "0.25rem 0.25rem 0 0" + :borderRadius "inherit" :color "inherit" :height "auto" :padding "1.5rem 4rem 1.5rem 1.5rem" :cursor "text" - :id "athena-input" - :auto-focus true - :required true + :id "athena-input" + :auto-focus true + :required true :_focus {:outline "none"} :sx {"::-webkit-search-cancel-button" {:display "none"}} :placeholder "Find or Create Page" - :onChange (fn [e] (search-handler (.. e -target -value))) - :onKeyDown (fn [e] (key-down-handler e state))}] - [:> IconButton {:background "none" - :color "inherit" - :position "absolute" - :transition "opacity 0.1s ease, background 0.1s ease" - :cursor "pointer" - :border 0 - :right "2rem" - :placeItems "center" - :placeContent "center" - :height "2.5rem" - :width "2.5rem" - :borderRadius "1000px" - :display "flex" - :transform "translate(0%, -50%)" - :top "50%" - :onClick #(set! (.-value (getElement "athena-input")) nil)} - [:> Close]]] - [results-el state] - [search-results-el @state]])))) + :on-change (fn [e] (search-handler (.. e -target -value))) + :on-key-down (fn [e] (key-down-handler e state))}] + (when (:query @state) + [:> IconButton {:background "none" + :color "inherit" + :position "absolute" + :transition "opacity 0.1s ease, background 0.1s ease" + :cursor "pointer" + :border 0 + :right "2rem" + :placeItems "center" + :placeContent "center" + :height "2.5rem" + :width "2.5rem" + :borderRadius "1000px" + :display "flex" + :top "2rem" + :onClick #(set! (.-value (getElement "athena-input")) nil)} + [:> Close]]) + [results-el state] + [search-results-el @state]]])))) diff --git a/src/cljs/athens/views/blocks/autocomplete_search.cljs b/src/cljs/athens/views/blocks/autocomplete_search.cljs index f9f1332d9e..4109231310 100644 --- a/src/cljs/athens/views/blocks/autocomplete_search.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_search.cljs @@ -1,13 +1,11 @@ (ns athens.views.blocks.autocomplete-search (:require - ["/components/Button/Button" :refer [Button]] - [athens.style :as style] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.dropdown :as dropdown] - [clojure.string :as string] - [goog.events :as events] - [reagent.core :as r] - [stylefy.core :as stylefy])) + ;; ["/components/Button/Button" :refer [Button]] + ["@chakra-ui/react" :refer [Portal Heading Button IconButton MenuDivider MenuButton VStack Box Menu MenuList Text MenuItem]] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [clojure.string :as string] + [goog.events :as events] + [reagent.core :as r])) (defn inline-item-click @@ -30,34 +28,37 @@ (not (.. @ref (contains (.. e -target))))) (swap! state assoc :search/type false))))] (r/create-class - {:display-name "inline-search" - :component-did-mount (fn [_this] (events/listen js/document "mousedown" handle-click-outside)) - :component-will-unmount (fn [_this] (events/unlisten js/document "mousedown" handle-click-outside)) - :reagent-render (fn [block state] - (let [{:search/keys [query results index type] caret-position :caret-position} @state - {:keys [left top]} caret-position] - (when (some #(= % type) [:page :block :hashtag :template]) - [:div (merge (stylefy/use-style dropdown/dropdown-style - {:ref #(reset! ref %) - ;; don't blur textarea when clicking to auto-complete - :on-mouse-down (fn [e] (.. e preventDefault))}) - {:style {:position "absolute" - :max-height "20rem" - :z-index (:zindex-popover style/ZINDICES) - :top (+ 24 top) - :left (+ 24 left)}}) - [:div#dropdown-menu (stylefy/use-style dropdown/menu-style) - (if (or (string/blank? query) - (empty? results)) - ;; Just using button for styling - [:> Button (stylefy/use-style {:opacity (style/OPACITIES :opacity-low)}) (str "Search for a " (symbol type))] - (doall - (for [[i {:keys [node/title block/string block/uid]}] (map-indexed list results)] - [:> Button {:key (str "inline-search-item" uid) - :id (str "dropdown-item-" i) - :is-pressed (= index i) + {:display-name "inline-search" + :component-did-mount (fn [_this] (events/listen js/document "mousedown" handle-click-outside)) + :component-will-unmount (fn [_this] (events/unlisten js/document "mousedown" handle-click-outside)) + :reagent-render (fn [block state] + (let [{:search/keys [query results index type] caret-position :caret-position} @state + {:keys [left top]} caret-position] + (when (some #(= % type) [:page :block :hashtag :template]) + [:> Portal + [:> VStack {:ref #(reset! ref %) + ;; don't blur textarea when clicking to auto-complete + :on-mouse-down (fn [e] (.. e preventDefault)) + :position "absolute" + :overflow "auto" + :p 1 + :align "stretch" + :justify "stretch" + :width "max-content" + :bg "background.upper" + :maxHeight "20rem" + :top (str (+ 24 top) "px") + :left (str (+ 24 left) "px")} + (if (or (string/blank? query) + (empty? results)) + [:> Text (str "Search for a " (symbol type))] + (doall + (for [[i {:keys [node/title block/string block/uid]}] (map-indexed list results)] + [:> Button {:key (str "inline-search-item" uid) + :id (str "dropdown-item-" i) + :width "100%" + :isActive (= index i) ;; if page link, expand to title. otherwise expand to uid for a block ref - :on-click (fn [_] (inline-item-click state (:block/uid block) (or title uid))) - :style {:text-align "left"}} - (or title string)])))]])))}))) + :onClick (fn [_] (inline-item-click state (:block/uid block) (or title uid)))} + (or title string)])))]])))}))) diff --git a/src/cljs/athens/views/blocks/autocomplete_slash.cljs b/src/cljs/athens/views/blocks/autocomplete_slash.cljs index ce80f6be1d..e4c2f3ea71 100644 --- a/src/cljs/athens/views/blocks/autocomplete_slash.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_slash.cljs @@ -1,6 +1,7 @@ (ns athens.views.blocks.autocomplete-slash (:require ["/components/Button/Button" :refer [Button]] + ["@chakra-ui/react" :refer [Portal Heading IconButton MenuDivider MenuButton Menu MenuList MenuItem]] [athens.views.blocks.textarea-keydown :as textarea-keydown] [athens.views.dropdown :as dropdown] [goog.events :as events] @@ -18,11 +19,12 @@ (defn slash-menu-el [_block state] (let [ref (atom nil) + clear-search (swap! state assoc :search/type false) handle-click-outside (fn [e] (let [{:search/keys [type]} @state] (when (and (= type :slash) (not (.. @ref (contains (.. e -target))))) - (swap! state assoc :search/type false))))] + clear-search)))] (r/create-class {:display-name "slash-menu" :component-did-mount (fn [_this] (events/listen js/document "mousedown" handle-click-outside)) @@ -36,13 +38,17 @@ ;; don't blur textarea when clicking to auto-complete :on-mouse-down (fn [e] (.. e preventDefault))}) {:style {:position "absolute" :left (+ left 24) :top (+ top 24)}}) - [:div#dropdown-menu (merge (stylefy/use-style dropdown/menu-style) {:style {:max-height "8em"}}) + [:> Menu {:isOpen true + :isLazy true + :onClose clear-search} + [:> MenuList (doall - (for [[i [text icon _expansion kbd _pos :as item]] (map-indexed list results)] - [:> Button {:key text - :id (str "dropdown-item-" i) - :is-pressed (= i index) - :on-click (fn [_] (slash-item-click state block item))} - [:<> [(r/adapt-react-class icon)] [:span text] (when kbd [:kbd kbd])]]))]])))}))) + (for [[i [text icon _expansion kbd _pos :as item]] (map-indexed list results)] + [:> MenuItem {:key text + :id (str "dropdown-item-" i) + :isActive (= i index) + :command kbd + :onClick (fn [_] (slash-item-click state block item))} + [:<> [(r/adapt-react-class icon)] [:span text]]]))]]])))}))) diff --git a/src/cljs/athens/views/blocks/content.cljs b/src/cljs/athens/views/blocks/content.cljs index 7e4e1c5437..3bb034bed0 100644 --- a/src/cljs/athens/views/blocks/content.cljs +++ b/src/cljs/athens/views/blocks/content.cljs @@ -5,7 +5,6 @@ [athens.db :as db] [athens.events.selection :as select-events] [athens.parse-renderer :refer [parse-and-render]] - [athens.style :as style] [athens.subs.selection :as select-subs] [athens.util :as util] [athens.views.blocks.internal-representation :as internal-representation] @@ -13,11 +12,9 @@ [clojure.edn :as edn] [clojure.set :as set] [clojure.string :as str] - [garden.selectors :as selectors] [goog.events :as goog-events] [komponentit.autosize :as autosize] - [re-frame.core :as rf] - [stylefy.core :as stylefy]) + [re-frame.core :as rf]) (:import (goog.events EventType))) @@ -54,120 +51,58 @@ "& > a" {:position "relative" :zIndex 2 :pointerEvents "all"}} - "span" {:gridArea "main"}}) - - -(def block-content-style - {:display "grid" - :color "foreground.primary" - :grid-template-areas "'main'" - :align-items "stretch" - :justify-content "stretch" - :position "relative" - :overflow "visible" - :z-index 2 - :flex-grow "1" - :word-break "break-word" - ::stylefy/manual [#_ [:textarea {:display "block" - :line-height 0 - :-webkit-appearance "none" - :cursor "text" - :resize "none"}] - #_ [:&:hover [:textarea [(selectors/& (selectors/not :.is-editing)) {:line-height 2}]]] - #_ [:.is-editing {:z-index 3 - :line-height "inherit" - :opacity "1"}] - [:span.text-run - {:pointer-events "None"} - [:>a {:position "relative" - :z-index 2 - :pointer-events "all"}]] - [:span - {:grid-area "main"} - [:>span - :>a {:position "relative" - :z-index 2}]] - [:abbr - {:grid-area "main" - :z-index 4} - [:>span - :>a {:position "relative" - :z-index 2}]] - ;; May want to refactor specific component styles to somewhere else. - ;; Closer to the component perhaps? - ;; Code - [:code :pre {:font-family "IBM Plex Mono"}] - ;; Media Containers - ;; Using a CSS hack/convention here to create a responsive container - ;; of a specific aspect ratio. - ;; TODO: Replace this with the CSS aspect-ratio property once available. - [:.media-16-9 {:height 0 - :width "calc(100% - 0.25rem)" - :z-index 1 - :transform-origin "right center" - :transition "all 0.2s ease" - :padding-bottom (str (* (/ 9 16) 100) "%") - :margin-block "0.25rem" - :margin-inline-end "0.25rem" - :position "relative"}] - ;; Media (YouTube embeds, map embeds, etc.) - [:iframe {:border 0 - :box-shadow [["inset 0 0 0 0.125rem" (style/color :background-minus-1)]] - :position "absolute" - :height "100%" - :width "100%" - :cursor "default" - :top 0 - :right 0 - :left 0 - :bottom 0 - :border-radius "0.25rem"}] - ;; Images - [:img {:border-radius "0.25rem" - :max-width "calc(100% - 0.25rem)"}] - - [:h1 :h2 :h3 :h4 :h5 :h6 {:margin "0" - :color (style/color :body-text-color :opacity-higher) - :font-weight "500"}] - [:h1 {:padding "0" - :margin-block-start "-0.1em"}] - [:h2 {:padding "0"}] - [:h3 {:padding "0"}] - [:h4 {:padding "0.25em 0"}] - [:h5 {:padding "1em 0"}] - [:h6 {:text-transform "uppercase" - :letter-spacing "0.06em" - :padding "1em 0"}] - [:p {:margin "0" - :padding-bottom "1em"}] - [:blockquote {:margin-inline "0.5em" - :margin-block "0.125rem" - :padding-block "calc(0.5em - 0.125rem - 0.125rem)" - :padding-inline "1.5em" - :border-radius "0.25em" - :background (style/color :background-minus-1) - :border-inline-start [["0.25em solid" (style/color :body-text-color :opacity-lower)]] - :color (style/color :body-text-color :opacity-high)} - [:p {:padding-bottom "1em"}] - [:p:last-child {:padding-bottom "0"}]] - [:.CodeMirror {:background (style/color :background-minus-1) - :margin "0.125rem 0.5rem" - :border-radius "0.25rem" - :font-size "85%" - :color (style/color :body-text-color) - :font-family "IBM Plex Mono"}] - [:.CodeMirror-gutters {:border-right "1px solid transparent" - :background (style/color :background-minus-1)}] - [:.CodeMirror-cursor {:border-left-color (style/color :link-color)}] - [:.CodeMirror-lines {:padding 0}] - [:.CodeMirror-linenumber {:color (style/color :body-text-color :opacity-med)}] - - [:mark.contents.highlight {:padding "0 0.2em" - :border-radius "0.125rem" - :background-color (style/color :text-highlight-color)}]]}) - - -(stylefy/class "block-content" block-content-style) + "span" {:gridArea "main" + "& > span" {:position "relative" + :zIndex 2}} + "abbr" {:gridArea "main" + :zIndex 4 + "& > span" {:position "relative" + :zIndex 2}} + "code, pre" {:fontFamily "IBM Plex Mono"} + ".media-16-9" {:height 0 + :width "calc(100% - 0.25rem)" + :zIndex 1 + :transformOrigin "right center" + :transitionDuration "0.2s" + :transitionTimingFunction "ease-in-out" + :transitionProperty "common" + :paddingBottom "56.25%" + :marginBlock "0.25rem" + :marginInlineEnd "0.25rem" + :position "relative"} + "iframe" {:border 0 + :boxShadow "inset 0 0 0 0.125rem" + :position "absolute" + :height "100%" + :width "100%" + :cursor "default" + :top 0 + :right 0 + :left 0 + :bottom 0 + :borderRadius "0.25rem"} + "img" {:borderRadius "0.25rem" + :maxWidth "calc(100% - 0.25rem)"} + "h1" {:fontSize "xl"} + "h2" {:fontSize "lg"} + "h3" {:fontSize "md"} + "h4" {:fontSize "sm"} + "h5" {:fontSize "xs"} + "h6" {:fontSize "xs"} + "blockquote" {:marginInline "0.5em" + :marginBlock "0.125rem" + :paddingBlock "calc(0.5em - 0.125rem - 0.125rem)" + :paddingInline "1.5em" + :borderRadius "0.25em" + :background "background.basement" + :borderInlineStart "1px solid" + :borderColor "separator.divider" + :color "foreground.primary"} + "p" {:paddingBottom "1em" + "&:last-child" {:paddingBottom 0}} + "mark.contents.highlight" {:padding "0 0.2em" + :borderRadius "0.125rem" + :background "highlight"}}) (defn find-selected-items @@ -388,7 +323,7 @@ 2 "1.7em" 3 "1.3em" "1em")] - [:> Box {:class ["block-content"] + [:> Box {:class "block-content" :display "grid" :background "background.floor" :color "foreground.primary" diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index 95db613549..6b5712398e 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -3,6 +3,7 @@ ["/components/Block/components/Anchor" :refer [Anchor]] ["/components/Block/components/Toggle" :refer [Toggle]] ["/components/Button/Button" :refer [Button]] + ["@chakra-ui/react" :refer [Box]] [athens.common.logging :as log] [athens.db :as db] [athens.electron.images :as images] @@ -36,74 +37,63 @@ ;; smaller than main content blocks, for instance. -(def block-container-style - {:display "flex" - :line-height "2em" - :position "relative" - :border-radius "0.125rem" - :justify-content "flex-start" - :flex-direction "column" - ::stylefy/manual [[:&.show-tree-indicator:before {:content "''" - :position "absolute" - :width "1px" - :left "calc(1.375em + 1px)" - :top "2em" - :bottom "0" - :opacity "0" - :transform "translateX(50%)" - :transition "background-color 0.2s ease-in-out, opacity 0.2s ease-in-out" - :background (style/color :border-color)}] - [:&:hover - :&:focus-within [:&.show-tree-indicator:before {:opacity "1"}]] - [:&:after {:content "''" - :z-index -1 - :position "absolute" - :top "0.75px" - :right 0 - :bottom "0.75px" - :left 0 - :opacity 0 - :pointer-events "none" - :border-radius "0.25rem" - :transition "opacity 0.075s ease" - :background (style/color :link-color :opacity-lower)}] - [:&.is-selected:after {:opacity 1}] - [:&.is-presence [:.block-content {:padding-right "1rem"}]] - [:.user-avatar {:position "absolute" - :left "4px" - :top "4px"}] - [:.block-body {:display "grid" - :grid-template-columns "1em 1em 1fr auto" - :grid-template-rows "0 1fr 0" - :grid-template-areas " +(def block-container-inner-style + {"&.show-tree-indicator:before" {:content "''" + :position "absolute" + :width "1px" + :left "calc(1.375em + 1px)" + :top "2em" + :bottom "0" + :opacity "0" + :transform "translateX(50%)" + :transition "background-color 0.2s ease-in-out, opacity 0.2s ease-in-out" + :background "separator.divider"} + "&:hover, &:focus-within.show-tree-indicator:before" {:opacity 1} + "&:after" {:content "''" + :zIndex -1 + :position "absolute" + :top "0.75px" + :right 0 + :bottom "0.75px" + :left 0 + :opacity 0 + :pointerEvents "none" + :borderRadius "0.25rem" + :transition "opacity 0.075s ease" + :background "link"} + "&.is-selected:after" {:opacity 1} + "&.is-presence .block-content" {:padding-right "1rem"} + ".user-avatar" {:position "absolute" + :left "4px" + :top "4px"} + ".block-body" {:display "grid" + :gridTemplateColumns "1em 1em 1fr auto" + :gridTemplateRows "0 1fr 0" + :gridTemplateAreas " 'above above above above' 'toggle bullet content refs' 'below below below below'" - :border-radius "0.5rem" - :position "relative"} - [:&:hover - :&:focus-within ["> .block-toggle" {:opacity "1"}]] - [:button.block-edit-toggle {:position "absolute" - :appearance "none" - :width "100%" - :background "none" - :border 0 - :cursor "text" - :display "block" - :z-index 1 - :top 0 - :right 0 - :bottom 0 - :left 0}]] - [:.block-content {:grid-area "content" - :min-height "1.5em"}] - [:&.is-linked-ref {:background-color (style/color :background-plus-2)}] - ;; Inset child blocks - [:.block-container {:margin-left "2rem" - :grid-area "body"}]]}) - - -(stylefy/class "block-container" block-container-style) + :borderRadius "0.5rem" + :position "relative"} + "&:hover > .block-toggle, + &:focus-within > .block-toggle" {:opacity "1"} + "button.block-edit-toggle" {:position "absolute" + :appearance "none" + :width "100%" + :background "none" + :border 0 + :cursor "text" + :display "block" + :z-index 1 + :top 0 + :right 0 + :bottom 0 + :left 0} + ".block-content" {:gridArea "content" + :minHeight "1.5em"} + "&.is-linked-ref" {:bg "background-attic"} + ".block-container" {:marginLeft "2rem" + :gridArea "body"}}) (def dragging-style @@ -441,26 +431,32 @@ (when (not= string (:string/previous @state)) (swap! state assoc :string/previous string :string/local string)) - [:div - {:class ["block-container" - (when (and dragging (not is-selected)) "dragging") - (when is-editing "is-editing") - (when is-selected "is-selected") - (when (and (seq children) open) "show-tree-indicator") - (when (and (false? initial-open) (= uid linked-ref-uid)) "is-linked-ref") - (when is-presence "is-presence")] - :data-uid uid + [:> Box {:display "flex" + :line-height "2em" + :position "relative" + :border-radius "0.125rem" + :justify-content "flex-start" + :flex-direction "column" + :sx block-container-inner-style + :class ["block-container" + (when (and dragging (not is-selected)) "dragging") + (when is-editing "is-editing") + (when is-selected "is-selected") + (when (and (seq children) open) "show-tree-indicator") + (when (and (false? initial-open) (= uid linked-ref-uid)) "is-linked-ref") + (when is-presence "is-presence")] + :data-uid uid ;; need to know children for selection resolution - :data-childrenuids children-uids + :data-childrenuids children-uids ;; :show-editable-dom allows us to render the editing elements (like the textarea) ;; even when not editing this block. When true, clicking the block content will pass ;; the clicks down to the underlying textarea. The textarea is expensive to render, ;; so we avoid rendering it when it's not needed. - :on-mouse-enter #(swap! state assoc :show-editable-dom true) - :on-mouse-leave #(swap! state assoc :show-editable-dom false) - :on-drag-over (fn [e] (block-drag-over e block state)) - :on-drag-leave (fn [e] (block-drag-leave e block state)) - :on-drop (fn [e] (block-drop e block state))} + :on-mouse-enter #(swap! state assoc :show-editable-dom true) + :on-mouse-leave #(swap! state assoc :show-editable-dom false) + :on-drag-over (fn [e] (block-drag-over e block state)) + :on-drag-leave (fn [e] (block-drag-leave e block state)) + :on-drop (fn [e] (block-drop e block state))} (when (= (:drag-target @state) :before) [drop-area-indicator/drop-area-indicator {:grid-area "above"}]) diff --git a/src/cljs/athens/views/blocks/textarea_keydown.cljs b/src/cljs/athens/views/blocks/textarea_keydown.cljs index 8bf9963d3e..4a750adce7 100644 --- a/src/cljs/athens/views/blocks/textarea_keydown.cljs +++ b/src/cljs/athens/views/blocks/textarea_keydown.cljs @@ -813,10 +813,19 @@ ;; used for paste, to determine if shift key was held down (swap! state assoc :last-keydown d-event) + (js/console.log @state) + ;; update caret position for search dropdowns and for up/down (when (nil? (:search/type @state)) - (let [caret-position (get-caret-position (.. e -target))] - (swap! state assoc :caret-position caret-position))) + (let [caret-position (get-caret-position (.. e -target)) + textarea-position (js/getClientBoundingRect (.. e -target)) + position {:left (+ (:left caret-position) (:x textarea-position)) + :top (+ (:top caret-position) (:y textarea-position))}] + + (js/console.log "caret-position", caret-position) + (js/console.log "textarea-position", textarea-position) + (js/console.log "position", position) + (swap! state assoc :caret-position position))) ;; dispatch center ;; only when nothing is selected or duplicate/events dispatched diff --git a/src/cljs/athens/views/dropdown.cljs b/src/cljs/athens/views/dropdown.cljs index a49d9e6ddb..559ad4cab8 100644 --- a/src/cljs/athens/views/dropdown.cljs +++ b/src/cljs/athens/views/dropdown.cljs @@ -56,74 +56,3 @@ :overflow "hidden" :text-overflow "ellipsis"}) - -(def menu-separator-style - {:border "0" - :background (color :border-color) - :align-self "stretch" - :justify-self "stretch" - :height "1px" - :margin "0.25rem 0"}) - - -#_(def submenu-indicator-style - {:margin-left "auto" - :opacity "0.5" - :display "flex" - :order 10 - :align-self "flex-end" - :font-family "inherit" - ::stylefy/manual [[:&:last-child {:padding-inline-end "0"}]]}) - - -;; Components -;; -;; -;; (defn block-context-menu-component -;; [style] -;; [dropdown {:style style :content -;; [menu {:content -;; [:<> -;; ;; [menu-heading "Modify Block 'Day of Datomic On-Prem 2016'"] -;; ;; [textinput {:icon [:> Face] :placeholder "Type to filter"}] -;; [:> Button [:<> [:> Link] [:span "Copy Page Reference"]]] -;; [:> Button [:<> [:> Star] [:span "Add to Shortcuts"]]] -;; [:> Button [:<> [:> Face] [:span "Add Reaction"] [submenu-indicator]]] -;; [menu-separator] -;; [:> Button [:<> [:> LastPage] [:span "Open in Sidebar"] [:kbd "shift-click"]]] -;; [:> Button [:<> [:> Launch] [:span "Open in New Window"] [:kbd "ctrl-o"]]] -;; [:> Button [:<> [:> UnfoldMore] [:span "Expand All"]]] -;; [:> Button [:<> [:> UnfoldLess] [:span "Collapse All"]]] -;; [:> Button [:<> [:> Slideshow] [:span "View As"] [submenu-indicator]]] -;; [menu-separator] -;; [:> Button [:<> [:> FileCopy] [:span "Duplicate and Break Links"]]] -;; [:> Button [:<> [:> LibraryAdd] [:span "Save as Template"]]] -;; [:> Button [:<> [:> History] [:span "Browse Versions"]]] -;; [:> Button [:<> [:> CloudDownload] [:span "Export As"]]]]}]}]) -;; -;; -;; (def items -;; {"Amet" {:count 6 :state :added} -;; "At" {:count 130 :state :excluded} -;; "Diam" {:count 6} -;; "Donec" {:count 6} -;; "Elit" {:count 30} -;; "Elitudomin mesucen defibocutruon" {:count 1} -;; "Erat" {:count 11} -;; "Est" {:count 2} -;; "Eu" {:count 2} -;; "Ipsum" {:count 2 :state :excluded} -;; "Magnis" {:count 10 :state :added} -;; "Metus" {:count 29} -;; "Mi" {:count 7 :state :added} -;; "Quam" {:count 1} -;; "Turpis" {:count 97} -;; "Vitae" {:count 1}}) -;; -;; -;; (defn filter-dropdown-component -;; [] -;; [dropdown {:style {:width "20em" :height "20em"} -;; :content [:<> -;; [menu-heading "Filters"] -;; [filters-el "((some-uid))" items]]}]) diff --git a/src/cljs/athens/views/help.cljs b/src/cljs/athens/views/help.cljs index 1d22b089fa..ac20b4ba92 100644 --- a/src/cljs/athens/views/help.cljs +++ b/src/cljs/athens/views/help.cljs @@ -1,34 +1,31 @@ (ns athens.views.help (:require - ["@material-ui/core/Modal" :default Modal] - [athens.style :refer [color]] - [athens.util :as util] - [clojure.string :as str] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]]) - (:import - (goog.events - KeyCodes))) + ["@chakra-ui/react" :refer [Text Heading Box Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] + [athens.util :as util] + [clojure.string :as str] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Helpers to create the help content ;; ========================== -(defn opaque-text +(defn faded-text [text] - [:span (use-style {:color (color :body-text-color :opacity-med) - :font-weight "normal"}) + [:> Text {:as "span" + :color "foreground.secondary" + :fontWeight "normal"} text]) (defn space [] - [:i (use-style {:width "0.25em" - :display "inline-block" - :margin-inline "0.25em" - :height "0.125em" - :border (str "1px solid " (color :body-text-color :opacity-low)) - :border-top 0})]) + [:> Box {:as "i" + :width "0.5em" + :display "inline-block" + :marginInline "0.125em" + :background "currentColor" + :height "1px" + :opacity "0.5"}]) (defn- add-keys @@ -41,7 +38,7 @@ (defn example [template & args] - (let [opaque-texts (map #(r/as-element [opaque-text %]) args) + (let [faded-texts (map #(r/as-element [faded-text %]) args) space-component (r/as-element [space]) insert-spaces (fn [str-or-vec] (if (and (string? str-or-vec) @@ -52,17 +49,16 @@ (interleave (repeat space-component)) add-keys)) str-or-vec))] - [:span (use-style - {:font-size "85%" - :font-weight "bold" - :user-select "all" - :word-break "break-word"}) + [:> Text {:fontSize "85%" + :fontWeight "bold" + :userSelect "all" + :wordBreak "break-word"} (as-> template t - (str/split t #"\$text") - (interleave t (concat opaque-texts [nil])) - (map insert-spaces t) - (add-keys t) - (into [:<>] t))])) + (str/split t #"\$text") + (interleave t (concat faded-texts [nil])) + (map insert-spaces t) + (add-keys t) + (into [:<>] t))])) ;; Help content @@ -181,13 +177,15 @@ ;; :example [:span (use-style {:text-decoration "underline"}) "Athens"] ;; :shortcut "mod+u"} {:description "Strikethrough" - :example [:span (use-style {:text-decoration "line-through"}) "Athens"] + :example [:> Text {:as "span" :textDecoration "line-through"} "Athens"] :shortcut "mod+y"} {:description "Highlight" - :example [:span (use-style {:background (color :highlight-color) - :color (color :background-color) - :border-radius "0.1rem" - :padding "0 0.125em"}) "Athens"] + :example [:> Text {:as "span" + :background "highlight" + :color "highlightContrast" + :borderRadius "0.1rem" + :padding "0 0.125em"} + "Athens"] :shortcut "mod+h"}]} {:name "Graph" :items [{:description "Open Node in Sidebar" @@ -225,111 +223,76 @@ (str/replace #"minus" "-") (str/replace #"plus" "+"))) keys (as-> shortcut-str s - (str/split s #"\+") - (map key-to-display s))] - [:div (use-style {:display "flex" - :align-items "center" - :gap "0.3rem"}) + (str/split s #"\+") + (map key-to-display s))] + [:> Box {:display "flex" + :alignItems "center" + :gap "0.3rem"} (doall - (for [key keys] - ^{:key key} - [:span (use-style {:font-family "inherit" - :display "inline-flex" - :gap "0.3em" - :text-transform "uppercase" - :font-size "0.8em" - :padding-inline "0.35em" - :background (color :background-plus-2) - :border-radius "0.25rem" - :font-weight 600}) - key]))])) - - -(def modal-body-styles - {:width "max-content" - :margin "2rem auto" - :max-width "calc(100% - 1rem)" - :border (str "1px solid " (color :border-color)) - :border-radius "1rem" - :box-shadow (str "0 0.25rem 0.5rem -0.25rem " (color :shadow-color)) - :display "flex"}) - - -(def help-styles - {:background-color (color :background-color) - :border-radius "1rem" - :display "flex" - :flex-direction "column" - :min-width "500px"}) - - -(def help-header-styles - {:display "flex" - :justify-content "space-between" - :margin 0 - :align-items "center" - :border-bottom [["1px solid" (color :border-color)]]}) - - -(def help-title - {:padding "1rem 1.5rem" - :margin "0" - :font-size "2rem" - :color (color :header-text-color)}) - + (for [key keys] + ^{:key key} + [:> Text {:fontFamily "inherit" + :display "inline-flex" + :gap "0.3em" + :textTransform "uppercase" + :fontSize "0.8em" + :paddingInline "0.35em" + :background "background.basement" + :borderRadius "0.25rem" + :fontWeight 600} + key]))])) (defn help-section [title & children] - [:section - [:h2 (use-style - {:color (color :body-text-color :opacity-med) - :text-transform "uppercase" - :letter-spacing "0.06rem" - :margin 0 - :font-weight 600 - :font-size "100%" - :padding "1rem 1.5rem"}) + [:> Box {:as "section"} + [:> Heading {:as "h2" + :color "foreground.primary" + :textTransform "uppercase" + :letterSpacing "0.06rem" + :margin 0 + :font-weight 600 + :font-size "100%" + :padding "1rem 1.5rem"} title] (doall - (for [child children] - ^{:key (hash child)} - child))]) + (for [child children] + ^{:key (hash child)} + child))]) (defn help-section-group [title & children] - [:section (use-style - {:display "grid" - :padding "1.5rem" - :grid-template-columns "12rem 1fr" - :column-gap "1rem" - :border-top [["1px solid" (color :border-color)]]}) - [:h3 (use-style {:font-size "1.5em" - :margin 0 - :font-weight "bold"}) + [:> Box {:display "grid" + :padding "1.5rem" + :gridTemplateColumns "12rem 1fr" + :columnGap "1rem" + :borderTop "1px solid" + :borderColor "separator.border"} + [:> Heading {:fontSize "1.5em" + :as "h3" + :margin 0 + :font-weight "bold"} title] [:div (doall - (for [child children] - ^{:key (hash child)} - child))]]) + (for [child children] + ^{:key (hash child)} + child))]]) (defn help-item [item] - [:div (use-style - {:border-radius "0.5rem" - :align-items "center" - :display "grid" - :gap "1rem" - :grid-template-columns "12rem 1fr" - :padding "0.25rem 0.5rem" - ::stylefy/manual ["&:nth-child(odd)" - {:background (color :background-plus-2 :opacity-low)}]}) - [:span (use-style - {:display "flex" - :justify-content "space-between"}) + [:> Box {:borderRadius "0.5rem" + :alignItems "center" + :display "grid" + :gap "1rem" + :gridTemplateColumns "12rem 1fr" + :padding "0.25rem 0.5rem" + :sx {"&:nth-child(odd)" + {:bg "background.floor"}}} + [:> Text {:display "flex" + :justify-content "space-between"} ;; Position of the example changes if there is a shortcut or not. (:description item) (when (contains? item :shortcut) @@ -349,47 +312,29 @@ (defn help-popup [] (r/with-let [open? (subscribe [:help/open?]) - close #(dispatch [:help/toggle]) - escape-handler (fn [event] - (when - (and @open? (= (.. event -keyCode) KeyCodes.ESC)) - (close))) - _ (js/addEventListener "keydown" escape-handler)] - [:> Modal {:open @open? - :style {:overflow-y "auto"} - :disableAutoFocus true - :onClose close} - [:div (use-style modal-body-styles) - [:div (use-style help-styles) - [:header (use-style help-header-styles) - [:h1 (use-style help-title) - "Help"] - [:nav (use-style {:display "flex" - :gap "1rem" - :padding "1rem"})]] - ;; Links at the top of the help. Uncomment when the correct links are obtained. - ;; [help-link - ;; [:> LiveHelp] - ;; "Get Help on Discord"] - ;; [help-link - ;; [:> Error] - ;; "Get Help on Discord"] - ;; [help-link - ;; [:> AddToPhotos] - ;; "Get Help on Discord"]]] - [:div (use-style {:overflow-y "auto"}) - (doall - (for [section content] - ^{:key section} - [help-section (:name section) - (doall - (for [group (:groups section)] - ^{:key group} - [help-section-group (:name group) - (doall - (for [item (:items group)] - ^{:key item} - [help-item item]))]))]))]]]] - (finally js/removeEventListener "keydown" escape-handler))) + close #(dispatch [:help/toggle])] + [:> Modal {:isOpen @open? + :onClose close + :scrollBehavior "outside" + :size "full"} + [:> ModalOverlay] + [:> ModalContent {:maxWidth "calc(100% - 8rem)" + :width "max-content" + :my "4rem"} + [:> ModalHeader "Help" + [:> ModalCloseButton]] + [:> ModalBody {:flexDirection "column"} + (doall + (for [section content] + ^{:key section} + [help-section (:name section) + (doall + (for [group (:groups section)] + ^{:key group} + [help-section-group (:name group) + (doall + (for [item (:items group)] + ^{:key item} + [help-item item]))]))]))]]])) diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index f885afcb15..7454d87b36 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -1,6 +1,6 @@ (ns athens.views.left-sidebar (:require - ["@chakra-ui/react" :refer [VStack HStack Heading Button Link Flex Box]] + ["@chakra-ui/react" :refer [VStack HStack Heading Button Link Flex]] ["framer-motion" :refer [AnimatePresence motion]] [athens.reactive :as reactive] [athens.router :as router] @@ -30,18 +30,20 @@ :flex "1" :border "none" :justifyContent "flex-start" - :bg "background.floor" + :bg "transparent" :boxShadow "0 0 0 0.25rem transparent" :_focus {:outline "none"} :_hover {:bg "background.upper"} - :onClick (fn [e] - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :left-sidebar - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page title e))) + :_active {:bg "background.attic" + :transitionDuration "0s"} + :on-click (fn [e] + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :left-sidebar + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page title e))) :draggable true :on-drag-over (fn [e] (.. e preventDefault) @@ -88,6 +90,7 @@ :paddingBottom "2rem" :alignItems "stretch" :gridArea "left-sidebar" + :position "relative" :overflow "hidden"} :initial {:width 0 :opacity 0} @@ -104,11 +107,12 @@ :spacing "0.25rem" :overflowY "overlay" :sx {:listStyle "none"}} + [:> Heading {:as "h2" :px "2rem" - :pb "1rem" - :size "md" - :color "feature.secondary"} + :pb "0.5rem" + :size "sm" + :color "foreground.secondary"} "Shortcuts"] (doall (for [sh shortcuts] @@ -118,6 +122,7 @@ ;; LOGO + BOTTOM BUTTONS [:> HStack {:as "footer" :width expanded-sidebar-width + :fontSize "sm" :px "2rem" :mt "auto"} [:> Link {:fontWeight "bold" diff --git a/src/cljs/athens/views/modal.cljs b/src/cljs/athens/views/modal.cljs deleted file mode 100644 index ded8914e85..0000000000 --- a/src/cljs/athens/views/modal.cljs +++ /dev/null @@ -1,46 +0,0 @@ -(ns athens.views.modal - (:require - [athens.db] - [athens.style :refer [color ZINDICES DEPTH-SHADOWS]] - [garden.selectors :as selectors] - [stylefy.core :as stylefy])) - - -;; Styles - -(def modal-style - {:z-index (:zindex-modal ZINDICES) - :animation "fade-in 0.2s" - :position "relative" - ::stylefy/manual [[:.modal {:position "fixed" - :top "50vh" - :left "50vw" - :transform "translate(-50%, -50%)" - :border-radius "0.5rem" - :display "flex" - :flex-direction "column" - :background-clip "padding-box" - :background (color :background-plus-1) - :box-shadow [[(:64 DEPTH-SHADOWS) ", 0 0 0 1px " (color :body-text-color :opacity-low)]]}] - [:modal__header {:display "contents"}] ; Deactivate layout on the default header - [(selectors/> :.modal__header :button) {:display "none"}] ; Hide default close button - [:.modal__title :.modal__footer {:flex "0 0 auto" - :padding "0.25rem 1rem" - :display "flex" - :align-items "center"} - [:&:empty {:display "none"}]] - [:.modal__title {:padding-right "0.75rem"} - [(selectors/+ :svg :h4) {:margin-inline-start "0.5rem"}] - [:button {:margin-inline-start "auto" - :align-self "flex-start" - :margin-block "0.5rem"}]] - [:.modal__content {:flex "1 1 100%" - :overflow-y "auto"}] - [:.modal__footer {:display "flex"}] - [:.modal__backdrop {:position "fixed" - :top 0 - :left 0 - :background "rgba(0,0,0,0.1)" - :z-index -1 - :width "100vw" - :height "100vh"}]]}) diff --git a/src/cljs/athens/views/pages/all_pages.cljs b/src/cljs/athens/views/pages/all_pages.cljs index 938fe357a6..7979fc4160 100644 --- a/src/cljs/athens/views/pages/all_pages.cljs +++ b/src/cljs/athens/views/pages/all_pages.cljs @@ -1,6 +1,6 @@ (ns athens.views.pages.all-pages (:require - ["@chakra-ui/react" :refer [Table Thead Tr Th Tbody Td Button]] + ["@chakra-ui/react" :refer [Table Thead Tr Th Tbody Td Button Box]] ["@material-ui/icons/ArrowDropDown" :default ArrowDropDown] ["@material-ui/icons/ArrowDropUp" :default ArrowDropUp] [athens.common-db :as common-db] @@ -63,18 +63,19 @@ ;; Components (defn- sortable-header - ([column-id label width] + ([column-id label width isNumeric] (let [sorted-by @(rf/subscribe [:all-pages/sorted-by]) growing? @(rf/subscribe [:all-pages/sort-order-ascending?])] - [:> Th {:width width} + [:> Th {:width width :isNumeric isNumeric} [:> Button {:onClick #(rf/dispatch [:all-pages/sort-by column-id]) :size "sm" :variant "link"} - label + (when-not isNumeric label) (when (= sorted-by column-id) (if growing? [:> ArrowDropUp] - [:> ArrowDropDown]))]]))) + [:> ArrowDropDown])) + (when isNumeric label)]]))) (defn page @@ -82,35 +83,34 @@ (let [all-pages (common-db/get-all-pages @db/dsdb)] (fn [] (let [sorted-pages @(rf/subscribe [:all-pages/sorted all-pages])] + [:> Box {:px 4 + :margin "5rem auto"} [:> Table {:variant "striped" - :margin "5rem auto" - :border "2rem solid transparent" - :flex-basis "100%" :max-width "70rem"} [:> Thead [:> Tr [sortable-header :title "Title"] - [sortable-header :links-count "Links" :width "10rem"] - [sortable-header :modified "Modified" {:date? true} :width "20rem"] - [sortable-header :created "Created" {:date? true} :width "20rem"]]] + [sortable-header :links-count "Links" "12rem" true] + [sortable-header :modified "Modified" "20rem" false {:date? true}] + [sortable-header :created "Created" "20rem" false {:date? true}]]] [:> Tbody (doall - (for [{:keys [block/uid node/title block/_refs] - modified :edit/time - created :create/time} sorted-pages] - [:> Tr {:key uid} - [:> Td - [:> Button {:variant "link" - :color "link" - :onClick (fn [e] - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :all-pages - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page title e)))} - title]] - [:> Td {:color "foreground.secondary"} (count _refs)] - [:> Td {:color "foreground.secondary"} (dates/date-string modified)] - [:> Td {:color "foreground.secondary"} (dates/date-string created)]]))]])))) + (for [{:keys [block/uid node/title block/_refs] + modified :edit/time + created :create/time} sorted-pages] + [:> Tr {:key uid} + [:> Td + [:> Button {:variant "link" + :color "link" + :onClick (fn [e] + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :all-pages + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page title e)))} + title]] + [:> Td {:width "12rem" :color "foreground.secondary" :isNumeric true} (count _refs)] + [:> Td {:width "18rem" :color "foreground.secondary"} (dates/date-string modified)] + [:> Td {:width "18rem" :color "foreground.secondary"} (dates/date-string created)]]))]]])))) diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index 40065158a5..85511bb94f 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -1,18 +1,19 @@ (ns athens.views.pages.block-page (:require - ["@material-ui/icons/Link" :default Link] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.style :refer [color]] - [athens.views.blocks.core :as blocks] - [athens.views.breadcrumbs :refer [breadcrumbs-list breadcrumb]] - [athens.views.pages.node-page :as node-page] - [garden.selectors :as selectors] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]])) + ["@chakra-ui/react" :refer [Heading IconButton Menu MenuList MenuItem]] + ["@material-ui/icons/Link" :default Link] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.style :refer [color]] + [athens.views.blocks.core :as blocks] + [athens.views.breadcrumbs :refer [breadcrumbs-list breadcrumb]] + [athens.views.pages.node-page :as node-page] + [garden.selectors :as selectors] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r] + [stylefy.core :as stylefy :refer [use-style]])) ;; Styles @@ -150,17 +151,17 @@ [parents-el uid id] ;; Header - [:h1 (merge - (use-style title-style {:data-uid uid :class "block-header"}) - {:on-click (fn [e] - (.. e preventDefault) - (if (.. e -shiftKey) - (do - (rf/dispatch [:reporting/navigation {:source :block-page - :target :block - :pane :right-pane}]) - (router/navigate-uid uid e)) - (dispatch [:editing/uid uid])))}) + [:> Heading {:size "lg" + :_hover {:textDecoration "underline"} + :onClick (fn [e] + (.. e preventDefault) + (if (.. e -shiftKey) + (do + (rf/dispatch [:reporting/navigation {:source :block-page + :target :block + :pane :right-pane}]) + (router/navigate-uid uid e)) + (dispatch [:editing/uid uid])))} [autosize/textarea {:id (str "editable-uid-" uid) :value (:string/local @state) diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index 6b162b9c8d..5dbf6cba1e 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -1,5 +1,6 @@ (ns athens.views.pages.daily-notes (:require + ["@chakra-ui/react" :refer [Heading Box]] [athens.dates :as dates] [athens.reactive :as reactive] [athens.style :refer [DEPTH-SHADOWS]] @@ -60,7 +61,30 @@ (for [{:keys [block/uid]} notes] ^{:key uid} [:<> - [:div (use-style daily-notes-page-style) + [:> Box {:boxShadow "page", + :bg "background.floor" + :alignSelf "stretch" + :justifySelf "stretch" + :margin "1.25rem 2.5rem" + :padding "1rem 2rem" + :borderWidth "1px" + :borderStyle "solid" + :borderColor "separator.divider" + :transitionDuration "0s" + :borderRadius "0.5rem" + :minHeight "calc(100vh - 10rem)"} [node-page/page [:block/uid uid]]]])) - [:div (use-style daily-notes-notional-page-style) - [:h1 "Earlier"]]]))))) + [:> Box {:boxShadow "page", + :bg "background.floor" + :alignSelf "stretch" + :justifySelf "stretch" + :margin "1.25rem 2.5rem" + :padding "1rem 2rem" + :borderWidth "1px" + :borderStyle "solid" + :borderColor "separator.divider" + :transitionDuration "0s" + :borderRadius "0.5rem" + :minHeight "calc(100vh - 10rem)" + :opacity "0.5"} + [:> Heading {:ml 10} "Earlier"]]]))))) diff --git a/src/cljs/athens/views/pages/graph.cljs b/src/cljs/athens/views/pages/graph.cljs index 0b872ff53b..c19457967d 100644 --- a/src/cljs/athens/views/pages/graph.cljs +++ b/src/cljs/athens/views/pages/graph.cljs @@ -325,9 +325,9 @@ graph-conf @(subscribe [:graph/conf]) graph-ref (get @graph-ref-map (or local-node-eid :global))] ;; set canvas dimensions - (swap! dimensions assoc :width (-> dom-node (.. (closest ".graph-page")) + (swap! dimensions assoc :width (-> dom-node (.. (closest "#app")) .-parentNode .-clientWidth)) - (swap! dimensions assoc :height (-> dom-node (.. (closest ".graph-page")) + (swap! dimensions assoc :height (-> dom-node (.. (closest "#app")) .-parentNode .-clientHeight)) ;; set init forces for graph (when graph-ref @@ -491,6 +491,10 @@ :db/id))] [:div.graph-page {:style (merge (when local-node-eid {:min-height "500px"}) - {:position "relative"})} - [graph-controls local-node-eid] + {:position "fixed" + :top 0 + :left 0 + :width "100vw" + :height "100vh"})} + #_ [graph-controls local-node-eid] [graph-root local-node-eid]]))) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index e2fa358cb1..9d307500ed 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -3,6 +3,7 @@ ["/components/Block/components/Anchor" :refer [Anchor]] ["/components/Button/Button" :refer [Button]] ["/components/Dialog/Dialog" :refer [Dialog]] + ["@chakra-ui/react" :refer [Portal Heading IconButton MenuDivider MenuButton Menu MenuList MenuItem]] ["@material-ui/core/Popover" :as Popover] ["@material-ui/icons/Bookmark" :default Bookmark] ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] @@ -25,11 +26,9 @@ [athens.views.blocks.core :as blocks] [athens.views.blocks.textarea-keydown :as textarea-keydown] [athens.views.breadcrumbs :refer [breadcrumbs-list breadcrumb]] - [athens.views.dropdown :refer [menu-style menu-separator-style]] [athens.views.hoc.perf-mon :as perf-mon] [clojure.string :as str] [datascript.core :as d] - [garden.selectors :as selectors] [komponentit.autosize :as autosize] [re-frame.core :as rf :refer [dispatch subscribe]] [reagent.core :as r] @@ -43,11 +42,6 @@ ;; --- material ui --- -(def m-popover (r/adapt-react-class (.-default Popover))) - - -;; Styles - (def page-style {:margin "2rem auto" @@ -56,57 +50,39 @@ :max-width "55rem"}) -(def dropdown-style - {::stylefy/manual [[:.menu {:background (color :background-plus-2) - :color (color :body-text-color) - :border-radius "calc(0.25rem + 0.25rem)" ; Button corner radius + container padding makes "concentric" container radius - :padding "0.25rem" - :display "inline-flex" - :box-shadow [[(:64 DEPTH-SHADOWS) ", 0 0 0 1px rgba(0, 0, 0, 0.05)"]]}]]}) - - (def page-header-style {:position "relative"}) -(def title-style - {:position "relative" - :overflow "visible" - :flex-grow "1" - :margin "0.10em 0 0.10em 1rem" - :letter-spacing "-0.03em" - :white-space "pre-line" - :word-break "break-word" - :line-height "1.40em" - ::stylefy/manual [[:textarea {:-webkit-appearance "none" - :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :font-weight "inherit" - :padding "0" - :letter-spacing "inherit" - :width "100%" - :min-height "100%" - :caret-color (color :link-color) - :background "transparent" - :margin "0" - :font-size "inherit" - :line-height "inherit" - :border-radius "0.25rem" - :transition "opacity 0.15s ease" - :border "0" - :font-family "inherit" - :visibility "hidden" - :position "absolute"}] - [:textarea ["::-webkit-scrollbar" {:display "none"}]] - [:textarea:focus - :.is-editing {:outline "none" - :visibility "visible" - :position "relative"}] - [:abbr {:z-index 4}] - [(selectors/+ :.is-editing :span) {:visibility "hidden" - :position "absolute"}]]}) +(def title-inner-style + {"textarea" {:appearance "none" + :cursor "text" + :resize "none" + :transform "translate3d(0,0,0)" + :color "inherit" + :fontWeight "inherit" + :padding "0" + :letterSpacing "inherit" + :width "100%" + :minHeight "100%" + :caretColor "link" + :background "transparent" + :margin "0" + :fontSize "inherit" + :lineHeight "inherit" + :borderRadius "0.25rem" + :transition "opacity 0.15s ease" + :border "0" + :fontFamily "inherit" + :visibility "hidden" + :position "absolute"} + ["textarea" ["::-webkit-scrollbar" {:display "none"}]] + [".is-editing textarea:focus" {:outline "none" + :visibility "visible" + :position "relative"}] + "abbr" {:z-index 4} + ".is-editing span" {:visibility "hidden" + :position "absolute"}}) (def references-style {:margin-top "3em"}) @@ -154,15 +130,6 @@ :margin-block-start "0"}]]}) -(def page-menu-toggle-style - {:position "absolute" - :left "-1.5rem" - :border-radius "1000px" - :padding "0.375rem 0.5rem" - :color (color :body-text-color :opacity-high) - :transform "translateY(-50%)" - :top "50%"}) - ;; Helpers @@ -335,54 +302,48 @@ (defn menu-dropdown [node daily-note?] (let [{:block/keys [uid] sidebar :page/sidebar title :node/title} node] - (r/with-let [ele (r/atom nil)] - [:<> - [:> Button {:class [(when @ele "is-active")] - :on-click #(reset! ele (.-currentTarget %)) - :style page-menu-toggle-style} - [:> MoreHoriz]] - [m-popover - (merge (use-style dropdown-style) - {:style {:font-size "14px"} - :open (boolean @ele) - :anchorEl @ele - :onClose #(reset! ele nil) - :anchorOrigin #js{:vertical "bottom" - :horizontal "left"} - :marginThreshold 10 - :transformOrigin #js{:vertical "top" - :horizontal "left"} - :classes {:root "backdrop" - :paper "menu"}}) - [:div (use-style menu-style) - [:<> - (if sidebar - [:> Button {:on-click #(dispatch [:left-sidebar/remove-shortcut title])} - [:> BookmarkBorder] - [:span "Remove Shortcut"]] - [:> Button {:on-click #(dispatch [:left-sidebar/add-shortcut title])} - [:> Bookmark] - [:span "Add Shortcut"]]) - [:> Button {:on-click #(dispatch [:right-sidebar/open-item uid true])} - [:> BubbleChart] - [:span "Show Local Graph"]]] - [:hr (use-style menu-separator-style)] - [:> Button {:on-click (fn [] + [:> Menu + [:> MenuButton {:as IconButton + :position "absolute" + :bg "transparent" + :height "2.5rem" + :width "2.5rem" + :right "100%" + :top "0.35rem" + :borderRadius "full" + :sx {"span" {:display "contents"} + "button svg:first-child" {:marginRight "0.25rem"}}} + [:> MoreHoriz]] + [:> Portal + [:> MenuList {:sx {"button svg:first-child" {:marginRight "0.25rem"}}} + [:<> + (if sidebar + [:> MenuItem {:onClick #(dispatch [:left-sidebar/remove-shortcut title])} + [:> BookmarkBorder] + [:span "Remove Shortcut"]] + [:> MenuItem {:onClick #(dispatch [:left-sidebar/add-shortcut title])} + [:> Bookmark] + [:span "Add Shortcut"]]) + [:> MenuItem {:onClick #(dispatch [:right-sidebar/open-item uid true])} + [:> BubbleChart] + [:span "Show Local Graph"]]] + [:> MenuDivider] + [:> MenuItem {:onClick (fn [] ;; if page being deleted is in right sidebar, remove from right sidebar - (when (contains? @(subscribe [:right-sidebar/items]) uid) - (dispatch [:right-sidebar/close-item uid])) + (when (contains? @(subscribe [:right-sidebar/items]) uid) + (dispatch [:right-sidebar/close-item uid])) ;; if page being deleted is open, navigate to all pages - (when (or (= @(subscribe [:current-route/page-title]) title) - (= @(subscribe [:current-route/uid]) uid)) - (rf/dispatch [:reporting/navigation {:source :page-title-delete - :target :all-pages - :pane :main-pane}]) - (router/navigate :pages)) + (when (or (= @(subscribe [:current-route/page-title]) title) + (= @(subscribe [:current-route/uid]) uid)) + (rf/dispatch [:reporting/navigation {:source :page-title-delete + :target :all-pages + :pane :main-pane}]) + (router/navigate :pages)) ;; if daily note, delete page and remove from daily notes, otherwise just delete page - (if daily-note? - (dispatch [:daily-note/delete uid title]) - (dispatch [:page/delete title])))} - [:> Delete] [:span "Delete Page"]]]]]))) + (if daily-note? + (dispatch [:daily-note/delete uid title]) + (dispatch [:page/delete title])))} + [:> Delete] [:span "Delete Page"]]]]])) (defn ref-comp @@ -530,6 +491,7 @@ "Link"])]))]))])]))) + ;; TODO: where to put page-level link filters? (defn node-page-el "title/initial is the title when a page is first loaded. @@ -569,25 +531,33 @@ ;; Dropdown [menu-dropdown node daily-note?] - [:h1 (use-style title-style - {:data-uid uid - :class "page-header" - :on-click (fn [e] - (let [shift? (.-shiftKey e)] - (.. e preventDefault) - (if (or daily-note? shift?) - (do - (rf/dispatch [:reporting/navigation {:source :page-title ; NOTE: this might be also used in right-pane situation - :target (if title - :page - :block) - :pane (if shift? - :right-pane - :main-pane)}]) - (if title - (router/navigate-page title e) - (router/navigate-uid uid e))) - (dispatch [:editing/uid uid]))))}) + [:> Heading {:data-uid uid + :class "page-header" + :position "relative" + :overflow "visible" + :flex-grow "1" + :margin "0.10em 0 0.10em 1rem" + :letter-spacing "-0.03em" + :white-space "pre-line" + :word-break "break-word" + :line-height "1.40em" + :sx title-inner-style + :onClick (fn [e] + (let [shift? (.-shiftKey e)] + (.. e preventDefault) + (if (or daily-note? shift?) + (do + (rf/dispatch [:reporting/navigation {:source :page-title ; NOTE: this might be also used in right-pane situation + :target (if title + :page + :block) + :pane (if shift? + :right-pane + :main-pane)}]) + (if title + (router/navigate-page title e) + (router/navigate-uid uid e))) + (dispatch [:editing/uid uid]))))} ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index e22c439257..a26b9c9252 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,22 +1,22 @@ (ns athens.views.right-sidebar (:require - ["@chakra-ui/react" :refer [VStack HStack Heading Link Flex Box]] - ["framer-motion" :refer [AnimatePresence motion]] - ["/components/Button/Button" :refer [Button]] - ["@material-ui/icons/BubbleChart" :default BubbleChart] - ["@material-ui/icons/ChevronRight" :default ChevronRight] - ["@material-ui/icons/Close" :default Close] - ["@material-ui/icons/Description" :default Description] - ["@material-ui/icons/FiberManualRecord" :default FiberManualRecord] - ["@material-ui/icons/VerticalSplit" :default VerticalSplit] - [athens.parse-renderer :as parse-renderer] - [athens.style :refer [color OPACITIES ZINDICES]] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.graph :as graph] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]])) + ["/components/Button/Button" :refer [Button]] + ["@chakra-ui/react" :refer [Flex Box]] + ["@material-ui/icons/BubbleChart" :default BubbleChart] + ["@material-ui/icons/ChevronRight" :default ChevronRight] + ["@material-ui/icons/Close" :default Close] + ["@material-ui/icons/Description" :default Description] + ["@material-ui/icons/FiberManualRecord" :default FiberManualRecord] + ["@material-ui/icons/VerticalSplit" :default VerticalSplit] + ["framer-motion" :refer [AnimatePresence motion]] + [athens.parse-renderer :as parse-renderer] + [athens.style :refer [color OPACITIES]] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.graph :as graph] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r] + [stylefy.core :as stylefy :refer [use-style]])) ;; Styles @@ -167,12 +167,17 @@ :paddingTop "2.75rem" :alignItems "stretch" :justifySelf "stretch" + :transformOrigin "right" :justifyContent "space-between" :position "relative" :gridArea "secondary-content" :overflow "hidden"} :initial {:width 0 :opacity 0} + :transition (if (:dragging @state) + {:type "tween" + :duration 0} + nil) :animate {:width (str (:width @state) "vw") :opacity 1} :exit {:width 0 diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index 6bad53dfb1..ca8ce25370 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -9,7 +9,6 @@ import { MergeType, Search, Settings, - Storage, Today, ToggleOff, ToggleOn, @@ -17,9 +16,12 @@ import { } from '@material-ui/icons'; import { + HTMLChakraProps, + ThemingProps, Tooltip, Flex, Button, + ButtonOptions, HStack, Divider, IconButton, @@ -28,18 +30,36 @@ import { import { WindowButtons } from './components/WindowButtons'; +interface ToolbarButtonProps extends ButtonOptions, HTMLChakraProps<'button'>, ThemingProps<"Button"> { + children: React.ReactChild; +}; +interface ToolbarIconButtonProps extends ButtonOptions, HTMLChakraProps<'button'>, ThemingProps<"Button"> { + children: React.ReactChild; +} + const toolbarButtonStyle = { background: 'background.floor', - _hover: { - bg: 'background.attic' - }, - _active: { - bg: 'link' +} + +const toolbarIconButtonStyle = { + background: 'background.floor', + sx: { + "svg": { + fontSize: "1.5em" + } } } -const ToolbarButton = ({ children, ...props }) => -const ToolbarIconButton = ({ children, ...props }) => {children} +const ToolbarButton = React.forwardRef((props: ToolbarButtonProps, ref) => { + const { children } = props; + return + + + <> {hostAddress && ( - <> - - - {hostAddress} - - - + handleCopyHostAddress(hostAddress)} + display="flex" + flexDirection="column" + textAlign="left" + justifyContent="flex-start" + alignItems="stretch" + > + Copy address + + {hostAddress} + + )} {currentUser && ( - <> - - - You appear as - - - {currentUser.username} - - - - + setShouldShowProfileSettings(true)}>Edit appearance )} {currentPageMembers.length > 0 && ( <> - - On this page - + + {currentPageMembers.map((member) => ( - + {member.username} + ))} - + )} {differentPageMembers.length > 0 && ( <> - - On other pages - {differentPageMembers.map((member) => ( - - ))} + + + {differentPageMembers.map((member) => ( + handlePressMember(member)} + key={member.personId} + icon={} + > + {member.username} + + ))} + )} - - - ) - } - - {currentUser && ( - <> - { - handleUpdateProfile(person); - profileSettingsState.close(); - }} - /> - - )} + + + + + setShouldShowProfileSettings(false)} + onUpdatePerson={(person) => { + handleUpdateProfile(person); + setShouldShowProfileSettings(false) + }} + /> ); }; diff --git a/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx b/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx index fd0ccdf63f..8f599852a0 100644 --- a/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx +++ b/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx @@ -1,58 +1,15 @@ import React from 'react'; -import styled, { keyframes } from 'styled-components'; -import { readableColor } from 'polished'; + +import { + keyframes, + Modal, ModalOverlay, ModalFooter, Center, Flex, Box, + ButtonGroup, ModalHeader, ModalCloseButton, ModalContent, ModalBody, Text, Heading, VStack, Divider, FormControl, FormHelperText, Input, Avatar, AvatarGroup, Menu, MenuDivider, MenuButton, MenuList, MenuGroup, MenuItem, Button, Popover, PopoverTrigger, PopoverContent, Portal, PopoverBody, AvatarBadge +} from '@chakra-ui/react'; + import { HexColorPicker } from "react-colorful"; import { AriaDialogProps } from '@react-types/dialog'; import { OverlayProps } from '@react-aria/overlays'; -import { Button } from '@/Button'; -import { Avatar } from '../Avatar'; -import { Input } from '../Input'; -import { Dialog } from '../Dialog'; - -const ProfileWrap = styled(Dialog.Body)` - width: 26rem; - - h3 { - text-align: center; - margin: 0; - font-weight: 600; - } - - hr { - margin: 1rem 0; - border: 0; - border-top: 1px solid var(--border-color); - } -`; - -const Actions = styled(Dialog.Actions)` - padding-Bottom: 1rem; - align-self: center; - gap: 1rem; - margin: 0; - - button { - width: 5em; - } -`; - -const AvatarWrap = styled.div` - display: flex; - align-items: center; - justify-content: center; - width: 20rem; - margin: 1em auto 2em; - border-radius: 1rem; - padding: 1rem; - border: 1px solid var(--border-color); - background: var(--background-plus-2); - - > * { - filter: drop-shadow(0 0.25rem 0.25rem var(--shadow-color---opacity-10)); - } -`; - const pulse = keyframes` from { transform: translate(-50%, -50%) scale(1) ; @@ -61,42 +18,39 @@ const pulse = keyframes` } `; -const ColorPickerWrap = styled.div` - .react-colorful { - width: 8.5rem; - height: 3rem; - gap: 1rem; - margin: -0.25rem 0 1rem; - flex-direction: row; - - > * { - border-radius: 0.5rem; - height: 100%; - flex: 0 0 4rem; - } - } - - .react-colorful__saturation { - border-bottom: 0; - } - - .react-colorful__interactive:focus - .react-colorful__pointer { - animation: ${pulse} 0.5s infinite alternate ease-in-out; - } -`; - -const Inputs = styled.div` - display: flex; - gap: 2rem; - align-items: flex-start; - justify-content: center; -`; - -const LabelWrapper = styled(Input.LabelWrapper)` - gap: 0.25rem; -`; - +const ColorPickerWrap = ({ children }) => { + return ( *": { + borderRadius: "0.5rem", + height: "100%", + flex: "0 0 4rem", + } + }, + ".react-colorful__saturation": { + borderBottom: 0 + }, + ".react-colorful__interactive:focus .react-colorful__pointer": { + animation: `${pulse} 0.5s infinite alternate ease-in-out` + } + }} + > + {children} + ) +}; + +const Inputs = ({ children }) => { + return ( + {children} + ) +} interface ProfileSettingsDialogProps extends OverlayProps, AriaDialogProps { person: Person; @@ -112,9 +66,9 @@ export const ProfileSettingsDialog = ({ isOpen, ...rest }: ProfileSettingsDialogProps) => { - const [editingUsername, setEditingUsername] = React.useState(person.username || ''); - const [editingColor, setEditingColor] = React.useState(person.color || '#0071DB'); - const [isValidUsername, setIsValidUsername] = React.useState(!!editingUsername); + const [ editingUsername, setEditingUsername ] = React.useState(person.username || ''); + const [ editingColor, setEditingColor ] = React.useState(person.color || '#0071DB'); + const [ isValidUsername, setIsValidUsername ] = React.useState(!!editingUsername); const handleChangeUsername = (e: React.ChangeEvent) => { const attempt = e.target.value.trim(); @@ -123,55 +77,58 @@ export const ProfileSettingsDialog = ({ } return ( - - -

How you appear to others

- - - - {isValidUsername ? editingUsername : person.username} - - - - - - - - - At least 2 characters - - -
- - - - -
-
+ + {isValidUsername ? editingUsername : person.username} + + + + + + + + At least 2 characters + + + + + + + + + + + + ) } diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js index e2ef7210cd..50995da690 100644 --- a/src/js/theme/theme.js +++ b/src/js/theme/theme.js @@ -1,4 +1,5 @@ import { extendTheme, cssVar } from '@chakra-ui/react' +import { readableColor } from 'polished'; import { spacing } from './spacing' const $arrowBg = cssVar("popper-arrow-bg"); @@ -102,7 +103,6 @@ const semanticTokens = { }, }, colors: { - transparent: 'transparent', brand: { default: 'linkLight', _dark: 'linkDark' @@ -188,6 +188,13 @@ const semanticTokens = { } const components = { + Avatar: { + baseStyle: { + container: { + borderColor: "background.floor" + }, + } + }, Accordion: { baseStyle: { button: { @@ -200,7 +207,7 @@ const components = { outline: "none", boxShadow: "focusInset" } - } + }, } }, Breadcrumb: { @@ -264,15 +271,26 @@ const components = { Menu: { baseStyle: { list: { - zIndex: 2, + zIndex: 3, bg: 'background.upper', shadow: 'menu' + }, + groupTitle: { + color: "foreground.secondary" + } + }, + sizes: { + sm: { + item: { + padding: '0.5rem 1rem', + } } } }, Modal: { baseStyle: { dialogContainer: { + WebkitAppRegion: 'no-drag', _focus: { outline: 'none' } @@ -295,6 +313,16 @@ const components = { } } }, + Spinner: { + baseStyle: ({ thickness }) => ({ + flexShrink: 0, + color: "separator.border", + borderWidth: thickness, + }), + defaultProps: { + thickness: '1.5px', + } + }, Table: { baseStyle: { border: 'separator.divider', diff --git a/yarn.lock b/yarn.lock index 7c4d0a3a71..01d111860b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1948,7 +1948,7 @@ compute-scroll-into-view "1.0.14" copy-to-clipboard "3.3.1" -"@chakra-ui/icon@2.0.5": +"@chakra-ui/icon@2.0.5", "@chakra-ui/icon@^2.0.5": version "2.0.5" resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-2.0.5.tgz#d57f53e6a2c7ae1bae7292a1778fd466c02e2e29" integrity sha512-ZrqRvCCIxGr4qFd/r1pmtd9tobRmv8KAxV7ygFoc/t4vOSKTcVIjhE12gsI3FzgvXM15ZFVwsxa1zodwgo5neQ== From a2cbce8d702d0dbaf22869b1f771307ba0aa6e7a Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Fri, 25 Mar 2022 20:48:28 -0400 Subject: [PATCH 10/79] chore: lint --- src/cljs/athens/effects.cljs | 3 +-- src/cljs/athens/electron/db_menu/db_list_item.cljs | 2 +- src/cljs/athens/events.cljs | 2 +- src/cljs/athens/views/athena.cljs | 2 +- src/cljs/athens/views/blocks/autocomplete_search.cljs | 3 +-- src/cljs/athens/views/blocks/autocomplete_slash.cljs | 3 +-- src/cljs/athens/views/pages/core.cljs | 2 +- src/cljs/athens/views/pages/settings.cljs | 2 +- src/cljs/athens/views/right_sidebar.cljs | 2 +- 9 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/cljs/athens/effects.cljs b/src/cljs/athens/effects.cljs index c29ca85476..21c7fadca2 100644 --- a/src/cljs/athens/effects.cljs +++ b/src/cljs/athens/effects.cljs @@ -17,8 +17,7 @@ [goog.dom.selection :refer [setCursorPosition]] [malli.core :as m] [malli.error :as me] - [re-frame.core :as rf] - [stylefy.core :as stylefy])) + [re-frame.core :as rf])) ;; Effects diff --git a/src/cljs/athens/electron/db_menu/db_list_item.cljs b/src/cljs/athens/electron/db_menu/db_list_item.cljs index 4a5d4a3787..f72122f91d 100644 --- a/src/cljs/athens/electron/db_menu/db_list_item.cljs +++ b/src/cljs/athens/electron/db_menu/db_list_item.cljs @@ -69,7 +69,7 @@ (when (:is-remote db) [:> Link]) (:id db)]] - (if on-remove + (when on-remove [:> IconButton {:onClick on-remove :size "sm" diff --git a/src/cljs/athens/events.cljs b/src/cljs/athens/events.cljs index bbbd093b8f..4878537327 100644 --- a/src/cljs/athens/events.cljs +++ b/src/cljs/athens/events.cljs @@ -1,7 +1,7 @@ (ns athens.events (:require - ["@chakra-ui/react" :refer [createStandaloneToast]] ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [createStandaloneToast]] [athens.athens-datoms :as athens-datoms] [athens.common-db :as common-db] [athens.common-events :as common-events] diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 7fa751e64e..7620d65342 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,6 +1,6 @@ (ns athens.views.athena (:require - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Box Heading Text]] + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] ["@material-ui/icons/Close" :default Close] [athens.common.utils :as utils] [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] diff --git a/src/cljs/athens/views/blocks/autocomplete_search.cljs b/src/cljs/athens/views/blocks/autocomplete_search.cljs index 4109231310..4cf87bb3ac 100644 --- a/src/cljs/athens/views/blocks/autocomplete_search.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_search.cljs @@ -1,7 +1,6 @@ (ns athens.views.blocks.autocomplete-search (:require - ;; ["/components/Button/Button" :refer [Button]] - ["@chakra-ui/react" :refer [Portal Heading Button IconButton MenuDivider MenuButton VStack Box Menu MenuList Text MenuItem]] + ["@chakra-ui/react" :refer [Portal Button VStack Text]] [athens.views.blocks.textarea-keydown :as textarea-keydown] [clojure.string :as string] [goog.events :as events] diff --git a/src/cljs/athens/views/blocks/autocomplete_slash.cljs b/src/cljs/athens/views/blocks/autocomplete_slash.cljs index e4c2f3ea71..ec6d0b7a4b 100644 --- a/src/cljs/athens/views/blocks/autocomplete_slash.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_slash.cljs @@ -1,7 +1,6 @@ (ns athens.views.blocks.autocomplete-slash (:require - ["/components/Button/Button" :refer [Button]] - ["@chakra-ui/react" :refer [Portal Heading IconButton MenuDivider MenuButton Menu MenuList MenuItem]] + ["@chakra-ui/react" :refer [Menu MenuList MenuItem]] [athens.views.blocks.textarea-keydown :as textarea-keydown] [athens.views.dropdown :as dropdown] [goog.events :as events] diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs index 71865c0023..2ef1085d3c 100644 --- a/src/cljs/athens/views/pages/core.cljs +++ b/src/cljs/athens/views/pages/core.cljs @@ -1,7 +1,7 @@ (ns athens.views.pages.core (:require - ["@chakra-ui/react" :refer [Box createStandaloneToast]] ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [Box createStandaloneToast]] [athens.views.hoc.perf-mon :as perf-mon] [athens.views.pages.all-pages :as all-pages] [athens.views.pages.daily-notes :as daily-notes] diff --git a/src/cljs/athens/views/pages/settings.cljs b/src/cljs/athens/views/pages/settings.cljs index be5de0d9de..be39d601e4 100644 --- a/src/cljs/athens/views/pages/settings.cljs +++ b/src/cljs/athens/views/pages/settings.cljs @@ -1,7 +1,7 @@ (ns athens.views.pages.settings (:require - ["@chakra-ui/react" :refer [createStandaloneToast Text Heading Box FormControl FormLabel ButtonGroup Grid Input Button Switch Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [createStandaloneToast Text Heading Box FormControl FormLabel ButtonGroup Grid Input Button Switch Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] [athens.db :refer [default-athens-persist]] [cljs-http.client :as http] [cljs.core.async :refer [ Accordion {:allowMultiple true} (doall - (for [[uid {:keys [open node/title block/string is-graph?]}] items] + (for [[uid {:keys [node/title block/string is-graph?]}] items] ^{:key uid} [:> AccordionItem {:_first {:borderTop 0}} [:> Box {:as "h2" :position "relative"} From 64632bc6f19c66e9c559b39aca9b93bf5b3e06f0 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Sun, 27 Mar 2022 12:42:22 -0400 Subject: [PATCH 11/79] improvements --- resources/public/index.html | 1 - src/cljs/athens/events.cljs | 15 +- src/cljs/athens/parse_renderer.cljs | 375 ++++++++++-------- .../athens/self_hosted/presence/views.cljs | 12 +- src/cljs/athens/util.cljs | 20 +- src/cljs/athens/views.cljs | 4 +- src/cljs/athens/views/blocks/content.cljs | 11 +- .../athens/views/blocks/context_menu.cljs | 65 +-- src/cljs/athens/views/blocks/core.cljs | 113 +++--- src/cljs/athens/views/left_sidebar.cljs | 1 + src/cljs/athens/views/pages/all_pages.cljs | 20 +- src/cljs/athens/views/pages/block_page.cljs | 7 +- src/cljs/athens/views/pages/core.cljs | 18 +- src/cljs/athens/views/pages/daily_notes.cljs | 6 +- src/cljs/athens/views/pages/node_page.cljs | 266 ++++++------- src/cljs/athens/views/pages/page.cljs | 28 +- src/cljs/athens/views/references.cljs | 52 +++ src/cljs/athens/views/right_sidebar.cljs | 6 +- src/js/components/AppToolbar/AppToolbar.tsx | 9 +- src/js/components/Block/components/Anchor.tsx | 171 +++----- src/js/components/Block/components/Toggle.tsx | 124 ++---- .../PresenceDetails/PresenceDetails.tsx | 70 ++-- .../ProfileSettingsDialog.tsx | 19 +- src/js/theme/theme.js | 121 ++++-- 24 files changed, 783 insertions(+), 751 deletions(-) create mode 100644 src/cljs/athens/views/references.cljs diff --git a/resources/public/index.html b/resources/public/index.html index c7a0500c30..177432f2fa 100644 --- a/resources/public/index.html +++ b/resources/public/index.html @@ -16,7 +16,6 @@ !function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags".split(" "),n=0;n -
diff --git a/src/cljs/athens/events.cljs b/src/cljs/athens/events.cljs index 4878537327..5799d91755 100644 --- a/src/cljs/athens/events.cljs +++ b/src/cljs/athens/events.cljs @@ -39,7 +39,8 @@ [re-frame.core :as rf :refer [reg-event-db reg-event-fx subscribe]])) -(def toast (createStandaloneToast {:theme theme})) +(def toast (createStandaloneToast (clj->js {:theme theme}))) + ;; -- re-frame app-db events --------------------------------------------- @@ -871,9 +872,9 @@ :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) {}) (catch :default _ - {:fx (toast clj->js {:status "error" + {:fx (toast (clj->js {:status "error" :title "Couldn't undo" - :description "Undo for this operation not supported in Lan-Party, yet."})})))) + :description "Undo for this operation not supported in Lan-Party, yet."}))})))) (reg-event-fx @@ -895,9 +896,9 @@ :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) {}) (catch :default _ - {:fx (toast clj->js {:status "error" + {:fx (toast (clj->js {:status "error" :title "Couldn't redo" - :description "Redo for this operation not supported in Lan-Party, yet."})})))) + :description "Redo for this operation not supported in Lan-Party, yet."}))})))) (reg-event-fx @@ -1566,9 +1567,9 @@ (re-find #"text/html" datatype) (.getAsString item (fn [_] #_(prn "getAsString" _)))))) items) {}) - {:fx (toast clj->js {:status "error" + {:fx (toast (clj->js {:status "error" :title "Couldn't paste" - :description "Image paste is not supported in Lan-Party, yet."})})))) + :description "Image paste is not supported in Lan-Party, yet."}))})))) (reg-event-fx diff --git a/src/cljs/athens/parse_renderer.cljs b/src/cljs/athens/parse_renderer.cljs index 42eece2c60..e10da7db6f 100644 --- a/src/cljs/athens/parse_renderer.cljs +++ b/src/cljs/athens/parse_renderer.cljs @@ -1,21 +1,48 @@ ^:cljstyle/ignore (ns athens.parse-renderer (:require - ["katex" :as katex] - ["katex/dist/contrib/mhchem"] - [athens.config :as config] - [athens.parser.impl :as parser-impl] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.style :refer [color OPACITIES]] - [clojure.string :as str] - [instaparse.core :as insta] - [re-frame.core :as rf] - [stylefy.core :as stylefy :refer [use-style]])) + ["@chakra-ui/react" :refer [Link Button Text]] + ["katex" :as katex] + ["katex/dist/contrib/mhchem"] + [athens.config :as config] + [athens.parser.impl :as parser-impl] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.style :refer [color OPACITIES]] + [clojure.string :as str] + [instaparse.core :as insta] + [re-frame.core :as rf] + [stylefy.core :as stylefy :refer [use-style]])) (declare parse-and-render) +(def fm-props {:as "b" :class "formatting" :fontWeight "normal" :opacity "0.3"}) + +(def content-props {:as "span" :fontWeight "normal" :opacity "0.3"}) + +(def link-props {:color "link" + :variant "link" + :minWidth "unset" + :whiteSpace "normal" + :wordBreak "break-word" + :lineHeight "unset" + :fontSize "inherit" + :fontWeight "inherit" + :textDecoration "none" + :_hover {:textDecoration "none"}}) + +(def ref-props {:as "span" + :white-space "normal" + :word-break "break-word" + :fontSize "0.9em" + :transition "background 0.05s ease" + :borderBottomWidth "1px" + :borderBottomStyle "solid" + :borderBottomColor "highlight" + :_hover {:background "background.upper" + :cursor "alias"}}) + ;; Styles @@ -32,39 +59,9 @@ :box-shadow (str "0px 0px 0px 1px " (color :link-color :opacity-lower))}]]}) -(def hashtag - {::stylefy/mode [[:hover {:text-decoration "underline" :cursor "pointer"}]] - ::stylefy/manual [[:.formatting {:opacity (:opacity-low OPACITIES)}]]}) - - (def image {:border-radius "0.125rem"}) -(def url-link - {:cursor "pointer" - :text-decoration "none" - :color (color :link-color) - ::stylefy/manual [[:.formatting {:color (color :body-text-color :opacity-low)}] - [:&:hover {:text-decoration "underline"}]]}) - - -(def autolink - {:cursor "pointer" - :text-decoration "none" - ::stylefy/manual [[:.formatting {:color (color :body-text-color :opacity-low)}] - [:.contents {:color (color :link-color) - :text-decoration "none"}] - [:&:hover [:.contents {:text-decoration "underline"}]]]}) - - -(def block-ref - {:font-size "0.9em" - :transition "background 0.05s ease" - :border-bottom [["1px" "solid" (color :highlight-color)]] - ::stylefy/mode [[:hover {:background-color (color :highlight-color :opacity-lower) - :cursor "alias"}]]}) - - (defn parse-title "Title coll is a sequence of plain strings or hiccup elements. If string, return string, otherwise parse the hiccup for its plain-text representation." @@ -79,12 +76,16 @@ (defn render-page-link "Renders a page link given the title of the page." [{:keys [from title]} title-coll] - [:span (assoc (use-style page-link {:class "page-link"}) - :title from) - [:span {:class "formatting"} "[["] + [:<> + [:> Text fm-props "[["] (cond (not (str/blank? title)) - [:span {:on-click (fn [e] + [:> Button + (merge link-props + {:class "page-link" + :fontWeight "normal" + :title from + :onClick (fn [e] (let [parsed-title (parse-title title-coll) shift? (.-shiftKey e)] (.. e stopPropagation) ; prevent bubbling up click handler for nested links @@ -93,22 +94,27 @@ :pane (if shift? :right-pane :main-pane)}]) - (router/navigate-page parsed-title e)))} + (router/navigate-page parsed-title e)))}) title] :else - (into [:span {:on-click (fn [e] - (let [parsed-title (parse-title title-coll) - shift? (.-shiftKey e)] - (.. e stopPropagation) ; prevent bubbling up click handler for nested links - (rf/dispatch [:reporting/navigation {:source :pr-page-link - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))}] - title-coll)) - [:span {:class "formatting"} "]]"]]) + (into + [:> Button + (merge link-props + {:class "page-link" + :title from + :onClick (fn [e] + (let [parsed-title (parse-title title-coll) + shift? (.-shiftKey e)] + (.. e stopPropagation) ; prevent bubbling up click handler for nested links + (rf/dispatch [:reporting/navigation {:source :pr-page-link + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))})] + title-coll)) + [:> Text fm-props "]]"]]) (defn- block-breadcrumb-string @@ -122,24 +128,37 @@ (defn render-block-ref [{:keys [from title]} ref-uid uid] (let [block (reactive/get-reactive-block-or-page-by-uid ref-uid) - parents (reactive/get-reactive-parents-recursively [:block/uid ref-uid]) + parents (reactive/get-reactive-parents-recursively [:block/uid ref-uid]) bc-string (block-breadcrumb-string parents)] (if block - [:span (assoc (use-style block-ref {:class "block-ref"}) - :title (-> from - (str/replace "](" - "]\n---\n(") - (str/replace (str "((" ref-uid "))") - bc-string))) - [:span {:class "contents" - :on-click (fn [e] - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :pr-block-ref - :target :block - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-uid ref-uid e)))} + [:> Button {:variant "link" + :as "a" + :title (-> from + (str/replace "](" + "]\n---\n(") + (str/replace (str "((" ref-uid "))") + bc-string)) + :class "block-ref" + :display "inline" + :color "unset" + :whiteSpace "unset" + :textAlign "unset" + :minWidth "unset" + :fontWeight "inherit" + :lineHeight "inherit" + :background "ref.feature" + :cursor "alias" + :sx {"-webkit-box-decoration-break" "clone"} + :_hover {:textDecoration "none"} + :onClick (fn [e] + (.. e stopPropagation) + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :pr-block-ref + :target :block + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-uid ref-uid e)))} (cond (= uid ref-uid) [parse-and-render "{{SELF}}"] @@ -148,7 +167,7 @@ [parse-and-render title ref-uid] :else - [parse-and-render (:block/string block) ref-uid])]] + [parse-and-render (:block/string block) ref-uid])] from))) @@ -193,98 +212,106 @@ "Transforms Instaparse output to Hiccup." [tree uid] (insta/transform - {:block (fn [& contents] - (apply clean-single-p-appending - [:span {:class "block"}] - contents)) - :heading (fn [{n :n} & contents] - (apply clean-single-p-appending - [({1 :h1 - 2 :h2 - 3 :h3 - 4 :h4 - 5 :h5 - 6 :h6} n)] - contents)) + {:block (fn [& contents] + (apply clean-single-p-appending + [:span {:class "block"}] + contents)) + :heading (fn [{n :n} & contents] + (apply clean-single-p-appending + [({1 :h1 + 2 :h2 + 3 :h3 + 4 :h4 + 5 :h5 + 6 :h6} n)] + contents)) ;; for more information regarding how custom components are parsed, see ;; https://athensresearch.gitbook.io/handbook/athens/athens-components-documentation/ - :component (fn [& contents] - (component (first contents) uid)) - :page-link (fn [{_from :from :as attr} & title-coll] - (render-page-link attr title-coll)) - :hashtag (fn [{_from :from} & title-coll] - [:span (use-style hashtag {:class "hashtag" - :on-click (fn [e] - (let [parsed-title (parse-title title-coll) - shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :pr-hashtag - :target :hashtag - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))}) - [:span {:class "formatting"} "#"] - [:span {:class "contents"} title-coll]]) - :block-ref (fn [{_from :from :as attr} ref-uid] - (render-block-ref attr ref-uid uid)) - :url-image (fn [{url :src alt :alt}] - [:img (use-style image {:class "url-image" - :alt alt - :src url})]) - :url-link (fn [{url :url} text] - [:a (use-style url-link {:class "url-link" - :href url - :target "_blank"}) - text]) - :link (fn [{:keys [text target title]}] - [:a (cond-> (use-style url-link {:class "url-link contents" - :href target - :target "_blank"}) - (string? title) - (assoc :title title)) - text]) - :autolink (fn [{:keys [text target]}] - [:span (use-style autolink) - [:span {:class "formatting"} "<"] - [:a {:class "autolink contents" - :href target - :target "_blank"} - text] - [:span {:class "formatting"} ">"]]) - :text-run (fn [& contents] - (apply conj [:span {:class "text-run"}] contents)) - :paragraph (fn [& contents] - (apply conj [:p] contents)) - :bold (fn [& contents] - (apply conj [:strong {:class "contents bold"}] contents)) - :italic (fn [& contents] - (apply conj [:i {:class "contents italic"}] contents)) - :strikethrough (fn [& contents] - (apply conj [:del {:class "contents del"}] contents)) - :underline (fn [& contents] - (apply conj [:u {:class "contents underline"}] contents)) - :highlight (fn [& contents] - (apply conj [:mark {:class "contents highlight"}] contents)) - :pre-formatted (fn [text] - [:code text]) - :inline-pre-formatted (fn [text] - [:code text]) - :indented-code-block (fn [{:keys [_from]} code-text] - (let [text (second code-text)] + :component (fn [& contents] + (component (first contents) uid)) + :page-link (fn [{_from :from :as attr} & title-coll] + (render-page-link attr title-coll)) + :hashtag (fn [{_from :from} & title-coll] + [:> Button {:variant "link" + :class "hashtag" + :color "inherit" + :fontWeight "inherit" + :_hover {:textDecoration "none"} + :onClick (fn [e] + (let [parsed-title (parse-title title-coll) + shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :pr-hashtag + :target :hashtag + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))} + [:> Text fm-props "#"] + [:span {:class "contents"} title-coll]]) + :block-ref (fn [{_from :from :as attr} ref-uid] + (render-block-ref attr ref-uid uid)) + :url-image (fn [{url :src alt :alt}] + [:img (use-style image {:class "url-image" + :alt alt + :src url})]) + :url-link (fn [{url :url} text] + [:> Button + (merge link-props {:class "url-link" + :href url + :target "_blank"}) + text]) + :link (fn [{:keys [text target title]}] + [:a (cond-> (merge link-props + {:class "url-link contents" + :href target + :target "_blank"}) + (string? title) + (assoc :title title)) + text]) + :autolink (fn [{:keys [text target]}] + [:<> + [:> Text fm-props "<"] + [:> Link (merge + link-props + {:class "autolink contents" + :href target + :target "_blank"}) + text] + [:> Text fm-props ">"]]) + :text-run (fn [& contents] + (apply conj [:span {:class "text-run"}] contents)) + :paragraph (fn [& contents] + (apply conj [:p] contents)) + :bold (fn [& contents] + (apply conj [:strong {:class "contents bold"}] contents)) + :italic (fn [& contents] + (apply conj [:i {:class "contents italic"}] contents)) + :strikethrough (fn [& contents] + (apply conj [:del {:class "contents del"}] contents)) + :underline (fn [& contents] + (apply conj [:u {:class "contents underline"}] contents)) + :highlight (fn [& contents] + (apply conj [:mark {:class "contents highlight"}] contents)) + :pre-formatted (fn [text] + [:code text]) + :inline-pre-formatted (fn [text] + [:code text]) + :indented-code-block (fn [{:keys [_from]} code-text] + (let [text (second code-text)] + [:pre + [:code text]])) + :fenced-code-block (fn [{lang :lang} code-text] + (let [mode (or lang "javascript") + text (second code-text)] + (when config/debug? + (js/console.log "Block code, original-mode:" lang + ", mode:" mode + ", text:" text)) [:pre - [:code text]])) - :fenced-code-block (fn [{lang :lang} code-text] - (let [mode (or lang "javascript") - text (second code-text)] - (when config/debug? - (js/console.log "Block code, original-mode:" lang - ", mode:" mode - ", text:" text)) - [:pre - [:code text]] + [:code text]] ;; TODO: Followup issue: #989 "Integrate with CodeMirror for code blocks" - #_[:> CodeMirror {:value text + #_[:> CodeMirror {:value text :options {:mode mode :lineNumbers true :matchBrackets true @@ -314,18 +341,18 @@ ;; update value based on `uid` )))}])) - :latex (fn [text] - [:span {:ref (fn [el] - (when el - (try - (katex/render text el (clj->js - {:throwOnError false})) - (catch :default e - (js/console.warn "Unexpected KaTeX error" e) - (aset el "innerHTML" text)))))}]) - :newline (fn [_] - [:br])} - tree)) + :latex (fn [text] + [:span {:ref (fn [el] + (when el + (try + (katex/render text el (clj->js + {:throwOnError false})) + (catch :default e + (js/console.warn "Unexpected KaTeX error" e) + (aset el "innerHTML" text)))))}]) + :newline (fn [_] + [:br])} + tree)) (defn parse-and-render diff --git a/src/cljs/athens/self_hosted/presence/views.cljs b/src/cljs/athens/self_hosted/presence/views.cljs index 7e7dcf1b2d..dadd5f1199 100644 --- a/src/cljs/athens/self_hosted/presence/views.cljs +++ b/src/cljs/athens/self_hosted/presence/views.cljs @@ -1,8 +1,7 @@ (ns athens.self-hosted.presence.views (:require ["/components/PresenceDetails/PresenceDetails" :refer [PresenceDetails]] - ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [Avatar AvatarGroup createStandaloneToast]] + ["@chakra-ui/react" :refer [Avatar AvatarGroup]] [athens.self-hosted.presence.events] [athens.self-hosted.presence.fx] [athens.self-hosted.presence.subs] @@ -11,9 +10,6 @@ [reagent.core :as r])) -(def toast - (createStandaloneToast {:theme theme})) - (defn user->person [{:keys [session-id username color] :page/keys [title]}] @@ -27,8 +23,8 @@ (defn copy-host-address-to-clipboard [host-address] (.. js/navigator -clipboard (writeText host-address)) - (toast (clj->js {:status "info" - :title "Host address copied to clipboard"}))) + (util/toast (clj->js {:status "info" + :title "Host address copied to clipboard"}))) (defn go-to-user-block @@ -41,7 +37,7 @@ (if page-uid ;; TODO: if we support navigating to a block, it should be added here. (rf/dispatch [:navigate :page {:id page-uid}]) - (toast (clj->js {:title "User is not on any page" + (util/toast (clj->js {:title "User is not on any page" :status "warning"}))))) diff --git a/src/cljs/athens/util.cljs b/src/cljs/athens/util.cljs index 89ab41b727..28481df664 100644 --- a/src/cljs/athens/util.cljs +++ b/src/cljs/athens/util.cljs @@ -1,12 +1,14 @@ (ns athens.util (:require - ["/textarea" :as getCaretCoordinates] - [athens.config :as config] - [athens.electron.utils :as electron.utils] - [clojure.string :as string] - [cognitect.transit :as tr] - [com.rpl.specter :as s] - [goog.dom :refer [getElement setProperties]]) + ["/textarea" :as getCaretCoordinates] + ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [createStandaloneToast]] + [athens.config :as config] + [athens.electron.utils :as electron.utils] + [clojure.string :as string] + [cognitect.transit :as tr] + [com.rpl.specter :as s] + [goog.dom :refer [getElement setProperties]]) (:require-macros [com.rpl.specter :refer [recursive-path]]) (:import @@ -14,6 +16,10 @@ KeyCodes))) +(def toast (createStandaloneToast (clj->js {:theme theme}))) + + + ;; Electron ipcMain Channels (def ipcMainChannels diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index a235aaeee8..1cbc2a8979 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -1,7 +1,7 @@ (ns athens.views (:require ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [ChakraProvider Flex Grid Spinner Center]] + ["@chakra-ui/react" :refer [ChakraProvider Flex Grid Spinner Center createStandaloneToast]] ["@react-aria/overlays" :refer [OverlayProvider]] [athens.config] [athens.electron.db-modal :as db-modal] @@ -22,6 +22,8 @@ ;; Components + + (defn alert [] (let [alert- (rf/subscribe [:alert])] diff --git a/src/cljs/athens/views/blocks/content.cljs b/src/cljs/athens/views/blocks/content.cljs index 3bb034bed0..0f9124ad25 100644 --- a/src/cljs/athens/views/blocks/content.cljs +++ b/src/cljs/athens/views/blocks/content.cljs @@ -33,7 +33,7 @@ :outline "none" :overflow "hidden" :padding "0" - :background "background.basement" + :background "var(--block-surface-color)" :grid-area "main" :min-height "100%" :caret-color "link" @@ -43,8 +43,9 @@ :border "0" :opacity "0" :font-family "inherit"} - "&:hover:not(.is-editing) textarea" {:lineHeight "2"} - "&.is-editing" {:zIndex 3 + "&:hover textarea:not(.is-editing)" {:lineHeight "2"} + "textarea.is-editing + *" {:opacity "0"} + ".is-editing" {:zIndex 3 :lineHeight "inherit" :opacity 1} "span.text-run" {:pointerEvents "none" @@ -58,7 +59,7 @@ :zIndex 4 "& > span" {:position "relative" :zIndex 2}} - "code, pre" {:fontFamily "IBM Plex Mono"} + "code, pre" {:fontFamily "code"} ".media-16-9" {:height 0 :width "calc(100% - 0.25rem)" :zIndex 1 @@ -325,7 +326,7 @@ "1em")] [:> Box {:class "block-content" :display "grid" - :background "background.floor" + :background "var(--block-surface-color)" :color "foreground.primary" :gridTemplateAreas "'main'" :alignItems "stretch" diff --git a/src/cljs/athens/views/blocks/context_menu.cljs b/src/cljs/athens/views/blocks/context_menu.cljs index fbc3dfbae1..c833c18b4b 100644 --- a/src/cljs/athens/views/blocks/context_menu.cljs +++ b/src/cljs/athens/views/blocks/context_menu.cljs @@ -1,18 +1,14 @@ (ns athens.views.blocks.context-menu (:require - ["/components/Button/Button" :refer [Button]] - [athens.db :as db] - [athens.listeners :as listeners] - [athens.subs.selection :as select-subs] - [athens.views.dropdown :refer [menu-style dropdown-style]] - [clojure.string :as string] - [goog.events :as events] - [re-frame.core :as rf] - [reagent.core :as r] - [stylefy.core :as stylefy])) + [athens.db :as db] + [athens.listeners :as listeners] + [athens.subs.selection :as select-subs] + [athens.util :refer [toast]] + [clojure.string :as string] + [re-frame.core :as rf])) -(defn copy-refs-mouse-down +(defn handle-copy-refs [_ uid state] (let [selected-items @(rf/subscribe [::select-subs/items]) ;; use this when using datascript-transit @@ -23,23 +19,13 @@ (->> (map (fn [uid] (str "((" uid "))\n")) selected-items) (string/join "")))] (.. js/navigator -clipboard (writeText data)) + (toast (clj->js {:title "Copied ref to clipboard"})) (swap! state assoc :context-menu/show false))) -(defn bullet-context-menu - "Handle right click. If no blocks are selected, just give option for copying current block's uid." - [e _uid state] - (.. e preventDefault) - (let [rect (.. e -target getBoundingClientRect)] - (swap! state assoc - :context-menu/x (.. rect -left) - :context-menu/y (.. rect -bottom) - :context-menu/show true))) - - (defn handle-copy-unformatted "If copying only a single block, dissoc children to not copy subtree." - [^js e uid state] + [^js uid state] (let [uids @(rf/subscribe [::select-subs/items])] (if (empty? uids) (let [block (dissoc (db/get-block [:block/uid uid]) :block/children) @@ -49,36 +35,5 @@ (map #(listeners/blocks-to-clipboard-data 0 % true)) (apply str))] (.. js/navigator -clipboard (writeText data))))) - (.. e preventDefault) + (toast (clj->js {:title "Copied content to clipboard" :status "success"})) (swap! state assoc :context-menu/show false)) - - -(defn context-menu-el - "Only option in context menu right now is copy block ref(s)." - [_block state] - (let [ref (atom nil) - handle-click-outside (fn [e] - (when (and (:context-menu/show @state) - (not (.. @ref (contains (.. e -target))))) - (swap! state assoc :context-menu/show false)))] - (r/create-class - {:display-name "context-menu" - :component-did-mount (fn [_this] (events/listen js/document "mousedown" handle-click-outside)) - :component-will-unmount (fn [_this] (events/unlisten js/document "mousedown" handle-click-outside)) - :reagent-render (fn [block state] - (let [{:block/keys [uid]} block - {:context-menu/keys [x y show]} @state - selected-items @(rf/subscribe [::select-subs/items])] - (when show - [:div (merge (stylefy/use-style dropdown-style - {:ref #(reset! ref %)}) - {:style {:position "fixed" - :left (str x "px") - :top (str y "px")}}) - [:div (stylefy/use-style menu-style) - [:> Button {:on-mouse-down (fn [e] (copy-refs-mouse-down e uid state))} - (if (empty? selected-items) - "Copy block ref" - "Copy block refs")] - [:> Button {:on-mouse-down (fn [e] (handle-copy-unformatted e uid state))} - "Copy unformatted"]]])))}))) diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index 00a6c487c8..205db7f03f 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -2,8 +2,7 @@ (:require ["/components/Block/components/Anchor" :refer [Anchor]] ["/components/Block/components/Toggle" :refer [Toggle]] - ["/components/Button/Button" :refer [Button]] - ["@chakra-ui/react" :refer [Box]] + ["@chakra-ui/react" :refer [Box Button]] [athens.common.logging :as log] [athens.db :as db] [athens.electron.images :as images] @@ -13,16 +12,16 @@ [athens.reactive :as reactive] [athens.router :as router] [athens.self-hosted.presence.views :as presence] - [athens.style :as style] [athens.subs.selection :as select-subs] [athens.util :as util :refer [mouse-offset vertical-center specter-recursive-path]] [athens.views.blocks.autocomplete-search :as autocomplete-search] [athens.views.blocks.autocomplete-slash :as autocomplete-slash] [athens.views.blocks.bullet :refer [bullet-drag-start bullet-drag-end]] [athens.views.blocks.content :as content] - [athens.views.blocks.context-menu :as context-menu] + [athens.views.blocks.context-menu :refer [handle-copy-unformatted handle-copy-refs]] [athens.views.blocks.drop-area-indicator :as drop-area-indicator] [athens.views.breadcrumbs :as breadcrumbs] + [athens.views.references :refer [reference-group reference-block]] [com.rpl.specter :as s] [goog.functions :as gfns] [re-frame.core :as rf] @@ -89,11 +88,15 @@ :right 0 :bottom 0 :left 0} + ".block-embed" {:borderRadius "sm" + :sx {"--block-surface-color" "background.basement"} + :bg "background.basement" + ".block-container" {:marginLeft 0.5}} ".block-content" {:gridArea "content" :minHeight "1.5em"} - "&.is-linked-ref" {:bg "background-attic"} - ".block-container" {:marginLeft "2rem" - :gridArea "body"}}) + "&.is-linked-ref" {:bg "background-attic"} + ".block-container" {:marginLeft "2rem" + :gridArea "body"}}) (def dragging-style @@ -191,55 +194,37 @@ {:block-embed? true}]])))])))) -(def references-style - {:padding-left "2em"}) - - -(def references-list-style - {:font-size "14px"}) - - -(def references-group-style - {:background (style/color :background-minus-2 :opacity-med) - :padding "0rem 0.5rem" - :border-radius "0.25rem" - :margin "0.5em 0"}) - - -(def references-group-block-style - {:width "100%" - ::stylefy/manual [[:&:first-of-type {:border-top "0" - :margin-block-start "0"}]]}) - - (defn inline-linked-refs-el [state uid] (let [refs (reactive/get-reactive-linked-references [:block/uid uid])] (when (not-empty refs) - [:div (stylefy/use-style references-style {:key "Inline Linked References"}) - [:section - [:div (stylefy/use-style references-list-style) - (doall - (for [[group-title group] refs] - [:div (stylefy/use-style references-group-style {:key (str "group-" group-title)}) - (doall - (for [block' group] - [:div (stylefy/use-style references-group-block-style {:key (str "ref-" (:block/uid block'))}) - [ref-comp block' state]]))]))]]]))) + [:> Box {:as "section" + :key "Inline Linked References" + :background "background.basement"} + (doall + (for [[group-title group] refs] + [reference-group {:title group-title + :key (str "group-" group-title)} + (doall + (for [block' group] + [reference-block {:key (str "ref-" (:block/uid block'))} + [ref-comp block' state]]))]))]))) ;; Components (defn block-refs-count-el - [count click-fn] - [:div (stylefy/use-style {:margin-left "1em" - :grid-area "refs" - :z-index (:zindex-dropdown style/ZINDICES) - :visibility (when-not (pos? count) "hidden")}) - [:> Button {:on-click (fn [e] - (.. e stopPropagation) - (click-fn e))} - count]]) + [count click-fn active?] + [:> Button {:gridArea "refs" + :size "sm" + :isActive active? + :ml "1em" + :zIndex 10 + :visibility (if (pos? count) "visible" "hidden") + :onClick (fn [e] + (.. e stopPropagation) + (click-fn e))} + count]) (defn block-drag-over @@ -438,7 +423,10 @@ :border-radius "0.125rem" :justify-content "flex-start" :flex-direction "column" - :sx block-container-inner-style + :background "var(--block-surface-color)" + :opacity (if dragging 0.5 1.0) + :sx (merge block-container-inner-style + {"--block-surface-color" "background.floor"}) :class ["block-container" (when (and dragging (not is-selected)) "dragging") (when is-editing "is-editing") @@ -447,12 +435,12 @@ (when (and (false? initial-open) (= uid linked-ref-uid)) "is-linked-ref") (when is-presence "is-presence")] :data-uid uid - ;; need to know children for selection resolution + ;; need to know children for selection resolution :data-childrenuids children-uids - ;; :show-editable-dom allows us to render the editing elements (like the textarea) - ;; even when not editing this block. When true, clicking the block content will pass - ;; the clicks down to the underlying textarea. The textarea is expensive to render, - ;; so we avoid rendering it when it's not needed. + ;; :show-editable-dom allows us to render the editing elements (like the textarea) + ;; even when not editing this block. When true, clicking the block content will pass + ;; the clicks down to the underlying textarea. The textarea is expensive to render, + ;; so we avoid rendering it when it's not needed. :on-mouse-enter #(swap! state assoc :show-editable-dom true) :on-mouse-leave #(swap! state assoc :show-editable-dom false) :on-drag-over (fn [e] (block-drag-over e block state)) @@ -472,14 +460,14 @@ (if (true? linked-ref) (swap! state update :linked-ref/open not) (toggle uid (not open))))}]) - (when (:context-menu/show @state) - [context-menu/context-menu-el uid-sanitized-block state]) [:> Anchor {:isClosedWithChildren (when (and (seq children) (or (and (true? linked-ref) (not (:linked-ref/open @state))) (and (false? linked-ref) (not open)))) "closed-with-children") :block block :shouldShowDebugDetails (util/re-frame-10x-open?) + :onCopyRefs #(handle-copy-refs nil uid state) + :onCopyUnformatted #(handle-copy-unformatted uid state) :on-click (fn [e] (let [shift? (.-shiftKey e)] (rf/dispatch [:reporting/navigation {:source :block-bullet @@ -488,18 +476,21 @@ :right-pane :main-pane)}]) (router/navigate-uid uid e))) - :on-context-menu (fn [e] (context-menu/bullet-context-menu e uid state)) + ;; :on-context-menu (fn [e] (context-menu/bullet-context-menu e uid state)) :on-drag-start (fn [e] (bullet-drag-start e uid state)) :on-drag-end (fn [e] (bullet-drag-end e uid state))}] [content/block-content-el block state] - + [presence/inline-presence-el uid] (when (and (> (count _refs) 0) (not= :block-embed? opts)) - [block-refs-count-el (count _refs) (fn [e] - (if (.. e -shiftKey) - (rf/dispatch [:right-sidebar/open-item uid]) - (swap! state update :inline-refs/open not)))])] + [block-refs-count-el + (count _refs) + (fn [e] + (if (.. e -shiftKey) + (rf/dispatch [:right-sidebar/open-item uid]) + (swap! state update :inline-refs/open not))) + (:inline-refs/open @state)])] [autocomplete-search/inline-search-el block state] [autocomplete-slash/slash-menu-el block state] diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index 2978e71d94..a117531ae9 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -24,6 +24,7 @@ :borderBottomColor (when (:below @drag) "brand")} [:> Button {:variant "link" :borderWidth "1px" + :color "foreground.primary" :p "1rem" :display "block" :py "0.5rem" diff --git a/src/cljs/athens/views/pages/all_pages.cljs b/src/cljs/athens/views/pages/all_pages.cljs index 7979fc4160..fddd792410 100644 --- a/src/cljs/athens/views/pages/all_pages.cljs +++ b/src/cljs/athens/views/pages/all_pages.cljs @@ -84,24 +84,26 @@ (fn [] (let [sorted-pages @(rf/subscribe [:all-pages/sorted all-pages])] [:> Box {:px 4 - :margin "5rem auto"} - [:> Table {:variant "striped" - :max-width "70rem"} + :margin "2rem auto 5rem"} + [:> Table {:variant "striped"} [:> Thead [:> Tr [sortable-header :title "Title"] [sortable-header :links-count "Links" "12rem" true] - [sortable-header :modified "Modified" "20rem" false {:date? true}] - [sortable-header :created "Created" "20rem" false {:date? true}]]] + [sortable-header :modified "Modified" "16rem" false {:date? true}] + [sortable-header :created "Created" "16rem" false {:date? true}]]] [:> Tbody (doall (for [{:keys [block/uid node/title block/_refs] modified :edit/time created :create/time} sorted-pages] [:> Tr {:key uid} - [:> Td + [:> Td {:overflow "hidden"} [:> Button {:variant "link" :color "link" + :display "block" + :maxWidth "100%" + :whiteSpace "nowrap" :onClick (fn [e] (let [shift? (.-shiftKey e)] (rf/dispatch [:reporting/navigation {:source :all-pages @@ -111,6 +113,6 @@ :main-pane)}]) (router/navigate-page title e)))} title]] - [:> Td {:width "12rem" :color "foreground.secondary" :isNumeric true} (count _refs)] - [:> Td {:width "18rem" :color "foreground.secondary"} (dates/date-string modified)] - [:> Td {:width "18rem" :color "foreground.secondary"} (dates/date-string created)]]))]]])))) + [:> Td {:width "12rem" :whiteSpace "nowrap" :color "foreground.secondary" :isNumeric true} (count _refs)] + [:> Td {:width "16rem" :whiteSpace "nowrap" :color "foreground.secondary"} (dates/date-string modified)] + [:> Td {:width "16rem" :whiteSpace "nowrap" :color "foreground.secondary"} (dates/date-string created)]]))]]])))) diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index a495f7cb4c..1851ff0e76 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -9,6 +9,7 @@ [athens.views.pages.node-page :as node-page] [komponentit.autosize :as autosize] [re-frame.core :as rf :refer [dispatch subscribe]] + [athens.views.references :refer [reference-group reference-block]] [reagent.core :as r] [stylefy.core :as stylefy :refer [use-style]])) @@ -57,7 +58,6 @@ [(r/adapt-react-class Link)] [:span "Linked References"]] ;; Hide button until feature is implemented - ;; [:> Button {:disabled true} [(r/adapt-react-class FilterList)]]] [:div (use-style node-page/references-list-style) (doall (for [[group-title group] linked-refs] @@ -72,11 +72,10 @@ :right-pane :main-pane)}]) (router/navigate-page parsed-title)))} - group-title]] (doall (for [block group] [:div (use-style node-page/references-group-block-style {:key (str "ref-" (:block/uid block))}) - [node-page/ref-comp block]]))]))]]]))) + [node-page/ref-comp block]]))]]]))]]]))) (defn parents-el @@ -101,7 +100,7 @@ (when (not= string (:string/previous @state)) (swap! state assoc :string/previous string :string/local string)) - [:div.block-page (use-style node-page/page-style {:data-uid uid}) + [:<> ;; Parent Context [parents-el uid id] diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs index 2ef1085d3c..170fa12831 100644 --- a/src/cljs/athens/views/pages/core.cljs +++ b/src/cljs/athens/views/pages/core.cljs @@ -11,7 +11,8 @@ [re-frame.core :as rf])) -(def toast (createStandaloneToast {:theme theme})) +(def toast (createStandaloneToast (clj->js {:theme theme}))) + ;; View @@ -24,6 +25,7 @@ (toast (clj->js {:status "info" :title "Reconnecting to server..."}))) [:> Box {:flex "1 1 100%" + :position "relative" :gridArea "main-content" :alignItems "flex-start" @@ -31,18 +33,24 @@ :paddingTop "3.25rem" :display "flex" :overflowY "overlay" - :sx {"&:before" {:content "''" + :sx {:maskImage "linear-gradient(to bottom, + transparent, + transparent 3rem, + black 5rem, + black calc(100vh - 5rem), + transparent 100vh)" + "&:before" {:content "''" :position "fixed" :zIndex "-1" :inset 0 :top "3.25rem" :WebkitAppRegion "no-drag"} "::WebkitScrollbar" {:background "background.basement" - :width "0.5rem" - :height "0.5rem"} + :width "0.5rem" + :height "0.5rem"} "::WebkitScrollbar-corner" {:bg "background.basement"} "::WebkitScrollbar-thumb" {:bg "background.upper" - :borderRadius "full"}} + :borderRadius "full"}} :on-scroll (when (= @route-name :home) #(rf/dispatch [:daily-note/scroll]))} (case @route-name diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index 710b85ddb7..70851afea7 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -29,9 +29,9 @@ [:> VStack {:id "daily-notes" :minHeight "calc(100vh + 1px)" :display "flex" - :gap "2.5rem" - :py "1.25rem" - :px "2.5rem" + :gap "1.5rem" + :py "2rem" + :px "2rem" :alignItems "stretch" :flex "1 1 100%" :flexDirection "column"} diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 56aac8d8e6..4b246666f2 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -1,48 +1,38 @@ (ns athens.views.pages.node-page (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Dialog/Dialog" :refer [Dialog]] - ["@chakra-ui/react" :refer [Box Button Portal Heading IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink]] - ["@material-ui/icons/Bookmark" :default Bookmark] - ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] - ["@material-ui/icons/BubbleChart" :default BubbleChart] - ["@material-ui/icons/Delete" :default Delete] - ["@material-ui/icons/MoreHoriz" :default MoreHoriz] - [athens.common-db :as common-db] - [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] - [athens.common.utils :as utils] - [athens.dates :as dates] - [athens.db :as db :refer [get-unlinked-references]] - [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.style :refer [color ]] - [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] - [athens.views.blocks.core :as blocks] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.hoc.perf-mon :as perf-mon] - [clojure.string :as str] - [datascript.core :as d] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r] - [stylefy.core :as stylefy :refer [use-style]]) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Dialog/Dialog" :refer [Dialog]] + ["@chakra-ui/react" :refer [Box Button Portal Heading IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] + ["@material-ui/icons/Bookmark" :default Bookmark] + ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] + ["@material-ui/icons/BubbleChart" :default BubbleChart] + ["@material-ui/icons/Delete" :default Delete] + ["@material-ui/icons/MoreHoriz" :default MoreHoriz] + [athens.common-db :as common-db] + [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] + [athens.common.utils :as utils] + [athens.dates :as dates] + [athens.db :as db :refer [get-unlinked-references]] + [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.style :refer [color]] + [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] + [athens.views.blocks.core :as blocks] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [athens.views.references :refer [reference-group reference-block]] + [athens.views.hoc.perf-mon :as perf-mon] + [clojure.string :as str] + [datascript.core :as d] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r] + [stylefy.core :as stylefy :refer [use-style]]) (:import - (goog.events - KeyCodes))) + (goog.events + KeyCodes))) -;; ------------------------------------------------------------------- -;; --- material ui --- - - - -(def page-style - {:margin "2rem auto" - :padding "1rem 2rem 10rem 3rem" - :flex-basis "100%" - :max-width "55rem"}) - (def page-header-style {:position "relative"}) @@ -259,10 +249,12 @@ (defn placeholder-block-el [parent-uid] - [:div {:class "block-container"} - [:div {:style {:display "flex"}} + [:> Box {:class "block-container"} + [:> Box {:display "flex"} [:> Anchor] - [:span {:on-click #(handle-new-first-child-block-click parent-uid)} "Click here to add content..."]]]) + [:> Button {:variant "link" + :onClick #(handle-new-first-child-block-click parent-uid)} + "Click here to add content..."]]]) (defn sync-title @@ -290,7 +282,9 @@ (defn menu-dropdown [node daily-note?] - (let [{:block/keys [uid] sidebar :page/sidebar title :node/title} node] + (let [{:block/keys [uid] sidebar + :page/sidebar title + :node/title} node] [:> Menu [:> MenuButton {:as IconButton :position "absolute" @@ -348,8 +342,7 @@ (let [{:keys [block parents embed-id]} @state block (reactive/get-reactive-block-document (:db/id block))] [:<> - [:> Breadcrumb {:fontSize "0.65em" - :pl 6} + [:> Breadcrumb {:fontSize "0.7em" :pl 6} (doall (for [{:keys [node/title block/string block/uid]} parents] [:> BreadcrumbItem {:key (str "breadcrumb-" uid)} @@ -358,7 +351,7 @@ new-P (drop-last parents)] (swap! state assoc :block new-B :parents new-P))} [parse-and-render (or title string) uid]]]))] - [:div.block-embed + [:> Box {:class "block-embed"} [blocks/block-el (recursively-modify-block-for-embed block embed-id) linked-ref-data @@ -376,106 +369,100 @@ [:> AccordionItem [:h2 [:> AccordionButton {:onClick (fn [] (swap! state update linked? not))} - [:> AccordionIcon] + [:> AccordionIcon] linked?]] - [:> AccordionPanel - (doall - (for [[group-title group] linked-refs] - [:div (use-style references-group-style {:key (str "group-" group-title)}) - [:h4 (use-style references-group-title-style) - [:a {:on-click (fn [e] - (let [shift? (.-shiftKey e) - parsed-title (parse-renderer/parse-title group-title)] - (rf/dispatch [:reporting/navigation {:source :main-page-linked-refs ; NOTE: this might be also used in right-pane situation - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))} - group-title]] - (doall - (for [block group] - ^{:key (str "ref-" (:block/uid block))} - [:div {:style {:display "flex" - :flex "1 1 100%" - :justify-content "space-between" - :align-items "flex-start"}} - [:div (use-style references-group-block-style) - [ref-comp block]]]))]))]]]))) + [:> AccordionPanel {:px 0} + [:> VStack {:spacing 6 + :pl 1 + :align "stretch"} + (doall + (for [[group-title group] linked-refs] + [reference-group {:title group-title + :on-click-title (fn [e] + (let [shift? (.-shiftKey e) + parsed-title (parse-renderer/parse-title group-title)] + (rf/dispatch [:reporting/navigation {:source :main-page-linked-refs ; NOTE: this might be also used in right-pane situation + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))} + (doall + (for [block group] + [reference-block {:key (str "ref-" (:block/uid block))} + [ref-comp block]]))]))]]]]))) + (defn unlinked-ref-el [state daily-notes? unlinked-refs title] (let [unlinked? "Unlinked References"] (when (not daily-notes?) - [:> Accordion {:index (if (get @state unlinked?) 0 nil)} - [:> AccordionItem - [:> Box {:as "h2" - :position "relative"} - [:> AccordionButton - {:onClick (fn [] - (if (get @state unlinked?) - (swap! state assoc unlinked? false) - (let [un-refs (get-unlinked-references (escape-str title))] - (swap! state assoc unlinked? true) - (reset! unlinked-refs un-refs))))} - [:> AccordionIcon] - unlinked?] - (when (and unlinked? (not-empty @unlinked-refs)) - [:> Button {:position "absolute" - :size "sm" - :fontSize "sm" - :top 1 - :right 1 - :onClick (fn [] - (let [unlinked-str-ids (->> @unlinked-refs - (mapcat second) - (map #(select-keys % [:block/string :block/uid])))] ; to remove the unnecessary data before dispatching the event - (dispatch [:unlinked-references/link-all unlinked-str-ids title])) - - (swap! state assoc unlinked? false) - - (reset! unlinked-refs []))} - "Link All"])] - [:> AccordionPanel - [:div (use-style references-list-style) + [:> Accordion {:index (if (get @state unlinked?) 0 nil)} + [:> AccordionItem + [:> Box {:as "h2" :position "relative"} + [:> AccordionButton {:onClick (fn [] + (if (get @state unlinked?) + (swap! state assoc unlinked? false) + (let [un-refs (get-unlinked-references (escape-str title))] + (swap! state assoc unlinked? true) + (reset! unlinked-refs un-refs))))} + [:> AccordionIcon] + unlinked?] + (when (and unlinked? (not-empty @unlinked-refs)) + [:> Button {:position "absolute" + :size "xs" + :top 1 + :right 1 + :onClick (fn [] + (let [unlinked-str-ids (->> @unlinked-refs + (mapcat second) + (map #(select-keys % [:block/string :block/uid])))] ; to remove the unnecessary data before dispatching the event + (dispatch [:unlinked-references/link-all unlinked-str-ids title])) + + (swap! state assoc unlinked? false) + + (reset! unlinked-refs []))} + "Link All"])] + [:> AccordionPanel {:px 0} + [:> VStack {:spacing 6 + :pl 1 + :align "stretch"} (doall (for [[[group-title] group] @unlinked-refs] - [:div (use-style references-group-style {:key (str "group-" group-title)}) - [:h4 (use-style references-group-title-style) - [:a {:on-click (fn [e] - (let [shift? (.-shiftKey e) - parsed-title (parse-renderer/parse-title group-title)] - (rf/dispatch [:reporting/navigation {:source :main-unlinked-refs ; NOTE: this isn't always `:main-unlinked-refs` it can also be `:right-pane-unlinked-refs` - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))} - group-title]] + [reference-group + {:title group-title + :on-click-title (fn [e] + (let [shift? (.-shiftKey e) + parsed-title (parse-renderer/parse-title group-title)] + (rf/dispatch [:reporting/navigation {:source :main-unlinked-refs ; NOTE: this isn't always `:main-unlinked-refs` it can also be `:right-pane-unlinked-refs` + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))} (doall (for [block group] - ^{:key (str "ref-" (:block/uid block))} - [:div {:style {:display "flex" - :justify-content "space-between" - :align-items "flex-start"}} - [:div (merge - (use-style references-group-block-style) - {:style {:max-width "90%"}}) - [ref-comp block]] - (when unlinked? - [:> Button {:style {:margin-top "1.5em"} - :on-click (fn [] - (let [hm (into (hash-map) @unlinked-refs) - new-unlinked-refs (->> (update-in hm [group-title] #(filter (fn [{:keys [block/uid]}] - (= uid (:block/uid block))) - %)) - seq)] - ;; ctrl-z doesn't work though, because Unlinked Refs aren't reactive to datascript. - (reset! unlinked-refs new-unlinked-refs) - (dispatch [:unlinked-references/link block title])))} - "Link"])]))]))]]]]))) - + [reference-block + {:key (str "ref-" (:block/uid block)) + :actions (when unlinked? + [:> Button {:marginTop "1.5em" + :size "xs" + :flex "0 0" + :float "right" + :variant "link" + :onClick (fn [] + (let [hm (into (hash-map) @unlinked-refs) + new-unlinked-refs (->> (update-in hm [group-title] #(filter (fn [{:keys [block/uid]}] + (= uid (:block/uid block))) + %)) + seq)] + ;; ctrl-z doesn't work though, because Unlinked Refs aren't reactive to datascript. + (reset! unlinked-refs new-unlinked-refs) + (dispatch [:unlinked-references/link block title])))} + "Link"])} + [ref-comp block]]))]))]]]]))) + ;; TODO: where to put page-level link filters? @@ -498,11 +485,9 @@ daily-note? (dates/is-daily-note uid) on-daily-notes? (= :home @(subscribe [:current-route/name]))] - (sync-title title state) - [:div (use-style page-style {:class ["node-page"] - :data-uid uid}) + [:<> (when alert-show [:> Dialog {:isOpen true @@ -510,13 +495,12 @@ :onConfirm confirm-fn :onDismiss cancel-fn}]) - ;; Header [:header (use-style page-header-style) ;; Dropdown [menu-dropdown node daily-note?] - + [:> Heading {:data-uid uid :class "page-header" :position "relative" diff --git a/src/cljs/athens/views/pages/page.cljs b/src/cljs/athens/views/pages/page.cljs index bcb5061db0..537ed741cf 100644 --- a/src/cljs/athens/views/pages/page.cljs +++ b/src/cljs/athens/views/pages/page.cljs @@ -1,5 +1,6 @@ (ns athens.views.pages.page (:require + ["@chakra-ui/react" :refer [Box]] [athens.common-db :as common-db] [athens.db :as db] [athens.reactive :as reactive] @@ -8,12 +9,28 @@ [re-frame.core :as rf])) +(defn page-container + [props children] + (let [{:keys [uid type]} props] + [:> Box {:as "article" + :data-ui uid + :class (str type "-page") + :flexDirection "column" + :display "flex" + :margin "2rem auto" + :padding "1rem 2rem 10rem 3rem" + :flexBasis "100%" + :maxWidth "75rem"} + children])) + + (defn page-by-title [] (let [title (rf/subscribe [:current-route/page-title]) page-eid (common-db/e-by-av @db/dsdb :node/title @title)] (if (int? page-eid) - [node-page/page page-eid] + [page-container {:uid page-eid :type "node"} + [node-page/page page-eid]] [:h3 (str "404: Page with title '" @title "' doesn't exist")]))) @@ -22,7 +39,8 @@ [] (let [uid (rf/subscribe [:current-route/uid]) {:keys [node/title block/string db/id]} (reactive/get-reactive-block-or-page-by-uid @uid)] - (cond - title [node-page/page id] - string [block-page/page id] - :else [:h3 "404: This page doesn't exist"]))) + [page-container {:uid @uid :type (if title "node" "block")} + (cond + title [node-page/page id] + string [block-page/page id] + :else [:h3 "404: This page doesn't exist"])])) diff --git a/src/cljs/athens/views/references.cljs b/src/cljs/athens/views/references.cljs new file mode 100644 index 0000000000..1c234fc530 --- /dev/null +++ b/src/cljs/athens/views/references.cljs @@ -0,0 +1,52 @@ +(ns athens.views.references + (:require + ["@chakra-ui/react" :refer [Box Button Heading]])) + + +(defn references-container + ([_ children] + [:> Box {:as "section" + :key "Inline Linked References" + :ml 6 + :borderRadius "md" + :background "background.basement"} + children])) + + +(defn reference-header + ([props] + (let [{:keys [on-click title]} props] + [:> Heading {:as "h4" + :py 2 + :color "foreground.secondary" + :textTransform "uppercase" + :fontWeight "bold" + :fontSize "0.75rem" + :size "md"} + [:> Button {:onClick on-click + :color "inherit" + :textTransform "inherit" + :_hover {:textDecoration "none" + :opacity 0.5} + :fontWeight "inherit" + :fontSize "inherit" + :variant "link"} + title]]))) + + +(defn reference-group + ([props children] + (let [{:keys [on-click-title title]} props] + [:> Box + [reference-header {:on-click on-click-title + :title title}] + children]))) + + +(defn reference-block + ([props children] + (let [{:keys [actions]} props] + [:> Box + children + actions]))) + diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 92f4aa5e83..d873ecf493 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -69,8 +69,8 @@ {:style {:display "flex" :WebkitAppRegion "no-drag" :flex-direction "column" - :height "100%" - :paddingTop "3.25rem" + :height "calc(100% - 3.25rem)" + :marginTop "3.25rem" :alignItems "stretch" :justifySelf "stretch" :transformOrigin "right" @@ -93,7 +93,7 @@ :cursor "col-resize" :position "absolute" :top 0 - :height "100%" + :bottom 0 :width "1px" :zIndex 1 :transitionDuration "0.2s" diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index b34bc8f030..b227797fa6 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -88,21 +88,24 @@ const AppToolbarWrapper = ({ children, ...props }) => , dash: - + } @@ -152,6 +67,10 @@ export interface AnchorProps { isClosedWithChildren: boolean; block: any; shouldShowDebugDetails: boolean; + as: ReactNode; + onContextMenu: (event: React.MouseEvent) => void; + onCopyRefs: () => void; + onCopyUnformatted: () => void; } interface AnchorButtonProps { @@ -200,10 +119,18 @@ const AnchorButton = React.forwardRef((props: AnchorButtonProps, ref) => { } }, "circle": { + transformOrigin: 'center', + transition: 'all 0.15s ease-in-out', + stroke: "transparent", + strokeWidth: "0.125em", fill: "currentColor", + ...isClosedWithChildren && ({ + transform: "scale(1.25)", + stroke: 'currentColor', + fill: "none", + }) } - } - } + }} {...props} > {children} @@ -216,32 +143,44 @@ const AnchorButton = React.forwardRef((props: AnchorButtonProps, ref) => { * A handle and indicator of a block's position in the document */ export const Anchor = (props: AnchorProps) => { - const { isClosedWithChildren, anchorElement, shouldShowDebugDetails, block } = props; - - const anchor = ( - {anchorElements[ anchorElement ] || anchorElements[ 'circle' ]} - ); - - if (!shouldShowDebugDetails) { - return anchor - } else { - return ( - setIsOpen(false)}> + { + e.preventDefault(); + e.stopPropagation(); + setIsOpen(true); + }} + isClosedWithChildren={isClosedWithChildren} + {...props} + as={MenuButton} > - - {anchor} - - - - - {propertiesList(block)} - - - - ) - } + {anchorElements[ anchorElement ] || anchorElements[ 'circle' ]} + + + + Copy block refs + Copy unformatted + {shouldShowDebugDetails && ( + <> + + + + {propertiesList(block)} + + + )} + + + + ) }; diff --git a/src/js/components/Block/components/Toggle.tsx b/src/js/components/Block/components/Toggle.tsx index 29719f1b4e..389990cc32 100644 --- a/src/js/components/Block/components/Toggle.tsx +++ b/src/js/components/Block/components/Toggle.tsx @@ -1,76 +1,5 @@ import React from 'react' -import { IconButton, Tooltip, Box, Text } from '@chakra-ui/react'; -import styled from 'styled-components'; -import { useFocusRing } from '@react-aria/focus'; -import { mergeProps } from '@react-aria/utils'; - -export const ToggleButton = styled.button` - width: 1em; - grid-area: toggle; - height: 2em; - position: relative; - z-index: 2; - flex-shrink: 0; - display: flex; - background: none; - border: none; - transition: color 0.05s ease; - align-items: center; - justify-content: center; - cursor: pointer; - color: inherit; - padding: 0; - -webkit-appearance: none; - color: var(--body-text-color---opacity-low); - - &:focus { - outline: none; - } - - &:hover { - color: var(--body-text-color---opacity-med); - } - - &:before { - content: ''; - inset: 0.25rem -0.125rem; - z-index: -1; - position: absolute; - transition: opacity 0.1s ease; - border-radius: 0.25rem; - opacity: 0; - background: var(--background-plus-2); - box-shadow: var(--depth-shadow-8); - } - - &:hover:before, - &:focus-visible:before { - opacity: 1; - } - - svg { - transform: rotate(90deg); - vector-effect: non-scaling-stroke; - transition: transform 0.1s ease-in-out; - } - - &.closed { - svg { - transform: rotate(0deg); - }; - } - - &:empty { - pointer-events: none; - } -`; - -const FocusRing = styled.div` - position: absolute; - inset: 0.25rem -0.125rem; - border: 2px solid var(--link-color); - border-radius: 0.25rem; -`; +import { IconButton } from '@chakra-ui/react'; interface ToggleProps extends React.HTMLAttributes { isOpen: boolean; @@ -80,16 +9,52 @@ interface ToggleProps extends React.HTMLAttributes { * Button to toggle the visibility of a block's child blocks. */ export const Toggle = React.forwardRef((props: ToggleProps, ref) => { - const { isFocusVisible, focusProps } = useFocusRing(); const { isOpen, } = props; return ( - { - {isFocusVisible && } - + ) }); diff --git a/src/js/components/PresenceDetails/PresenceDetails.tsx b/src/js/components/PresenceDetails/PresenceDetails.tsx index ef2da69a29..dfe12f36d3 100644 --- a/src/js/components/PresenceDetails/PresenceDetails.tsx +++ b/src/js/components/PresenceDetails/PresenceDetails.tsx @@ -1,13 +1,12 @@ import styled, { keyframes } from "styled-components"; import React from "react"; -import { Text, Heading, VStack, Divider, Avatar, AvatarGroup, Menu, MenuDivider, MenuButton, MenuList, MenuGroup, MenuItem, Button, Popover, PopoverTrigger, PopoverContent, Portal, PopoverBody } from '@chakra-ui/react'; +import { Text, Tooltip, Avatar, AvatarGroup, Menu, MenuDivider, MenuButton, MenuList, MenuGroup, MenuItem, Button, Portal } from '@chakra-ui/react'; import { RefreshDouble, Lock } from "iconoir-react"; import { ProfileSettingsDialog } from "@/ProfileSettingsDialog"; import { ConnectedGraphConnection } from "@/Icons/ConnectedGraphConnection"; -import { ConnectedGraphHost } from "@/Icons/ConnectedGraphHost"; import { Icon } from "@/Icons/Icon"; const rotate = keyframes` @@ -79,13 +78,43 @@ export interface PresenceDetailsProps { connectionStatus: ConnectionStatus; defaultOpen?: boolean; } - -interface PresenceDetailsPopoverProps { - children: React.ReactNode; - isOpen: boolean; - onClose: () => void; +interface ConnectionButtonProps { + connectionStatus: ConnectionStatus; + showablePersons: Person[]; } +const ConnectionButton = React.forwardRef((props: ConnectionButtonProps, ref) => { + const { connectionStatus, showablePersons } = props; + return ( + + + + ) +}); + + export const PresenceDetails = (props: PresenceDetailsProps) => { const { hostAddress, @@ -96,7 +125,6 @@ export const PresenceDetails = (props: PresenceDetailsProps) => { handlePressMember, handleUpdateProfile, connectionStatus, - defaultOpen, } = props; const showablePersons = [ ...currentPageMembers, ...differentPageMembers ]; const [ shouldShowProfileSettings, setShouldShowProfileSettings ] = React.useState(false); @@ -106,26 +134,10 @@ export const PresenceDetails = (props: PresenceDetailsProps) => { ) : ( <> - - - + <> @@ -190,7 +202,7 @@ export const PresenceDetails = (props: PresenceDetailsProps) => { marginBlock={-1} size="xs" name={member.username} - color={member.color} + bg={member.color} />} > {member.username} diff --git a/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx b/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx index 8f599852a0..078b4eb2c3 100644 --- a/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx +++ b/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.tsx @@ -2,8 +2,23 @@ import React from 'react'; import { keyframes, - Modal, ModalOverlay, ModalFooter, Center, Flex, Box, - ButtonGroup, ModalHeader, ModalCloseButton, ModalContent, ModalBody, Text, Heading, VStack, Divider, FormControl, FormHelperText, Input, Avatar, AvatarGroup, Menu, MenuDivider, MenuButton, MenuList, MenuGroup, MenuItem, Button, Popover, PopoverTrigger, PopoverContent, Portal, PopoverBody, AvatarBadge + Modal, + ModalOverlay, + ModalFooter, + Center, + Flex, + Box, + ButtonGroup, + ModalHeader, + ModalCloseButton, + ModalContent, + ModalBody, + Text, + FormControl, + FormHelperText, + Input, + Avatar, + Button } from '@chakra-ui/react'; import { HexColorPicker } from "react-colorful"; diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js index 50995da690..282c8e8a10 100644 --- a/src/js/theme/theme.js +++ b/src/js/theme/theme.js @@ -14,6 +14,10 @@ const shadows = { page: '0 0.25rem 1rem #00000055', } +const fonts = { + code: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace', +} + const radii = { none: '0', sm: '0.25rem', @@ -36,13 +40,8 @@ const colors = { backgroundColorLight: "#F6F6F6", backgroundMinus1Light: "#FAF8F6", backgroundMinus2Light: "#EFEDEB", - backgroundVibrancyLight: "#ffffff55", - confirmationLight: "#009E23", - headerLight: "#322F38", - bodyLight: "#433F38", - borderLight: "hsla(32, 81%, 10: 0.08)", errorLight: "#fd5243", shadowLight: "#000", @@ -52,7 +51,6 @@ const colors = { backgroundColorDark: "#1A1A1A", backgroundPlus1Dark: "#222", backgroundPlus2Dark: "#333", - backgroundVibrancyDark: "#222222cc", linkDark: "#498eda", @@ -62,10 +60,6 @@ const colors = { highlightContrastDark: "#000", warningDark: "#DE3C21", - confirmationDark: "#189E36", - headerDark: "#BABABA", - bodyDark: "#AAA", - borderDark: "hsla(32, 81%, 90%, 0.08)", errorDark: "#fd5243", shadowDark: "#000", } @@ -148,22 +142,22 @@ const semanticTokens = { }, // status colors danger: { - default: 'red', - _dark: 'red' + default: 'warningLight', + _dark: 'warningDark' + }, + info: { + default: 'linkLight', + _dark: 'linkDark' }, warning: { default: 'warningLight', _dark: 'warningDark' }, - confirmation: { + success: { default: 'confirmationLight', _dark: 'confirmationDark' }, // other colors - headerText: { - default: 'headerLight', - _dark: 'headerDark' - }, textHighlight: { default: 'textHighlightLight', _dark: 'textHighlightDark' @@ -183,18 +177,65 @@ const semanticTokens = { linkContrast: { default: 'linkContrastLight', _dark: 'linkContrastDark' + }, + // block content colors + "ref.feature": { + default: "#fbbe6322", + _dark: "#fbbe6322", + } + } +} + +const makeAvatarColor = (bg, color) => { + if (bg && color) { + return { + col: bg, + color: color, + } + } else if (bg && !color) { + return { + bg: bg, + color: readableColor(bg) + } + } else if (color && !bg) { + return { + bg: readableColor(color), + color: color, } } } const components = { - Avatar: { - baseStyle: { - container: { - borderColor: "background.floor" - }, + Alert: { + variants: { + // variant used by toasts + solid: ({ colorScheme }) => ({ + container: { + bg: 'background.vibrancy', + backdropFilter: "blur(20px)", + border: "1px solid", + borderColor: "separator.divider", + color: "foreground.primary", + }, + title: { + fontWeight: "normal" + }, + icon: { + color: colorScheme || "info" + } + }) } }, + Avatar: { + baseStyle: ({ bg, color }) => { + return { + container: { + borderColor: "background.floor", + ...makeAvatarColor(bg, color) + }, + } + }, + }, Accordion: { baseStyle: { button: { @@ -214,16 +255,14 @@ const components = { baseStyle: { separator: { color: 'separator.border' - } + }, } }, Button: { baseStyle: { color: 'foreground.primary', _active: { - transitionDuration: '0s', - color: 'linkContrast', - bg: 'link', + transitionDuration: "0s", }, _focus: { outline: 'none', @@ -236,7 +275,14 @@ const components = { }, variants: { link: { - color: "foreground.primary" + color: "link", + borderRadius: "unset" + }, + solid: { + _active: { + color: 'foreground.primary', + bg: 'background.attic', + }, } }, colorSchemes: { @@ -254,9 +300,7 @@ const components = { baseStyle: { fontSize: "1em", _active: { - transitionDuration: '0s', - color: 'linkContrast', - bg: 'link', + transitionDuration: "0s", }, _focus: { outline: 'none', @@ -266,17 +310,30 @@ const components = { outline: 'none', boxShadow: 'focus' } + }, + variants: { + solid: { + _active: { + color: 'linkContrast', + bg: 'link', + }, + } } }, Menu: { baseStyle: { list: { zIndex: 3, + overflow: 'hidden', + py: 0, bg: 'background.upper', shadow: 'menu' }, groupTitle: { - color: "foreground.secondary" + color: "foreground.secondary", + textTransform: "uppercase", + fontSize: "0.75em", + fontWeight: "bold", } }, sizes: { @@ -416,4 +473,4 @@ const sizes = { ...spacing } -export const theme = extendTheme({ config, radii, colors, shadows, semanticTokens, spacing, sizes, components, styles }); +export const theme = extendTheme({ config, radii, fonts, colors, shadows, semanticTokens, spacing, sizes, components, styles }); From 8ca8f05c13ad90dda5bc113986f6c0790d246d60 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Sun, 27 Mar 2022 14:25:54 -0400 Subject: [PATCH 12/79] improvment: misc cleanpu --- src/cljs/athens/events.cljs | 12 +--- src/cljs/athens/views.cljs | 2 +- src/cljs/athens/views/left_sidebar.cljs | 1 + src/cljs/athens/views/pages/block_page.cljs | 56 +++++++++---------- src/cljs/athens/views/pages/core.cljs | 7 +-- src/cljs/athens/views/pages/daily_notes.cljs | 56 +++++++++---------- src/cljs/athens/views/pages/header.cljs | 58 ++++++++++++++++++++ src/cljs/athens/views/pages/node_page.cljs | 52 ++---------------- src/cljs/athens/views/pages/page.cljs | 6 ++ src/cljs/athens/views/pages/settings.cljs | 8 +-- src/cljs/athens/views/references.cljs | 3 +- src/cljs/athens/views/right_sidebar.cljs | 11 +--- 12 files changed, 138 insertions(+), 134 deletions(-) create mode 100644 src/cljs/athens/views/pages/header.cljs diff --git a/src/cljs/athens/events.cljs b/src/cljs/athens/events.cljs index 5799d91755..28ec0b2137 100644 --- a/src/cljs/athens/events.cljs +++ b/src/cljs/athens/events.cljs @@ -1,7 +1,5 @@ (ns athens.events (:require - ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [createStandaloneToast]] [athens.athens-datoms :as athens-datoms] [athens.common-db :as common-db] [athens.common-events :as common-events] @@ -39,10 +37,6 @@ [re-frame.core :as rf :refer [reg-event-db reg-event-fx subscribe]])) -(def toast (createStandaloneToast (clj->js {:theme theme}))) - - - ;; -- re-frame app-db events --------------------------------------------- (reg-event-fx @@ -872,7 +866,7 @@ :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) {}) (catch :default _ - {:fx (toast (clj->js {:status "error" + {:fx (util/toast (clj->js {:status "error" :title "Couldn't undo" :description "Undo for this operation not supported in Lan-Party, yet."}))})))) @@ -896,7 +890,7 @@ :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) {}) (catch :default _ - {:fx (toast (clj->js {:status "error" + {:fx (util/toast (clj->js {:status "error" :title "Couldn't redo" :description "Redo for this operation not supported in Lan-Party, yet."}))})))) @@ -1567,7 +1561,7 @@ (re-find #"text/html" datatype) (.getAsString item (fn [_] #_(prn "getAsString" _)))))) items) {}) - {:fx (toast (clj->js {:status "error" + {:fx (util/toast (clj->js {:status "error" :title "Couldn't paste" :description "Image paste is not supported in Lan-Party, yet."}))})))) diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 1cbc2a8979..0f7db8ede6 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -1,7 +1,7 @@ (ns athens.views (:require ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [ChakraProvider Flex Grid Spinner Center createStandaloneToast]] + ["@chakra-ui/react" :refer [ChakraProvider Flex Grid Spinner Center]] ["@react-aria/overlays" :refer [OverlayProvider]] [athens.config] [athens.electron.db-modal :as db-modal] diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index a117531ae9..1fabd1339e 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -37,6 +37,7 @@ :flex "1" :border "none" :bg "transparent" + :borderRadius "md" :boxShadow "0 0 0 0.25rem transparent" :_focus {:outline "none"} :_hover {:bg "background.upper"} diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index 1851ff0e76..73072e9c39 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -1,15 +1,15 @@ (ns athens.views.pages.block-page (:require - ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink Heading]] + ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink]] ["@material-ui/icons/Link" :default Link] [athens.parse-renderer :as parse-renderer] [athens.reactive :as reactive] [athens.router :as router] [athens.views.blocks.core :as blocks] + [athens.views.pages.header :refer [editable-title-container]] [athens.views.pages.node-page :as node-page] [komponentit.autosize :as autosize] [re-frame.core :as rf :refer [dispatch subscribe]] - [athens.views.references :refer [reference-group reference-block]] [reagent.core :as r] [stylefy.core :as stylefy :refer [use-style]])) @@ -105,36 +105,36 @@ [parents-el uid id] ;; Header - [:> Heading {:size "lg" - :_hover {:textDecoration "underline"} - :onClick (fn [e] - (.. e preventDefault) - (if (.. e -shiftKey) - (do - (rf/dispatch [:reporting/navigation {:source :block-page - :target :block - :pane :right-pane}]) - (router/navigate-uid uid e)) - (dispatch [:editing/uid uid])))} - [autosize/textarea - {:id (str "editable-uid-" uid) - :value (:string/local @state) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :auto-focus true - :on-blur (fn [_] (persist-textarea-string @state uid)) - :on-key-down (fn [e] (node-page/handle-key-down e uid state nil)) - :on-change (fn [e] (block-page-change e uid state))}] - (if (clojure.string/blank? (:string/local @state)) - [:wbr] - [:span [parse-renderer/parse-and-render (:string/local @state) uid]])] + [editable-title-container {:onClick (fn [e] + (.. e preventDefault) + (if (.. e -shiftKey) + (do + (rf/dispatch [:reporting/navigation {:source :block-page + :target :block + :pane :right-pane}]) + (router/navigate-uid uid e)) + + (dispatch [:editing/uid uid])))} + [:<> + [autosize/textarea + {:id (str "editable-uid-" uid) + :value (:string/local @state) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :auto-focus true + :on-blur (fn [_] (persist-textarea-string @state uid)) + :on-key-down (fn [e] (node-page/handle-key-down e uid state nil)) + :on-change (fn [e] (block-page-change e uid state))}] + (if (clojure.string/blank? (:string/local @state)) + [:wbr] + [:span [parse-renderer/parse-and-render (:string/local @state) uid]])]] ;; Children - [:div (for [child children] - (let [{:keys [db/id]} child] - ^{:key id} [blocks/block-el child]))] + [:div (for [child children] + (let [{:keys [db/id]} child] + ^{:key id} [blocks/block-el child]))] ;; Refs - [linked-refs-el id]])))) + [linked-refs-el id]])))) (defn page diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs index 170fa12831..6b96484f71 100644 --- a/src/cljs/athens/views/pages/core.cljs +++ b/src/cljs/athens/views/pages/core.cljs @@ -1,7 +1,7 @@ (ns athens.views.pages.core (:require - ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [Box createStandaloneToast]] + ["@chakra-ui/react" :refer [Box]] + [athens.util :refer [toast]] [athens.views.hoc.perf-mon :as perf-mon] [athens.views.pages.all-pages :as all-pages] [athens.views.pages.daily-notes :as daily-notes] @@ -11,9 +11,6 @@ [re-frame.core :as rf])) -(def toast (createStandaloneToast (clj->js {:theme theme}))) - - ;; View diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index 70851afea7..950489d4a6 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -1,8 +1,9 @@ (ns athens.views.pages.daily-notes (:require - ["@chakra-ui/react" :refer [Heading Box VStack]] + ["@chakra-ui/react" :refer [Box VStack]] [athens.dates :as dates] [athens.reactive :as reactive] + [athens.views.pages.header :refer [title-container]] [athens.views.pages.node-page :as node-page] [re-frame.core :refer [dispatch subscribe]])) @@ -16,6 +17,26 @@ (keep #(reactive/get-reactive-block-document [:block/uid %]) ids)) + +(defn daily-notes-page + ([props children] + (let [{:keys [real?]} props] + [:> Box {:boxShadow "page", + :bg "background.floor" + :alignSelf "stretch" + :justifySelf "stretch" + :opacity (if real? 1 0.5) + :px 14 + :py 14 + :borderWidth "1px" + :borderStyle "solid" + :borderColor "separator.divider" + :transitionDuration "0s" + :borderRadius "0.5rem" + :minHeight "calc(100vh - 10rem)"} + children]))) + + ;; Components @@ -37,31 +58,8 @@ :flexDirection "column"} (doall (for [{:keys [block/uid]} notes] - ^{:key uid} - [:<> - [:> Box {:boxShadow "page", - :bg "background.floor" - :alignSelf "stretch" - :justifySelf "stretch" - :px "2rem" - :borderWidth "1px" - :borderStyle "solid" - :borderColor "separator.divider" - :transitionDuration "0s" - :borderRadius "0.5rem" - :minHeight "calc(100vh - 10rem)"} - [node-page/page [:block/uid uid]]]])) - [:> Box {:boxShadow "page", - :bg "background.floor" - :alignSelf "stretch" - :justifySelf "stretch" - :margin "1.25rem 2.5rem" - :padding "1rem 2rem" - :borderWidth "1px" - :borderStyle "solid" - :borderColor "separator.divider" - :transitionDuration "0s" - :borderRadius "0.5rem" - :minHeight "calc(100vh - 10rem)" - :opacity "0.5"} - [:> Heading {:ml 10} "Earlier"]]]))))) + [daily-notes-page {:key uid + :real? true} + [node-page/page [:block/uid uid]]])) + [daily-notes-page {:real? false} + [title-container "Earlier"]]]))))) diff --git a/src/cljs/athens/views/pages/header.cljs b/src/cljs/athens/views/pages/header.cljs new file mode 100644 index 0000000000..4e2066f3df --- /dev/null +++ b/src/cljs/athens/views/pages/header.cljs @@ -0,0 +1,58 @@ +(ns athens.views.pages.header + (:require + ["@chakra-ui/react" :refer [Box]])) + + +(def title-style-props + {:position "relative" + :fontSize "2rem" + :overflow "visible" + :flex-grow "1" + :margin "0.5em 0" + :whiteSpace "pre-line" + :wordBreak "break-word" + :fontWeight "bold"}) + + +(defn title-container + [children] + [:> Box title-style-props + children]) + + +(defn editable-title-container + ([props children] + (let [{:keys [_]} props] + [:> Box (merge + title-style-props + {:as "header" + :class "page-header" + :sx {"textarea" {:appearance "none" + :cursor "text" + :resize "none" + :transform "translate3d(0,0,0)" + :color "inherit" + :fontWeight "inherit" + :padding "0" + :letterSpacing "inherit" + :width "100%" + :minHeight "100%" + :caretColor "link" + :background "transparent" + :margin "0" + :fontSize "inherit" + :lineHeight "inherit" + :borderRadius "0.25rem" + :transition "opacity 0.15s ease" + :border "0" + :fontFamily "inherit" + :visibility "hidden" + :position "absolute"} + {"textarea ::WebkitScrollbar" {:display "none"}} + {".is-editing textarea:focus" {:outline "none" + :visibility "visible" + :position "relative"}} + "abbr" {:z-index 4} + ".is-editing span" {:visibility "hidden" + :position "absolute"}}}) + children]))) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 4b246666f2..41ffd5afc1 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -2,7 +2,7 @@ (:require ["/components/Block/components/Anchor" :refer [Anchor]] ["/components/Dialog/Dialog" :refer [Dialog]] - ["@chakra-ui/react" :refer [Box Button Portal Heading IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] + ["@chakra-ui/react" :refer [Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] ["@material-ui/icons/Bookmark" :default Bookmark] ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] ["@material-ui/icons/BubbleChart" :default BubbleChart] @@ -20,8 +20,9 @@ [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] [athens.views.blocks.core :as blocks] [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.references :refer [reference-group reference-block]] [athens.views.hoc.perf-mon :as perf-mon] + [athens.views.pages.header :refer [editable-title-container]] + [athens.views.references :refer [reference-group reference-block]] [clojure.string :as str] [datascript.core :as d] [komponentit.autosize :as autosize] @@ -38,37 +39,6 @@ {:position "relative"}) -(def title-inner-style - {"textarea" {:appearance "none" - :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :fontWeight "inherit" - :padding "0" - :letterSpacing "inherit" - :width "100%" - :minHeight "100%" - :caretColor "link" - :background "transparent" - :margin "0" - :fontSize "inherit" - :lineHeight "inherit" - :borderRadius "0.25rem" - :transition "opacity 0.15s ease" - :border "0" - :fontFamily "inherit" - :visibility "hidden" - :position "absolute"} - ["textarea" ["::WebkitScrollbar" {:display "none"}]] - [".is-editing textarea:focus" {:outline "none" - :visibility "visible" - :position "relative"}] - "abbr" {:z-index 4} - ".is-editing span" {:visibility "hidden" - :position "absolute"}}) - - (def references-style {:margin-top "3em"}) @@ -377,7 +347,8 @@ :align "stretch"} (doall (for [[group-title group] linked-refs] - [reference-group {:title group-title + [reference-group {:key (str "group-" group-title) + :title group-title :on-click-title (fn [e] (let [shift? (.-shiftKey e) parsed-title (parse-renderer/parse-title group-title)] @@ -501,21 +472,10 @@ ;; Dropdown [menu-dropdown node daily-note?] - [:> Heading {:data-uid uid - :class "page-header" - :position "relative" - :overflow "visible" - :flex-grow "1" - :margin "0.10em 0 0.10em 1rem" - :letter-spacing "-0.03em" - :white-space "pre-line" - :word-break "break-word" - :line-height "1.40em" - :sx title-inner-style} + [editable-title-container ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. - (when-not daily-note? [autosize/textarea {:value (:title/local @state) diff --git a/src/cljs/athens/views/pages/page.cljs b/src/cljs/athens/views/pages/page.cljs index 537ed741cf..1afbd749aa 100644 --- a/src/cljs/athens/views/pages/page.cljs +++ b/src/cljs/athens/views/pages/page.cljs @@ -44,3 +44,9 @@ title [node-page/page id] string [block-page/page id] :else [:h3 "404: This page doesn't exist"])])) + + +(defn editable-title-container + [props children] + [:> Box (merge props {:as "header"}) + children]) \ No newline at end of file diff --git a/src/cljs/athens/views/pages/settings.cljs b/src/cljs/athens/views/pages/settings.cljs index be39d601e4..09ee22e656 100644 --- a/src/cljs/athens/views/pages/settings.cljs +++ b/src/cljs/athens/views/pages/settings.cljs @@ -1,8 +1,8 @@ (ns athens.views.pages.settings (:require - ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [createStandaloneToast Text Heading Box FormControl FormLabel ButtonGroup Grid Input Button Switch Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] + ["@chakra-ui/react" :refer [Text Heading Box FormControl FormLabel ButtonGroup Grid Input Button Switch Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] [athens.db :refer [default-athens-persist]] + [athens.util :refer [toast]] [cljs-http.client :as http] [cljs.core.async :refer [ Box {:as "section" - :key "Inline Linked References" + [:> Box {:as "aside" :ml 6 :borderRadius "md" :background "background.basement"} diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index d873ecf493..3530925047 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,10 +1,7 @@ (ns athens.views.right-sidebar (:require ["@chakra-ui/react" :refer [Flex Text Box AddIcon IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] - ["@material-ui/icons/BubbleChart" :default BubbleChart] ["@material-ui/icons/Close" :default Close] - ["@material-ui/icons/Description" :default Description] - ["@material-ui/icons/FiberManualRecord" :default FiberManualRecord] ["@material-ui/icons/VerticalSplit" :default VerticalSplit] ["framer-motion" :refer [AnimatePresence motion]] [athens.parse-renderer :as parse-renderer] @@ -123,12 +120,10 @@ ^{:key uid} [:> AccordionItem {:_first {:borderTop 0}} [:> Box {:as "h2" :position "relative"} - [:> AccordionButton + [:> AccordionButton {:borderBottom "1px solid" + :borderBottomColor "separator.divider"} [:> AccordionIcon {:as AddIcon}] - (cond - is-graph? [:<> [:> BubbleChart] [parse-renderer/parse-and-render title uid]] - title [:<> [:> Description] [parse-renderer/parse-and-render title uid]] - :else [:<> [:> FiberManualRecord] [parse-renderer/parse-and-render string uid]])] + [parse-renderer/parse-and-render (or title string) uid]] [:> IconButton {:size "sm" :position "absolute" :right 1 From 4805316a92415994a0e61bdc85358d5d26614aea Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Mon, 28 Mar 2022 17:08:13 -0400 Subject: [PATCH 13/79] fix misplaced anchor menu --- src/js/components/Block/components/Anchor.tsx | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/src/js/components/Block/components/Anchor.tsx b/src/js/components/Block/components/Anchor.tsx index 0b6144bc72..0c3f6feb5f 100644 --- a/src/js/components/Block/components/Anchor.tsx +++ b/src/js/components/Block/components/Anchor.tsx @@ -1,11 +1,11 @@ import React, { ReactNode } from 'react'; -import { Menu, MenuList, MenuItem, MenuGroup, MenuDivider, MenuButton, IconButton, Portal, Box, Text } from '@chakra-ui/react'; +import { Menu, MenuList, MenuItem, MenuGroup, MenuDivider, MenuButton, IconButton, Portal, Box, Text, ButtonProps } from '@chakra-ui/react'; -const anchorElements = { - circle: +const ANCHORS = { + CIRCLE: , - dash: + DASH: } @@ -71,42 +71,37 @@ export interface AnchorProps { onContextMenu: (event: React.MouseEvent) => void; onCopyRefs: () => void; onCopyUnformatted: () => void; + onDragStart: () => void; + onDragEnd: () => void; + onClick: () => void; } -interface AnchorButtonProps { - children: ReactNode; - isClosedWithChildren: boolean; -} - -const AnchorButton = React.forwardRef((props: AnchorButtonProps, ref) => { - const { children, isClosedWithChildren } = props; - - return ( { + return ({ + bg: "transparent", + "aria-label": "Block anchor", + className: [ 'anchor', isClosedWithChildren && 'closed-with-children' ].filter(Boolean).join(' '), + draggable: true, + gridArea: "bullet", + flexShrink: 0, + position: 'relative', + appearance: "none", + border: "0", + color: "inherit", + mr: 0.25, + display: "flex", + placeItems: "center", + placeContent: "center", + zIndex: 2, + minWidth: "0", + minHeight: "0", + h: "2em", + w: "1.25em", + fontSize: "inherit", + mx: "-0.125em", + size: "sm", + p: 0, + sx: { "svg": { pointerEvents: "none", transform: "scale(1.0001)", // Prevents the bullet being squished @@ -130,13 +125,9 @@ const AnchorButton = React.forwardRef((props: AnchorButtonProps, ref) => { fill: "none", }) } - }} - {...props} - > - {children} - ); -} -); + } + }) +}; /** @@ -148,24 +139,33 @@ export const Anchor = (props: AnchorProps) => { shouldShowDebugDetails, onCopyRefs, onCopyUnformatted, + onContextMenu, + onDragStart, + onDragEnd, + onClick, block } = props; const [ isOpen, setIsOpen ] = React.useState(false); return ( setIsOpen(false)}> - { + console.log(e); e.preventDefault(); e.stopPropagation(); setIsOpen(true); }} - isClosedWithChildren={isClosedWithChildren} - {...props} as={MenuButton} > - {anchorElements[ anchorElement ] || anchorElements[ 'circle' ]} - + {ANCHORS[ anchorElement ] || ANCHORS.CIRCLE} + Copy block refs From 4b257b9b36f99d62e8311fa4699db059c46ebdf1 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Mon, 28 Mar 2022 17:08:27 -0400 Subject: [PATCH 14/79] fix incorrect size for presence button --- src/js/components/PresenceDetails/PresenceDetails.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/components/PresenceDetails/PresenceDetails.tsx b/src/js/components/PresenceDetails/PresenceDetails.tsx index dfe12f36d3..8f9d835e30 100644 --- a/src/js/components/PresenceDetails/PresenceDetails.tsx +++ b/src/js/components/PresenceDetails/PresenceDetails.tsx @@ -90,6 +90,7 @@ const ConnectionButton = React.forwardRef((props: ConnectionButtonProps, ref) => - - {isOpen && {body}} - ) -}; diff --git a/src/js/components/concept/RightSidebar/index.ts b/src/js/components/concept/RightSidebar/index.ts deleted file mode 100644 index 03e2ab657e..0000000000 --- a/src/js/components/concept/RightSidebar/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { RightSidebar } from './RightSidebar'; -export { RightSidebar } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index dc2ce6dbb7..405f3534fc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1948,7 +1948,7 @@ compute-scroll-into-view "1.0.14" copy-to-clipboard "3.3.1" -"@chakra-ui/icon@2.0.5", "@chakra-ui/icon@^2.0.5": +"@chakra-ui/icon@2.0.5": version "2.0.5" resolved "https://registry.yarnpkg.com/@chakra-ui/icon/-/icon-2.0.5.tgz#d57f53e6a2c7ae1bae7292a1778fd466c02e2e29" integrity sha512-ZrqRvCCIxGr4qFd/r1pmtd9tobRmv8KAxV7ygFoc/t4vOSKTcVIjhE12gsI3FzgvXM15ZFVwsxa1zodwgo5neQ== From 99b7fc877376c9f996f43995a60612ca7554b492 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Tue, 29 Mar 2022 23:19:34 -0400 Subject: [PATCH 32/79] chore: cleanup lint --- .../athens/views/blocks/autocomplete_search.cljs | 2 +- .../athens/views/blocks/autocomplete_slash.cljs | 2 +- src/cljs/athens/views/blocks/core.cljs | 16 +++++++++------- src/cljs/athens/views/pages/node_page.cljs | 4 ++-- src/cljs/athens/views/references.cljs | 9 --------- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/cljs/athens/views/blocks/autocomplete_search.cljs b/src/cljs/athens/views/blocks/autocomplete_search.cljs index 0dc5d33770..9417cae7ef 100644 --- a/src/cljs/athens/views/blocks/autocomplete_search.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_search.cljs @@ -17,7 +17,7 @@ (defn inline-search-el - [_block state] + [_block #_ state] (fn [block state] (let [open? (some #(= % type) [:page :block :hashtag :template]) {:search/keys [query results index type] caret-position :caret-position} @state diff --git a/src/cljs/athens/views/blocks/autocomplete_slash.cljs b/src/cljs/athens/views/blocks/autocomplete_slash.cljs index d28d94b62b..abb07facfd 100644 --- a/src/cljs/athens/views/blocks/autocomplete_slash.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_slash.cljs @@ -13,7 +13,7 @@ (defn slash-menu-el - [_block state] + [_block #_ state] (fn [block state] (let [{:search/keys [index results type] caret-position :caret-position} @state {:keys [left top]} caret-position] diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index 06d1138f49..dade4b94f6 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -13,7 +13,9 @@ [athens.router :as router] [athens.self-hosted.presence.views :as presence] [athens.subs.selection :as select-subs] - [athens.util :as util :refer [mouse-offset vertical-center specter-recursive-path]] + [athens.util :as util :refer [mouse-offset vertical-center + ; specter-recursive-path + ]] [athens.views.blocks.autocomplete-search :as autocomplete-search] [athens.views.blocks.autocomplete-slash :as autocomplete-slash] [athens.views.blocks.bullet :refer [bullet-drag-start bullet-drag-end]] @@ -21,7 +23,7 @@ [athens.views.blocks.context-menu :refer [handle-copy-unformatted handle-copy-refs]] [athens.views.blocks.drop-area-indicator :as drop-area-indicator] [athens.views.references :refer [reference-group reference-block]] - [com.rpl.specter :as s] + ;; [com.rpl.specter :as s] [goog.functions :as gfns] [re-frame.core :as rf] [reagent.core :as r])) @@ -382,11 +384,11 @@ children _refs]} (merge (reactive/get-reactive-block-document ident) block) children-uids (set (map :block/uid children)) - uid-sanitized-block (s/transform - (specter-recursive-path #(contains? % :block/uid)) - (fn [{:block/keys [original-uid uid] :as block}] - (assoc block :block/uid (or original-uid uid))) - block) + ;; uid-sanitized-block (s/transform + ;; (specter-recursive-path #(contains? % :block/uid)) + ;; (fn [{:block/keys [original-uid uid] :as block}] + ;; (assoc block :block/uid (or original-uid uid))) + ;; block) {:keys [dragging]} @state is-editing @(rf/subscribe [:editing/is-editing uid]) is-selected @(rf/subscribe [::select-subs/selected? uid]) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 644b455842..8d76e6fe8c 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -303,7 +303,7 @@ :color "foreground.secondary" :borderRadius "full"} (count linked-refs)]]] - [:> AccordionPanel {:px 0} + [:> AccordionPanel {:p 0} [:> VStack {:spacing 6 :pl 9 :align "stretch"} @@ -362,7 +362,7 @@ (reset! unlinked-refs []))} "Link All"])] - [:> AccordionPanel {:px 0} + [:> AccordionPanel {:p 0} [:> VStack {:spacing 6 :pl 1 :align "stretch"} diff --git a/src/cljs/athens/views/references.cljs b/src/cljs/athens/views/references.cljs index 1b06da185c..2c4e656a04 100644 --- a/src/cljs/athens/views/references.cljs +++ b/src/cljs/athens/views/references.cljs @@ -3,15 +3,6 @@ ["@chakra-ui/react" :refer [Box Button Heading VStack]])) -(defn references-container - ([_ children] - [:> Box {:as "aside" - :ml 6 - :borderRadius "md" - :background "background.basement"} - children])) - - (defn reference-header ([props] (let [{:keys [on-click title]} props] From 008011b9c0f62e1cf66852b912ca0dd3861c152a Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Tue, 29 Mar 2022 23:19:57 -0400 Subject: [PATCH 33/79] chore: style cleanup --- src/cljs/athens/components.cljs | 20 +- src/cljs/athens/effects.cljs | 36 +- src/cljs/athens/electron/db_menu/core.cljs | 35 +- src/cljs/athens/electron/db_menu/db_icon.cljs | 5 +- .../athens/electron/db_menu/db_list_item.cljs | 32 +- .../electron/db_menu/status_indicator.cljs | 8 +- src/cljs/athens/electron/db_modal.cljs | 53 +- src/cljs/athens/events.cljs | 1864 ++++++++--------- src/cljs/athens/parse_renderer.cljs | 364 ++-- .../athens/self_hosted/presence/views.cljs | 76 +- src/cljs/athens/util.cljs | 19 +- src/cljs/athens/views.cljs | 35 +- src/cljs/athens/views/athena.cljs | 160 +- .../views/blocks/autocomplete_search.cljs | 22 +- .../views/blocks/autocomplete_slash.cljs | 18 +- src/cljs/athens/views/blocks/content.cljs | 193 +- .../athens/views/blocks/context_menu.cljs | 12 +- src/cljs/athens/views/blocks/core.cljs | 120 +- .../views/blocks/drop_area_indicator.cljs | 3 +- .../athens/views/blocks/textarea_keydown.cljs | 48 +- src/cljs/athens/views/devtool.cljs | 42 +- src/cljs/athens/views/help.cljs | 109 +- src/cljs/athens/views/left_sidebar.cljs | 32 +- src/cljs/athens/views/pages/all_pages.cljs | 46 +- src/cljs/athens/views/pages/block_page.cljs | 110 +- src/cljs/athens/views/pages/core.cljs | 21 +- src/cljs/athens/views/pages/daily_notes.cljs | 53 +- src/cljs/athens/views/pages/graph.cljs | 364 ++-- src/cljs/athens/views/pages/header.cljs | 72 +- src/cljs/athens/views/pages/node_page.cljs | 178 +- src/cljs/athens/views/pages/settings.cljs | 55 +- src/cljs/athens/views/references.cljs | 2 +- src/cljs/athens/views/right_sidebar.cljs | 191 +- 33 files changed, 2199 insertions(+), 2199 deletions(-) diff --git a/src/cljs/athens/components.cljs b/src/cljs/athens/components.cljs index d793ff34c6..1d305bf1b2 100644 --- a/src/cljs/athens/components.cljs +++ b/src/cljs/athens/components.cljs @@ -1,15 +1,15 @@ (ns athens.components (:require - ["@chakra-ui/react" :refer [Checkbox Box Button]] - ["@material-ui/icons/Edit" :default Edit] - [athens.db :as db] - [athens.parse-renderer :refer [component]] - [athens.reactive :as reactive] - [athens.util :refer [recursively-modify-block-for-embed]] - [athens.views.blocks.core :as blocks] - [clojure.string :as str] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r])) + ["@chakra-ui/react" :refer [Checkbox Box Button]] + ["@material-ui/icons/Edit" :default Edit] + [athens.db :as db] + [athens.parse-renderer :refer [component]] + [athens.reactive :as reactive] + [athens.util :refer [recursively-modify-block-for-embed]] + [athens.views.blocks.core :as blocks] + [clojure.string :as str] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) (defn todo-on-click diff --git a/src/cljs/athens/effects.cljs b/src/cljs/athens/effects.cljs index 21c7fadca2..2ea70ec0d4 100644 --- a/src/cljs/athens/effects.cljs +++ b/src/cljs/athens/effects.cljs @@ -1,23 +1,23 @@ (ns athens.effects (:require - [athens.async :as async] - [athens.common-db :as common-db] - [athens.common-events.schema :as schema] - [athens.common.logging :as log] - [athens.common.sentry :refer-macros [wrap-span wrap-span-no-new-tx]] - [athens.db :as db] - [athens.reactive :as reactive] - [athens.self-hosted.client :as client] - [cljs-http.client :as http] - [cljs.core.async :refer [go Portal [:> PopoverContent {:overflow-y "auto"} [:> FocusLock [:> VStack {:align "stretch" :overflow "hidden" :spacing 0} - ;; Show active DB first + ;; Show active DB first [:> Box {:bg "background.floor" :pb 4} [db-list-item {:db active-db :is-current true :key (:id active-db)}] [current-db-tools {:db active-db} all-dbs merge-open?]] - ;; Show all inactive DBs and a separator + ;; Show all inactive DBs and a separator [:> Heading {:fontSize "xs" :py 4 :pb 3 :borderTop "1px solid" :borderTopColor "separator.divider" - ;; :bg "background.floor" + ;; :bg "background.floor" :px 10 :letterSpacing "wide" :textTransform "uppercase" @@ -73,11 +74,11 @@ :overflow-y "auto"} {:align "stretch" :spacing 0} (doall - (for [[key db] inactive-dbs] - [db-list-item {:db db - :is-current false - :key key}]))] - ;; Add DB control + (for [[key db] inactive-dbs] + [db-list-item {:db db + :is-current false + :key key}]))] + ;; Add DB control [:> ButtonGroup {:borderTop "1px solid" :borderTopColor "separator.divider" :p 2 :pt 0 :pl 10 :size "sm" :width "100%" :ml 10 :justifyContent "flex-start"} [:> Button {:onClick #(dispatch [:modal/toggle])} "Add Database"]]]]]]]])) diff --git a/src/cljs/athens/electron/db_menu/db_icon.cljs b/src/cljs/athens/electron/db_menu/db_icon.cljs index f9dd467015..14e2e6a6fc 100644 --- a/src/cljs/athens/electron/db_menu/db_icon.cljs +++ b/src/cljs/athens/electron/db_menu/db_icon.cljs @@ -1,7 +1,8 @@ (ns athens.electron.db-menu.db-icon (:require - ["@chakra-ui/react" :refer [Box]] - [athens.electron.db-menu.status-indicator :refer [status-indicator]])) + ["@chakra-ui/react" :refer [Box]] + [athens.electron.db-menu.status-indicator :refer [status-indicator]])) + (defn db-icon [{:keys [db status]}] diff --git a/src/cljs/athens/electron/db_menu/db_list_item.cljs b/src/cljs/athens/electron/db_menu/db_list_item.cljs index fc175d8283..723cb4e7a1 100644 --- a/src/cljs/athens/electron/db_menu/db_list_item.cljs +++ b/src/cljs/athens/electron/db_menu/db_list_item.cljs @@ -1,11 +1,11 @@ (ns athens.electron.db-menu.db-list-item (:require - ["@chakra-ui/react" :refer [VStack Box Flex Text Button IconButton]] - ["@material-ui/icons/Clear" :default Clear] - ["@material-ui/icons/Link" :default Link] - [athens.electron.db-menu.db-icon :refer [db-icon]] - [athens.electron.dialogs :as dialogs] - [re-frame.core :refer [dispatch]])) + ["@chakra-ui/react" :refer [VStack Box Flex Text Button IconButton]] + ["@material-ui/icons/Clear" :default Clear] + ["@material-ui/icons/Link" :default Link] + [athens.electron.db-menu.db-icon :refer [db-icon]] + [athens.electron.dialogs :as dialogs] + [re-frame.core :refer [dispatch]])) (defn active-db @@ -78,16 +78,16 @@ (when (:is-remote db) [:> Link]) (:id db)]]] - (when on-remove - [:> IconButton - {:onClick on-remove - :gridArea "main" - :alignSelf "center" - :justifySelf "flex-end" - :size "sm" - :mr 2 - :bg "transparent"} - [:> Clear]])]) + (when on-remove + [:> IconButton + {:onClick on-remove + :gridArea "main" + :alignSelf "center" + :justifySelf "flex-end" + :size "sm" + :mr 2 + :bg "transparent"} + [:> Clear]])]) (defn db-list-item diff --git a/src/cljs/athens/electron/db_menu/status_indicator.cljs b/src/cljs/athens/electron/db_menu/status_indicator.cljs index 9be5a02215..cab8e5dc60 100644 --- a/src/cljs/athens/electron/db_menu/status_indicator.cljs +++ b/src/cljs/athens/electron/db_menu/status_indicator.cljs @@ -1,9 +1,9 @@ (ns athens.electron.db-menu.status-indicator (:require - ["@chakra-ui/react" :refer [Box Tooltip]] - ["@material-ui/icons/CheckCircle" :default CheckCircle] - ["@material-ui/icons/Error" :default Error] - ["@material-ui/icons/Sync" :default Sync])) + ["@chakra-ui/react" :refer [Box Tooltip]] + ["@material-ui/icons/CheckCircle" :default CheckCircle] + ["@material-ui/icons/Error" :default Error] + ["@material-ui/icons/Sync" :default Sync])) (defn status-indicator diff --git a/src/cljs/athens/electron/db_modal.cljs b/src/cljs/athens/electron/db_modal.cljs index 82d9ded6f3..725bf6dc6c 100644 --- a/src/cljs/athens/electron/db_modal.cljs +++ b/src/cljs/athens/electron/db_modal.cljs @@ -12,7 +12,6 @@ [reagent.core :as r])) - (defn file-cb [e transformed-db roam-db-filename] (let [fr (js/FileReader.) @@ -105,7 +104,6 @@ "Merge"]]]]))]]))) - (defn form-container [content footer] [:> Box {:as "form" @@ -118,7 +116,6 @@ :pr 5} footer]]) - (defn open-local-comp [loading db] [form-container @@ -146,9 +143,6 @@ "Open from file"]]]) - - - (defn create-new-local [state] [form-container @@ -156,12 +150,11 @@ [:> FormLabel "Name"] [:> Input {:value (:input @state) :onChange #(swap! state assoc :input (js-event->val %))}]] - [:> ButtonGroup - [:> Button {:value (:input @state) - :isDisabled (clojure.string/blank? (:input @state)) - :onClick #(dialogs/create-dialog! (:input @state))} - "Choose folder"]]]) - + [:> ButtonGroup + [:> Button {:value (:input @state) + :isDisabled (clojure.string/blank? (:input @state)) + :onClick #(dialogs/create-dialog! (:input @state))} + "Choose folder"]]]) (defn join-remote-comp @@ -172,21 +165,21 @@ (fn [] [form-container (->> - [:> VStack {:spacing 4} - [:> FormControl - [:> FormLabel "Database name"] - [:> Input {:value @name - :onChange #(reset! name (js-event->val %))}]] - [:> FormControl - [:> FormLabel "Remote address"] - [:> Input {:value @address - :onChange #(reset! address (js-event->val %))}]] - [:> FormControl {:flexDirection "row"} - [:> FormLabel "Password"] - [:> Input {:value @password - :type "password" - :onChange #(reset! password (js-event->val %))}]]] - doall) + [:> VStack {:spacing 4} + [:> FormControl + [:> FormLabel "Database name"] + [:> Input {:value @name + :onChange #(reset! name (js-event->val %))}]] + [:> FormControl + [:> FormLabel "Remote address"] + [:> Input {:value @address + :onChange #(reset! address (js-event->val %))}]] + [:> FormControl {:flexDirection "row"} + [:> FormLabel "Password"] + [:> Input {:value @password + :type "password" + :onChange #(reset! password (js-event->val %))}]]] + doall) [:> ButtonGroup [:> Button {:type "submit" :isDisabled (or (clojure.string/blank? @name) @@ -216,9 +209,9 @@ (when-not @loading [:> ModalCloseButton]) [:> ModalBody {:display "contents"} - ;; TODO: this is hacky, we're just hiding the picker and forcing - ;; tab 2 for the web client. Instead we should use Stuart's - ;; redesigned DB picker. + ;; TODO: this is hacky, we're just hiding the picker and forcing + ;; tab 2 for the web client. Instead we should use Stuart's + ;; redesigned DB picker. [:> Tabs {:isFitted true :display "contents" :defaultIndex (if utils/electron? 0 2)} diff --git a/src/cljs/athens/events.cljs b/src/cljs/athens/events.cljs index 28ec0b2137..2b76d3e59f 100644 --- a/src/cljs/athens/events.cljs +++ b/src/cljs/athens/events.cljs @@ -1,92 +1,92 @@ (ns athens.events (:require - [athens.athens-datoms :as athens-datoms] - [athens.common-db :as common-db] - [athens.common-events :as common-events] - [athens.common-events.bfs :as bfs] - [athens.common-events.graph.atomic :as atomic-graph-ops] - [athens.common-events.graph.composite :as composite-ops] - [athens.common-events.graph.ops :as graph-ops] - [athens.common-events.resolver.atomic :as atomic-resolver] - [athens.common-events.resolver.undo :as undo-resolver] - [athens.common-events.schema :as schema] - [athens.common.logging :as log] - [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] - [athens.common.utils :as common.utils] - [athens.dates :as dates] - [athens.db :as db] - [athens.electron.db-picker :as db-picker] - [athens.electron.images :as images] - [athens.electron.monitoring.core] - [athens.electron.utils :as electron.utils] - [athens.events.remote :as events-remote] - [athens.events.sentry] - [athens.interceptors :as interceptors] - [athens.patterns :as patterns] - [athens.undo :as undo] - [athens.util :as util] - [athens.utils.sentry :as sentry] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [clojure.string :as string] - [datascript.core :as d] - [day8.re-frame.async-flow-fx] - [day8.re-frame.tracing :refer-macros [fn-traced]] - [goog.dom :refer [getElement]] - [malli.core :as m] - [malli.error :as me] - [re-frame.core :as rf :refer [reg-event-db reg-event-fx subscribe]])) + [athens.athens-datoms :as athens-datoms] + [athens.common-db :as common-db] + [athens.common-events :as common-events] + [athens.common-events.bfs :as bfs] + [athens.common-events.graph.atomic :as atomic-graph-ops] + [athens.common-events.graph.composite :as composite-ops] + [athens.common-events.graph.ops :as graph-ops] + [athens.common-events.resolver.atomic :as atomic-resolver] + [athens.common-events.resolver.undo :as undo-resolver] + [athens.common-events.schema :as schema] + [athens.common.logging :as log] + [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] + [athens.common.utils :as common.utils] + [athens.dates :as dates] + [athens.db :as db] + [athens.electron.db-picker :as db-picker] + [athens.electron.images :as images] + [athens.electron.monitoring.core] + [athens.electron.utils :as electron.utils] + [athens.events.remote :as events-remote] + [athens.events.sentry] + [athens.interceptors :as interceptors] + [athens.patterns :as patterns] + [athens.undo :as undo] + [athens.util :as util] + [athens.utils.sentry :as sentry] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [clojure.string :as string] + [datascript.core :as d] + [day8.re-frame.async-flow-fx] + [day8.re-frame.tracing :refer-macros [fn-traced]] + [goog.dom :refer [getElement]] + [malli.core :as m] + [malli.error :as me] + [re-frame.core :as rf :refer [reg-event-db reg-event-fx subscribe]])) ;; -- re-frame app-db events --------------------------------------------- (reg-event-fx - :create-in-memory-conn - (fn [_ _] - (let [conn (d/create-conn common-db/schema)] - (doseq [[_id data] athens-datoms/welcome-events] - (atomic-resolver/resolve-transact! conn data)) - {:async-flow {:id :db-in-mem-load - :db-path [:async-flow :db/in-mem-load] - :first-dispatch [:reset-conn @conn] - :rules [{:when :seen? - :events :success-reset-conn - :dispatch [:stage/success-db-load] - :halt? true}]}}))) + :create-in-memory-conn + (fn [_ _] + (let [conn (d/create-conn common-db/schema)] + (doseq [[_id data] athens-datoms/welcome-events] + (atomic-resolver/resolve-transact! conn data)) + {:async-flow {:id :db-in-mem-load + :db-path [:async-flow :db/in-mem-load] + :first-dispatch [:reset-conn @conn] + :rules [{:when :seen? + :events :success-reset-conn + :dispatch [:stage/success-db-load] + :halt? true}]}}))) (rf/reg-event-db - :stage/success-db-load - (fn [db] - (js/console.debug ":stage/success-db-load") - db)) + :stage/success-db-load + (fn [db] + (js/console.debug ":stage/success-db-load") + db)) (rf/reg-event-db - :stage/fail-db-load - (fn [db] - (js/console.debug ":stage/fail-db-load") - db)) + :stage/fail-db-load + (fn [db] + (js/console.debug ":stage/fail-db-load") + db)) (reg-event-db - :init-rfdb - [(interceptors/sentry-span-no-new-tx "init-rfdb")] - (fn [_ _] - db/rfdb)) + :init-rfdb + [(interceptors/sentry-span-no-new-tx "init-rfdb")] + (fn [_ _] + db/rfdb)) (reg-event-db - :db/sync - [(interceptors/sentry-span-no-new-tx "db/sync")] - (fn [db [_]] - (assoc db :db/synced true))) + :db/sync + [(interceptors/sentry-span-no-new-tx "db/sync")] + (fn [db [_]] + (assoc db :db/synced true))) (reg-event-db - :db/not-synced - [(interceptors/sentry-span-no-new-tx "db/not-synced")] - (fn [db [_]] - (assoc db :db/synced false))) + :db/not-synced + [(interceptors/sentry-span-no-new-tx "db/not-synced")] + (fn [db [_]] + (assoc db :db/synced false))) (defn shared-blocks-excl-date-pages @@ -199,217 +199,217 @@ (reg-event-fx - :upload/roam-edn - [(interceptors/sentry-span-no-new-tx "upload/roam-edn")] - (fn [_ [_ transformed-dates-roam-db roam-db-filename]] - (let [shared-pages (get-shared-pages transformed-dates-roam-db) - merge-shared (mapv (fn [x] (merge-shared-page [:node/title x] transformed-dates-roam-db roam-db-filename)) - shared-pages) - merge-unshared (->> (not-shared-pages transformed-dates-roam-db shared-pages) - (map (fn [x] (db/get-roam-node-document [:node/title x] transformed-dates-roam-db)))) - tx-data (concat merge-shared merge-unshared)] + :upload/roam-edn + [(interceptors/sentry-span-no-new-tx "upload/roam-edn")] + (fn [_ [_ transformed-dates-roam-db roam-db-filename]] + (let [shared-pages (get-shared-pages transformed-dates-roam-db) + merge-shared (mapv (fn [x] (merge-shared-page [:node/title x] transformed-dates-roam-db roam-db-filename)) + shared-pages) + merge-unshared (->> (not-shared-pages transformed-dates-roam-db shared-pages) + (map (fn [x] (db/get-roam-node-document [:node/title x] transformed-dates-roam-db)))) + tx-data (concat merge-shared merge-unshared)] ;; TODO: this functionality needs to create a internal representation event instead. ;; That will cause it to work in RTC and remove the need to transact directly to the in-memory db. - {:dispatch [:transact tx-data]}))) + {:dispatch [:transact tx-data]}))) (reg-event-fx - :athena/toggle - [(interceptors/sentry-span-no-new-tx "athena/toggle")] - (fn [{:keys [db]} _] - {:db (update db :athena/open not) - :dispatch [:posthog/report-feature :athena]})) + :athena/toggle + [(interceptors/sentry-span-no-new-tx "athena/toggle")] + (fn [{:keys [db]} _] + {:db (update db :athena/open not) + :dispatch [:posthog/report-feature :athena]})) (reg-event-db - :athena/update-recent-items - [(interceptors/sentry-span-no-new-tx "athena/undate-recent-items")] - (fn-traced [db [_ selected-page]] - (when (nil? ((set (:athena/recent-items db)) selected-page)) - (update db :athena/recent-items conj selected-page)))) + :athena/update-recent-items + [(interceptors/sentry-span-no-new-tx "athena/undate-recent-items")] + (fn-traced [db [_ selected-page]] + (when (nil? ((set (:athena/recent-items db)) selected-page)) + (update db :athena/recent-items conj selected-page)))) (reg-event-db - :devtool/toggle - [(interceptors/sentry-span-no-new-tx "devtool/toggle")] - (fn [db _] - (update db :devtool/open not))) + :devtool/toggle + [(interceptors/sentry-span-no-new-tx "devtool/toggle")] + (fn [db _] + (update db :devtool/open not))) (reg-event-fx - :help/toggle - [(interceptors/sentry-span-no-new-tx "help/toggle")] - (fn [{:keys [db]} _] - {:db (update db :help/open? not) - :dispatch [:posthog/report-feature :help]})) + :help/toggle + [(interceptors/sentry-span-no-new-tx "help/toggle")] + (fn [{:keys [db]} _] + {:db (update db :help/open? not) + :dispatch [:posthog/report-feature :help]})) (reg-event-fx - :left-sidebar/toggle - [(interceptors/sentry-span-no-new-tx "left-sidebar/toggle")] - (fn [{:keys [db]} _] - {:db (update db :left-sidebar/open not) - :dispatch [:posthog/report-feature :left-sidebar]})) + :left-sidebar/toggle + [(interceptors/sentry-span-no-new-tx "left-sidebar/toggle")] + (fn [{:keys [db]} _] + {:db (update db :left-sidebar/open not) + :dispatch [:posthog/report-feature :left-sidebar]})) (reg-event-fx - :right-sidebar/toggle - [(interceptors/sentry-span-no-new-tx "right-sidebar/toggle")] - (fn [{:keys [db]} _] - (let [closing? (:right-sidebar/open db)] - {:db (update db :right-sidebar/open not) - :dispatch [:posthog/report-feature :right-sidebar (not closing?)]}))) + :right-sidebar/toggle + [(interceptors/sentry-span-no-new-tx "right-sidebar/toggle")] + (fn [{:keys [db]} _] + (let [closing? (:right-sidebar/open db)] + {:db (update db :right-sidebar/open not) + :dispatch [:posthog/report-feature :right-sidebar (not closing?)]}))) (reg-event-fx - :right-sidebar/toggle-item - [(interceptors/sentry-span-no-new-tx "right-sidebar/toggle-item")] - (fn [{:keys [db]} [_ item]] - {:db (update-in db [:right-sidebar/items item :open] not) - :dispatch [:posthog/report-feature :right-sidebar true]})) + :right-sidebar/toggle-item + [(interceptors/sentry-span-no-new-tx "right-sidebar/toggle-item")] + (fn [{:keys [db]} [_ item]] + {:db (update-in db [:right-sidebar/items item :open] not) + :dispatch [:posthog/report-feature :right-sidebar true]})) (reg-event-db - :right-sidebar/set-width - [(interceptors/sentry-span-no-new-tx "right-sidebar/set-width")] - (fn [db [_ width]] - (assoc db :right-sidebar/width width))) + :right-sidebar/set-width + [(interceptors/sentry-span-no-new-tx "right-sidebar/set-width")] + (fn [db [_ width]] + (assoc db :right-sidebar/width width))) (reg-event-db - :mouse-down/set - (fn [db _] - (assoc db :mouse-down true))) + :mouse-down/set + (fn [db _] + (assoc db :mouse-down true))) (reg-event-db - :mouse-down/unset - (fn [db _] - (assoc db :mouse-down false))) + :mouse-down/unset + (fn [db _] + (assoc db :mouse-down false))) ;; no ops -- does not do anything ;; useful in situations where there is no dispatch value (reg-event-fx - :no-op - (fn [_ _] - (log/warn "Called :no-op re-frame event, this shouldn't be happening.") - {})) + :no-op + (fn [_ _] + (log/warn "Called :no-op re-frame event, this shouldn't be happening.") + {})) ;; TODO: dec all indices > closed item (reg-event-fx - :right-sidebar/close-item - [(interceptors/sentry-span-no-new-tx "right-sidebar/close-item")] - (fn [{:keys [db]} [_ uid]] - (let [{:right-sidebar/keys - [items]} db - last-item? (= 1 (count items)) - new-db (cond-> (update db :right-sidebar/items dissoc uid) - last-item? (assoc :right-sidebar/open false))] - {:db new-db - :dispatch [:posthog/report-feature :right-sidebar (not last-item?)]}))) + :right-sidebar/close-item + [(interceptors/sentry-span-no-new-tx "right-sidebar/close-item")] + (fn [{:keys [db]} [_ uid]] + (let [{:right-sidebar/keys + [items]} db + last-item? (= 1 (count items)) + new-db (cond-> (update db :right-sidebar/items dissoc uid) + last-item? (assoc :right-sidebar/open false))] + {:db new-db + :dispatch [:posthog/report-feature :right-sidebar (not last-item?)]}))) (reg-event-fx - :right-sidebar/navigate-item - [(interceptors/sentry-span-no-new-tx "right-sidebar/navigate-item")] - (fn [{:keys [db]} [_ uid breadcrumb-uid]] - (let [block (d/pull @db/dsdb '[:node/title :block/string] [:block/uid breadcrumb-uid]) - item-index (get-in db [:right-sidebar/items uid :index]) - new-item (merge block {:open true :index item-index})] - {:db (-> db - (update-in [:right-sidebar/items] dissoc uid) - (update-in [:right-sidebar/items] assoc breadcrumb-uid new-item)) - :dispatch [:posthog/report-feature :right-sidebar true]}))) + :right-sidebar/navigate-item + [(interceptors/sentry-span-no-new-tx "right-sidebar/navigate-item")] + (fn [{:keys [db]} [_ uid breadcrumb-uid]] + (let [block (d/pull @db/dsdb '[:node/title :block/string] [:block/uid breadcrumb-uid]) + item-index (get-in db [:right-sidebar/items uid :index]) + new-item (merge block {:open true :index item-index})] + {:db (-> db + (update-in [:right-sidebar/items] dissoc uid) + (update-in [:right-sidebar/items] assoc breadcrumb-uid new-item)) + :dispatch [:posthog/report-feature :right-sidebar true]}))) ;; TODO: change right sidebar items from map to datascript (reg-event-fx - :right-sidebar/open-item - [(interceptors/sentry-span-no-new-tx "right-sidebar/open-item")] - (fn [{:keys [db]} [_ uid is-graph?]] - (let [block (d/pull @db/dsdb '[:node/title :block/string] [:block/uid uid]) - new-item (merge block {:open true :index -1 :is-graph? is-graph?}) + :right-sidebar/open-item + [(interceptors/sentry-span-no-new-tx "right-sidebar/open-item")] + (fn [{:keys [db]} [_ uid is-graph?]] + (let [block (d/pull @db/dsdb '[:node/title :block/string] [:block/uid uid]) + new-item (merge block {:open true :index -1 :is-graph? is-graph?}) ;; Avoid a memory leak by forgetting the comparison function ;; that is stored in the sorted map ;; `(assoc (:right-sidebar/items db) uid new-item)` - new-items (into {} - (assoc (:right-sidebar/items db) uid new-item)) - inc-items (reduce-kv (fn [m k v] (assoc m k (update v :index inc))) - {} - new-items) - sorted-items (into (sorted-map-by (fn [k1 k2] - (compare - [(get-in inc-items [k1 :index]) k2] - [(get-in inc-items [k2 :index]) k1]))) inc-items)] - {:db (assoc db :right-sidebar/items sorted-items) - :dispatch-n [(when (not (:right-sidebar/open db)) - [:right-sidebar/toggle]) - [:right-sidebar/scroll-top] - [:posthog/report-feature :right-sidebar true]]}))) - - -(reg-event-fx - :right-sidebar/open-page - [(interceptors/sentry-span-no-new-tx "right-sidebar/open-page")] - (fn [{:keys [db]} [_ page-title is-graph?]] - (let [{:keys [:block/uid] - :as block} (d/pull @db/dsdb '[:block/uid :node/title :block/string] [:node/title page-title]) - new-item (merge block {:open true :index -1 :is-graph? is-graph?}) + new-items (into {} + (assoc (:right-sidebar/items db) uid new-item)) + inc-items (reduce-kv (fn [m k v] (assoc m k (update v :index inc))) + {} + new-items) + sorted-items (into (sorted-map-by (fn [k1 k2] + (compare + [(get-in inc-items [k1 :index]) k2] + [(get-in inc-items [k2 :index]) k1]))) inc-items)] + {:db (assoc db :right-sidebar/items sorted-items) + :dispatch-n [(when (not (:right-sidebar/open db)) + [:right-sidebar/toggle]) + [:right-sidebar/scroll-top] + [:posthog/report-feature :right-sidebar true]]}))) + + +(reg-event-fx + :right-sidebar/open-page + [(interceptors/sentry-span-no-new-tx "right-sidebar/open-page")] + (fn [{:keys [db]} [_ page-title is-graph?]] + (let [{:keys [:block/uid] + :as block} (d/pull @db/dsdb '[:block/uid :node/title :block/string] [:node/title page-title]) + new-item (merge block {:open true :index -1 :is-graph? is-graph?}) ;; Avoid a memory leak by forgetting the comparison function ;; that is stored in the sorted map ;; `(assoc (:right-sidebar/items db) uid new-item)` - new-items (into {} - (assoc (:right-sidebar/items db) uid new-item)) - inc-items (reduce-kv (fn [m k v] (assoc m k (update v :index inc))) - {} - new-items) - sorted-items (into (sorted-map-by (fn [k1 k2] - (compare - [(get-in inc-items [k1 :index]) k2] - [(get-in inc-items [k2 :index]) k1]))) inc-items)] - {:db (assoc db :right-sidebar/items sorted-items) - :dispatch-n [(when (not (:right-sidebar/open db)) - [:right-sidebar/toggle]) - [:right-sidebar/scroll-top] - [:posthog/report-feature :right-sidebar true]]}))) + new-items (into {} + (assoc (:right-sidebar/items db) uid new-item)) + inc-items (reduce-kv (fn [m k v] (assoc m k (update v :index inc))) + {} + new-items) + sorted-items (into (sorted-map-by (fn [k1 k2] + (compare + [(get-in inc-items [k1 :index]) k2] + [(get-in inc-items [k2 :index]) k1]))) inc-items)] + {:db (assoc db :right-sidebar/items sorted-items) + :dispatch-n [(when (not (:right-sidebar/open db)) + [:right-sidebar/toggle]) + [:right-sidebar/scroll-top] + [:posthog/report-feature :right-sidebar true]]}))) (reg-event-fx - :right-sidebar/scroll-top - [(interceptors/sentry-span-no-new-tx "right-sidebar/scroll-top")] - (fn [] - {:right-sidebar/scroll-top nil})) + :right-sidebar/scroll-top + [(interceptors/sentry-span-no-new-tx "right-sidebar/scroll-top")] + (fn [] + {:right-sidebar/scroll-top nil})) (reg-event-fx - :editing/uid - [(interceptors/sentry-span-no-new-tx "editing/uid")] - (fn [{:keys [db]} [_ uid index]] - (let [remote? (db-picker/remote-db? db)] - {:db (assoc db :editing/uid uid) - :editing/focus [uid index] - :dispatch-n [(when (and uid remote?) - [:presence/send-update {:block-uid (util/embed-uid->original-uid uid)}])]}))) + :editing/uid + [(interceptors/sentry-span-no-new-tx "editing/uid")] + (fn [{:keys [db]} [_ uid index]] + (let [remote? (db-picker/remote-db? db)] + {:db (assoc db :editing/uid uid) + :editing/focus [uid index] + :dispatch-n [(when (and uid remote?) + [:presence/send-update {:block-uid (util/embed-uid->original-uid uid)}])]}))) (reg-event-fx - :editing/target - [(interceptors/sentry-span-no-new-tx "editing/target")] - (fn [_ [_ target]] - (let [uid (-> (.. target -id) - (string/split "editable-uid-") - second)] - {:dispatch [:editing/uid uid]}))) + :editing/target + [(interceptors/sentry-span-no-new-tx "editing/target")] + (fn [_ [_ target]] + (let [uid (-> (.. target -id) + (string/split "editable-uid-") + second)] + {:dispatch [:editing/uid uid]}))) (reg-event-fx - :editing/first-child - [(interceptors/sentry-span-no-new-tx "editing/first-child")] - (fn [_ [_ uid]] - (when-let [first-block-uid (db/get-first-child-uid uid @db/dsdb)] - {:dispatch [:editing/uid first-block-uid]}))) + :editing/first-child + [(interceptors/sentry-span-no-new-tx "editing/first-child")] + (fn [_ [_ uid]] + (when-let [first-block-uid (db/get-first-child-uid uid @db/dsdb)] + {:dispatch [:editing/uid first-block-uid]}))) (defn select-up @@ -451,153 +451,153 @@ (reg-event-db - :selected/up - [(interceptors/sentry-span-no-new-tx "selected/up")] - (fn [db [_ selected-items]] - (assoc-in db [:selection :items] (select-up selected-items)))) + :selected/up + [(interceptors/sentry-span-no-new-tx "selected/up")] + (fn [db [_ selected-items]] + (assoc-in db [:selection :items] (select-up selected-items)))) ;; using a set or a hash map, we would need a secondary editing/uid to maintain the head/tail position ;; this would let us know if the operation is additive or subtractive (reg-event-db - :selected/down - [(interceptors/sentry-span-no-new-tx "selected/down")] - (fn [db [_ selected-items]] - (let [last-item (last selected-items) - next-block-uid (db/next-block-uid last-item true) - ordered-selection (cond-> (into [] selected-items) - next-block-uid (into [next-block-uid]))] - (log/debug ":selected/down, new-selection:" (pr-str ordered-selection)) - (assoc-in db [:selection :items] ordered-selection)))) + :selected/down + [(interceptors/sentry-span-no-new-tx "selected/down")] + (fn [db [_ selected-items]] + (let [last-item (last selected-items) + next-block-uid (db/next-block-uid last-item true) + ordered-selection (cond-> (into [] selected-items) + next-block-uid (into [next-block-uid]))] + (log/debug ":selected/down, new-selection:" (pr-str ordered-selection)) + (assoc-in db [:selection :items] ordered-selection)))) ;; Alerts (reg-event-db - :alert/unset - (fn-traced [db] - (assoc db :alert nil))) + :alert/unset + (fn-traced [db] + (assoc db :alert nil))) ;; Use native js/alert rather than custom UI alert (reg-event-fx - :alert/js - (fn [_ [_ message]] - {:alert/js! message})) + :alert/js + (fn [_ [_ message]] + {:alert/js! message})) (reg-event-fx - :confirm/js - (fn [_ [_ message true-cb false-cb]] - {:confirm/js! [message true-cb false-cb]})) + :confirm/js + (fn [_ [_ message true-cb false-cb]] + {:confirm/js! [message true-cb false-cb]})) ;; Modal (reg-event-db - :modal/toggle - (fn [db _] - (update db :modal not))) + :modal/toggle + (fn [db _] + (update db :modal not))) ;; Loading (reg-event-db - :loading/set - (fn-traced [db] - (assoc-in db [:loading?] true))) + :loading/set + (fn-traced [db] + (assoc-in db [:loading?] true))) (reg-event-db - :loading/unset - (fn-traced [db] - (assoc-in db [:loading?] false))) + :loading/unset + (fn-traced [db] + (assoc-in db [:loading?] false))) (reg-event-db - :tooltip/uid - (fn [db [_ uid]] - (assoc db :tooltip/uid uid))) + :tooltip/uid + (fn [db [_ uid]] + (assoc db :tooltip/uid uid))) ;; Connection status (reg-event-fx - :conn-status - (fn [{:keys [db]} [_ to-status]] - (let [from-status (:connection-status db)] - {:db (assoc db :connection-status to-status) - :dispatch-n [(condp = [from-status to-status] - [:reconnecting :connected] [:loading/unset] - [:connected :reconnecting] [:loading/set] - nil)]}))) + :conn-status + (fn [{:keys [db]} [_ to-status]] + (let [from-status (:connection-status db)] + {:db (assoc db :connection-status to-status) + :dispatch-n [(condp = [from-status to-status] + [:reconnecting :connected] [:loading/unset] + [:connected :reconnecting] [:loading/set] + nil)]}))) ;; Daily Notes (reg-event-db - :daily-note/reset - (fn [db [_ uid]] - (assoc db :daily-notes/items uid))) + :daily-note/reset + (fn [db [_ uid]] + (assoc db :daily-notes/items uid))) (reg-event-db - :daily-note/add - (fn [db [_ uid]] - (update db :daily-notes/items (comp rseq sort distinct conj) uid))) + :daily-note/add + (fn [db [_ uid]] + (update db :daily-notes/items (comp rseq sort distinct conj) uid))) (reg-event-fx - :daily-note/ensure-day - (fn [_ [_ {:keys [uid title]}]] - (when-not (db/e-by-av :block/uid uid) - {:dispatch [:page/new {:title title - :block-uid (common.utils/gen-block-uid)}]}))) + :daily-note/ensure-day + (fn [_ [_ {:keys [uid title]}]] + (when-not (db/e-by-av :block/uid uid) + {:dispatch [:page/new {:title title + :block-uid (common.utils/gen-block-uid)}]}))) (reg-event-fx - :daily-note/prev - (fn [{:keys [db]} [_ {:keys [uid] :as day}]] - (let [new-db (update db :daily-notes/items (fn [items] - (into [uid] items)))] - {:db new-db - :dispatch [:daily-note/ensure-day day]}))) + :daily-note/prev + (fn [{:keys [db]} [_ {:keys [uid] :as day}]] + (let [new-db (update db :daily-notes/items (fn [items] + (into [uid] items)))] + {:db new-db + :dispatch [:daily-note/ensure-day day]}))) (reg-event-fx - :daily-note/next - (fn [_ [_ {:keys [uid] :as day}]] - {:dispatch-n [[:daily-note/ensure-day day] - [:daily-note/add uid]]})) + :daily-note/next + (fn [_ [_ {:keys [uid] :as day}]] + {:dispatch-n [[:daily-note/ensure-day day] + [:daily-note/add uid]]})) (reg-event-fx - :daily-note/delete - (fn [{:keys [db]} [_ uid title]] - (let [filtered-dn (filterv #(not= % uid) (:daily-notes/items db)) ; Filter current date from daily note vec - new-db (assoc db :daily-notes/items filtered-dn)] - {:fx [[:dispatch [:page/delete title]]] - :db new-db}))) + :daily-note/delete + (fn [{:keys [db]} [_ uid title]] + (let [filtered-dn (filterv #(not= % uid) (:daily-notes/items db)) ; Filter current date from daily note vec + new-db (assoc db :daily-notes/items filtered-dn)] + {:fx [[:dispatch [:page/delete title]]] + :db new-db}))) (reg-event-fx - :daily-note/scroll - (fn [_ [_]] - (let [daily-notes @(subscribe [:daily-notes/items]) - el (getElement "daily-notes")] - (when el - (let [offset-top (.. el -offsetTop) - rect (.. el getBoundingClientRect) - from-bottom (.. rect -bottom) - from-top (.. rect -top) - doc-height (.. js/document -documentElement -scrollHeight) - top-delta (- offset-top from-top) - bottom-delta (- from-bottom doc-height)] + :daily-note/scroll + (fn [_ [_]] + (let [daily-notes @(subscribe [:daily-notes/items]) + el (getElement "daily-notes")] + (when el + (let [offset-top (.. el -offsetTop) + rect (.. el getBoundingClientRect) + from-bottom (.. rect -bottom) + from-top (.. rect -top) + doc-height (.. js/document -documentElement -scrollHeight) + top-delta (- offset-top from-top) + bottom-delta (- from-bottom doc-height)] ;; Don't allow user to scroll up for now. - (cond - (< top-delta 1) nil #_(dispatch [:daily-note/prev (get-day (uid-to-date (first daily-notes)) -1)]) - (< bottom-delta 1) {:fx [[:dispatch [:daily-note/next (dates/get-day (dates/uid-to-date (last daily-notes)) 1)]]]})))))) + (cond + (< top-delta 1) nil #_(dispatch [:daily-note/prev (get-day (uid-to-date (first daily-notes)) -1)]) + (< bottom-delta 1) {:fx [[:dispatch [:daily-note/next (dates/get-day (dates/uid-to-date (last daily-notes)) 1)]]]})))))) ;; -- event-fx and Datascript Transactions ------------------------------- @@ -606,31 +606,31 @@ (reg-event-fx - :http-success/get-db - [(interceptors/sentry-span-no-new-tx "http-success/get-db")] - (fn [_ [_ json-str]] - (let [datoms (db/str-to-db-tx json-str) - new-db (d/db-with common-db/empty-db datoms)] - {:dispatch [:reset-conn new-db]}))) + :http-success/get-db + [(interceptors/sentry-span-no-new-tx "http-success/get-db")] + (fn [_ [_ json-str]] + (let [datoms (db/str-to-db-tx json-str) + new-db (d/db-with common-db/empty-db datoms)] + {:dispatch [:reset-conn new-db]}))) (reg-event-fx - :theme/set - [(interceptors/sentry-span-no-new-tx "theme/set")] - (fn [{:keys [db]} _] - (util/switch-body-classes (if (-> db :athens/persist :theme/dark) - ["is-theme-light" "is-theme-dark"] - ["is-theme-dark" "is-theme-light"])) - {})) + :theme/set + [(interceptors/sentry-span-no-new-tx "theme/set")] + (fn [{:keys [db]} _] + (util/switch-body-classes (if (-> db :athens/persist :theme/dark) + ["is-theme-light" "is-theme-dark"] + ["is-theme-dark" "is-theme-light"])) + {})) (reg-event-fx - :theme/toggle - [(interceptors/sentry-span-no-new-tx "theme/toggle")] - (fn [{:keys [db]} _] - {:db (update-in db [:athens/persist :theme/dark] not) - :dispatch-n [[:theme/set] - [:posthog/report-feature :theme]]})) + :theme/toggle + [(interceptors/sentry-span-no-new-tx "theme/toggle")] + (fn [{:keys [db]} _] + {:db (update-in db [:athens/persist :theme/dark] not) + :dispatch-n [[:theme/set] + [:posthog/report-feature :theme]]})) ;; Datascript @@ -642,22 +642,22 @@ ;; - :upload/roam-edn (needs internal representation) ;; No other reframe events should be calling this event. (reg-event-fx - :transact - [(interceptors/sentry-span "transact")] - (fn-traced [_ [_ tx-data]] - (let [synced? @(subscribe [:db/synced]) - electron? electron.utils/electron?] - (if (and synced? electron?) - {:fx [[:transact! tx-data] - [:dispatch [:db/not-synced]] - [:dispatch [:save]]]} - {:fx [[:transact! tx-data]]})))) + :transact + [(interceptors/sentry-span "transact")] + (fn-traced [_ [_ tx-data]] + (let [synced? @(subscribe [:db/synced]) + electron? electron.utils/electron?] + (if (and synced? electron?) + {:fx [[:transact! tx-data] + [:dispatch [:db/not-synced]] + [:dispatch [:save]]]} + {:fx [[:transact! tx-data]]})))) (rf/reg-event-fx - :success-transact - (fn [_ _] - {})) + :success-transact + (fn [_ _] + {})) ;; These events are used for async flows, so we know when changes are in the @@ -665,29 +665,29 @@ ;; If you need to know which event was resolved, check the arg as ;; shown in https://github.com/day8/re-frame-async-flow-fx#advanced-use. (rf/reg-event-fx - :success-resolve-forward-transact - (fn [_ [_ _event]] - {})) + :success-resolve-forward-transact + (fn [_ [_ _event]] + {})) (rf/reg-event-fx - :fail-resolve-transact-forward - (fn [_ [_ _event]] - {})) + :fail-resolve-transact-forward + (fn [_ [_ _event]] + {})) (reg-event-fx - :reset-conn - [(interceptors/sentry-span-no-new-tx "reset-conn")] - (fn-traced [_ [_ db skip-health-check?]] - {:reset-conn! [db skip-health-check?]})) + :reset-conn + [(interceptors/sentry-span-no-new-tx "reset-conn")] + (fn-traced [_ [_ db skip-health-check?]] + {:reset-conn! [db skip-health-check?]})) (rf/reg-event-fx - :success-reset-conn - (fn [_ _] - (js/console.debug ":success-reset-conn") - {})) + :success-reset-conn + (fn [_ _] + (js/console.debug ":success-reset-conn") + {})) (defn datom->tx-entry @@ -696,226 +696,226 @@ (rf/reg-event-fx - :db-dump-handler - (fn-traced [{:keys [db]} [_ datoms]] - (let [existing-tx (sentry/transaction-get-current) - sentry-tx (if existing-tx - existing-tx - (sentry/transaction-start "db-dump-handler")) - conversion-span (sentry/span-start sentry-tx "convert-datoms") + :db-dump-handler + (fn-traced [{:keys [db]} [_ datoms]] + (let [existing-tx (sentry/transaction-get-current) + sentry-tx (if existing-tx + existing-tx + (sentry/transaction-start "db-dump-handler")) + conversion-span (sentry/span-start sentry-tx "convert-datoms") ;; TODO: this new-db should be derived from an internal representation transact event instead. - new-db (d/db-with common-db/empty-db - (into [] (map datom->tx-entry) datoms))] - (sentry/span-finish conversion-span) - {:db db - :async-flow {:id :db-dump-handler-async-flow ; NOTE do not ever use id that is defined event - :db-path [:async-flow :db-dump-handler] - :first-dispatch [:reset-conn new-db true] - :rules [{:when :seen? - :events :success-reset-conn - :dispatch-n [[:remote/start-event-sync] - [:db/sync] - [:remote/connected]]} - {:when :seen-all-of? - :events [:success-reset-conn - :remote/start-event-sync - :db/sync - :remote/connected] - :dispatch-n (cond-> [[:stage/success-db-load]] - (not existing-tx) (conj [:sentry/end-tx sentry-tx])) - :halt? true}]}}))) - - -(reg-event-fx - :electron-sync - [(interceptors/sentry-span-no-new-tx "electron-sync")] - (fn [_ _] - (let [synced? @(subscribe [:db/synced]) - electron? electron.utils/electron?] - (merge {} - (when (and synced? electron?) - {:fx [[:dispatch [:db/not-synced]] - [:dispatch [:save]]]}))))) - - -(reg-event-fx - :resolve-transact-forward - [(interceptors/sentry-span "resolve-transact-forward")] - (fn [{:keys [db]} [_ event]] - (let [remote? (db-picker/remote-db? db) - valid? (schema/valid-event? event) - dsdb @db/dsdb - undo? (undo-resolver/undo? event)] - (log/debug ":resolve-transact-forward event:" (pr-str event) - "remote?" (pr-str remote?) - "valid?" (pr-str valid?) - "undo?" (pr-str undo?)) - (if-not valid? + new-db (d/db-with common-db/empty-db + (into [] (map datom->tx-entry) datoms))] + (sentry/span-finish conversion-span) + {:db db + :async-flow {:id :db-dump-handler-async-flow ; NOTE do not ever use id that is defined event + :db-path [:async-flow :db-dump-handler] + :first-dispatch [:reset-conn new-db true] + :rules [{:when :seen? + :events :success-reset-conn + :dispatch-n [[:remote/start-event-sync] + [:db/sync] + [:remote/connected]]} + {:when :seen-all-of? + :events [:success-reset-conn + :remote/start-event-sync + :db/sync + :remote/connected] + :dispatch-n (cond-> [[:stage/success-db-load]] + (not existing-tx) (conj [:sentry/end-tx sentry-tx])) + :halt? true}]}}))) + + +(reg-event-fx + :electron-sync + [(interceptors/sentry-span-no-new-tx "electron-sync")] + (fn [_ _] + (let [synced? @(subscribe [:db/synced]) + electron? electron.utils/electron?] + (merge {} + (when (and synced? electron?) + {:fx [[:dispatch [:db/not-synced]] + [:dispatch [:save]]]}))))) + + +(reg-event-fx + :resolve-transact-forward + [(interceptors/sentry-span "resolve-transact-forward")] + (fn [{:keys [db]} [_ event]] + (let [remote? (db-picker/remote-db? db) + valid? (schema/valid-event? event) + dsdb @db/dsdb + undo? (undo-resolver/undo? event)] + (log/debug ":resolve-transact-forward event:" (pr-str event) + "remote?" (pr-str remote?) + "valid?" (pr-str valid?) + "undo?" (pr-str undo?)) + (if-not valid? ;; Don't try to process invalid events, just log them. - (let [explanation (-> schema/event - (m/explain event) - (me/humanize))] - (log/warn "Not sending invalid event. Error:" (pr-str explanation) - "\nInvalid event was:" (pr-str event)) - {:fx [[:dispatch [:fail-resolve-forward-transact event]]]}) + (let [explanation (-> schema/event + (m/explain event) + (me/humanize))] + (log/warn "Not sending invalid event. Error:" (pr-str explanation) + "\nInvalid event was:" (pr-str event)) + {:fx [[:dispatch [:fail-resolve-forward-transact event]]]}) - (try + (try ;; Seems valid, lets process it. - (let [;; First, resolve it into dsdb. - db' (if remote? + (let [;; First, resolve it into dsdb. + db' (if remote? ;; Remote db events have to be managed via the synchronizer in events.remote. - (first (events-remote/add-memory-event! [db db/dsdb] event)) - (do + (first (events-remote/add-memory-event! [db db/dsdb] event)) + (do ;; For local dbs, just transact it directly into dsdb. - (atomic-resolver/resolve-transact! db/dsdb event) - db)) + (atomic-resolver/resolve-transact! db/dsdb event) + db)) ;; Then figure out the undo situation. - db'' (if undo? + db'' (if undo? ;; For undos, let the undo/redo handlers manage db state. - db' + db' ;; Otherwise wipe the redo stack and add the new event. - (-> db' - undo/reset-redo - (undo/push-undo (:event/id event) [dsdb event])))] + (-> db' + undo/reset-redo + (undo/push-undo (:event/id event) [dsdb event])))] ;; Wrap it up. - (merge - {:db db'' - :fx [;; Local dbs will need to be synced via electron. - (when-not remote? [:dispatch [:electron-sync]]) + (merge + {:db db'' + :fx [;; Local dbs will need to be synced via electron. + (when-not remote? [:dispatch [:electron-sync]]) ;; Remote dbs just wait for the event to be confirmed by the server. - (when remote? [:dispatch [:db/not-synced]]) + (when remote? [:dispatch [:db/not-synced]]) ;; Processing has finished successfully at this point, signal the async flows. - [:dispatch [:success-resolve-forward-transact event]]]} + [:dispatch [:success-resolve-forward-transact event]]]} ;; Remote dbs need to actually send the event via the network. - (when remote? {:remote/send-event-fx! event}))) + (when remote? {:remote/send-event-fx! event}))) ;; Bork bork, still need to clean up. - (catch :default e - (log/error ":resolve-transact-forward failed with event " event " with error " e) - {:fx [[:dispatch [:fail-resolve-forward-transact event]]]})))))) - - -(reg-event-fx - :page/delete - [(interceptors/sentry-span "page/delete")] - (fn [_ [_ title]] - (log/debug ":page/delete:" title) - (let [event (common-events/build-atomic-event (atomic-graph-ops/make-page-remove-op title))] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) - - -(reg-event-fx - :left-sidebar/add-shortcut - [(interceptors/sentry-span-no-new-tx "left-sidebar/add-shortcut")] - (fn [_ [_ name]] - (log/debug ":page/add-shortcut:" name) - (let [add-shortcut-op (atomic-graph-ops/make-shortcut-new-op name) - event (common-events/build-atomic-event add-shortcut-op)] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + (catch :default e + (log/error ":resolve-transact-forward failed with event " event " with error " e) + {:fx [[:dispatch [:fail-resolve-forward-transact event]]]})))))) + + +(reg-event-fx + :page/delete + [(interceptors/sentry-span "page/delete")] + (fn [_ [_ title]] + (log/debug ":page/delete:" title) + (let [event (common-events/build-atomic-event (atomic-graph-ops/make-page-remove-op title))] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + + +(reg-event-fx + :left-sidebar/add-shortcut + [(interceptors/sentry-span-no-new-tx "left-sidebar/add-shortcut")] + (fn [_ [_ name]] + (log/debug ":page/add-shortcut:" name) + (let [add-shortcut-op (atomic-graph-ops/make-shortcut-new-op name) + event (common-events/build-atomic-event add-shortcut-op)] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) (reg-event-fx - :left-sidebar/remove-shortcut - [(interceptors/sentry-span-no-new-tx "left-sidebar/remove-shortcut")] - (fn [_ [_ name]] - (log/debug ":page/remove-shortcut:" name) - (let [remove-shortcut-op (atomic-graph-ops/make-shortcut-remove-op name) - event (common-events/build-atomic-event remove-shortcut-op)] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + :left-sidebar/remove-shortcut + [(interceptors/sentry-span-no-new-tx "left-sidebar/remove-shortcut")] + (fn [_ [_ name]] + (log/debug ":page/remove-shortcut:" name) + (let [remove-shortcut-op (atomic-graph-ops/make-shortcut-remove-op name) + event (common-events/build-atomic-event remove-shortcut-op)] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) (reg-event-fx - :left-sidebar/drop - [(interceptors/sentry-span-no-new-tx "left-sidebar/drop")] - (fn [_ [_ source-order target-order relation]] - (let [[source-name target-name] (common-db/find-source-target-title @db/dsdb source-order target-order) - drop-op (atomic-graph-ops/make-shortcut-move-op source-name - {:page/title target-name - :relation relation}) - event (common-events/build-atomic-event drop-op)] - {:fx [[:dispatch [:resolve-transact-forward event]] - [:dispatch [:posthog/report-feature :left-sidebar]]]}))) + :left-sidebar/drop + [(interceptors/sentry-span-no-new-tx "left-sidebar/drop")] + (fn [_ [_ source-order target-order relation]] + (let [[source-name target-name] (common-db/find-source-target-title @db/dsdb source-order target-order) + drop-op (atomic-graph-ops/make-shortcut-move-op source-name + {:page/title target-name + :relation relation}) + event (common-events/build-atomic-event drop-op)] + {:fx [[:dispatch [:resolve-transact-forward event]] + [:dispatch [:posthog/report-feature :left-sidebar]]]}))) (reg-event-fx - :save - [(interceptors/sentry-span-no-new-tx "save")] - (fn [_ _] - {:fs/write! nil})) + :save + [(interceptors/sentry-span-no-new-tx "save")] + (fn [_ _] + {:fs/write! nil})) (reg-event-fx - :undo - [(interceptors/sentry-span-no-new-tx "undo")] - (fn [{:keys [db]} _] - (log/debug ":undo") - (try - (log/debug ":undo count" (undo/count-undo db)) - (if-some [[undo db'] (undo/pop-undo db)] - (let [[evt-dsdb evt] undo - evt-id (:event/id evt) - dsdb @db/dsdb - undo-evt (undo-resolver/build-undo-event dsdb evt-dsdb evt) - undo-evt-id (:event/id undo-evt) - db'' (undo/push-redo db' undo-evt-id [dsdb undo-evt])] - (log/debug ":undo evt" (pr-str evt-id) "as" (pr-str undo-evt-id)) - {:db db'' - :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) - {}) - (catch :default _ - {:fx (util/toast (clj->js {:status "error" - :title "Couldn't undo" - :description "Undo for this operation not supported in Lan-Party, yet."}))})))) + :undo + [(interceptors/sentry-span-no-new-tx "undo")] + (fn [{:keys [db]} _] + (log/debug ":undo") + (try + (log/debug ":undo count" (undo/count-undo db)) + (if-some [[undo db'] (undo/pop-undo db)] + (let [[evt-dsdb evt] undo + evt-id (:event/id evt) + dsdb @db/dsdb + undo-evt (undo-resolver/build-undo-event dsdb evt-dsdb evt) + undo-evt-id (:event/id undo-evt) + db'' (undo/push-redo db' undo-evt-id [dsdb undo-evt])] + (log/debug ":undo evt" (pr-str evt-id) "as" (pr-str undo-evt-id)) + {:db db'' + :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) + {}) + (catch :default _ + {:fx (util/toast (clj->js {:status "error" + :title "Couldn't undo" + :description "Undo for this operation not supported in Lan-Party, yet."}))})))) (reg-event-fx - :redo - [(interceptors/sentry-span-no-new-tx "redo")] - (fn [{:keys [db]} _] - (log/debug ":redo") - (try - (log/debug ":redo count" (undo/count-redo db)) - (if-some [[redo db'] (undo/pop-redo db)] - (let [[evt-dsdb evt] redo - evt-id (:event/id evt) - dsdb @db/dsdb - undo-evt (undo-resolver/build-undo-event dsdb evt-dsdb evt) - undo-evt-id (:event/id undo-evt) - db'' (undo/push-undo db' undo-evt-id [dsdb undo-evt])] - (log/debug ":redo evt" (pr-str evt-id) "as" (pr-str undo-evt-id)) - {:db db'' - :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) - {}) - (catch :default _ - {:fx (util/toast (clj->js {:status "error" - :title "Couldn't redo" - :description "Redo for this operation not supported in Lan-Party, yet."}))})))) + :redo + [(interceptors/sentry-span-no-new-tx "redo")] + (fn [{:keys [db]} _] + (log/debug ":redo") + (try + (log/debug ":redo count" (undo/count-redo db)) + (if-some [[redo db'] (undo/pop-redo db)] + (let [[evt-dsdb evt] redo + evt-id (:event/id evt) + dsdb @db/dsdb + undo-evt (undo-resolver/build-undo-event dsdb evt-dsdb evt) + undo-evt-id (:event/id undo-evt) + db'' (undo/push-undo db' undo-evt-id [dsdb undo-evt])] + (log/debug ":redo evt" (pr-str evt-id) "as" (pr-str undo-evt-id)) + {:db db'' + :fx [[:dispatch [:resolve-transact-forward undo-evt]]]}) + {}) + (catch :default _ + {:fx (util/toast (clj->js {:status "error" + :title "Couldn't redo" + :description "Redo for this operation not supported in Lan-Party, yet."}))})))) (reg-event-fx - :reset-undo-redo - [(interceptors/sentry-span-no-new-tx "reset-undo-redo")] - (fn [{:keys [db]} _] - {:db (undo/reset db)})) + :reset-undo-redo + [(interceptors/sentry-span-no-new-tx "reset-undo-redo")] + (fn [{:keys [db]} _] + {:db (undo/reset db)})) (reg-event-fx - :up - [(interceptors/sentry-span-no-new-tx "up")] - (fn [_ [_ uid target-pos]] - (let [prev-block-uid (db/prev-block-uid uid)] - {:dispatch [:editing/uid (or prev-block-uid uid) target-pos]}))) - - -(reg-event-fx - :down - [(interceptors/sentry-span-no-new-tx "down")] - (fn [_ [_ uid target-pos]] - (let [next-block-uid (db/next-block-uid uid)] - {:dispatch [:editing/uid (or next-block-uid uid) target-pos]}))) + :up + [(interceptors/sentry-span-no-new-tx "up")] + (fn [_ [_ uid target-pos]] + (let [prev-block-uid (db/prev-block-uid uid)] + {:dispatch [:editing/uid (or prev-block-uid uid) target-pos]}))) + + +(reg-event-fx + :down + [(interceptors/sentry-span-no-new-tx "down")] + (fn [_ [_ uid target-pos]] + (let [next-block-uid (db/next-block-uid uid)] + {:dispatch [:editing/uid (or next-block-uid uid) target-pos]}))) (defn backspace @@ -978,10 +978,10 @@ ;; will pick db value of backspace/delete instead of current state ;; which might not be same as blur is not yet called (reg-event-fx - :backspace - [(interceptors/sentry-span-no-new-tx "backspace")] - (fn [_ [_ uid value maybe-local-updates]] - (backspace uid value maybe-local-updates))) + :backspace + [(interceptors/sentry-span-no-new-tx "backspace")] + (fn [_ [_ uid value maybe-local-updates]] + (backspace uid value maybe-local-updates))) ;; Atomic events start ========== @@ -1028,183 +1028,183 @@ (reg-event-fx - :backspace/delete-only-child - (fn [_ [_ uid]] - (log/debug ":backspace/delete-only-child:" (pr-str uid)) - (let [sentry-tx (close-and-get-sentry-tx "backspace/delete-only-child") - op (wrap-span-no-new-tx "build-block-remove-op" - (graph-ops/build-block-remove-op @db/dsdb uid)) - event (common-events/build-atomic-event op)] - {:fx [(transact-async-flow :backspace-delete-only-child event sentry-tx [[:editing/uid nil]])]}))) + :backspace/delete-only-child + (fn [_ [_ uid]] + (log/debug ":backspace/delete-only-child:" (pr-str uid)) + (let [sentry-tx (close-and-get-sentry-tx "backspace/delete-only-child") + op (wrap-span-no-new-tx "build-block-remove-op" + (graph-ops/build-block-remove-op @db/dsdb uid)) + event (common-events/build-atomic-event op)] + {:fx [(transact-async-flow :backspace-delete-only-child event sentry-tx [[:editing/uid nil]])]}))) (reg-event-fx - :enter/new-block - (fn [_ [_ {:keys [block parent new-uid embed-id]}]] - (log/debug ":enter/new-block" (pr-str block) (pr-str parent) (pr-str new-uid)) - (let [sentry-tx (close-and-get-sentry-tx "enter/new-block") - op (atomic-graph-ops/make-block-new-op new-uid {:block/uid (:block/uid block) - :relation :after}) - event (common-events/build-atomic-event op)] - {:fx [(transact-async-flow :enter-new-block event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) + :enter/new-block + (fn [_ [_ {:keys [block parent new-uid embed-id]}]] + (log/debug ":enter/new-block" (pr-str block) (pr-str parent) (pr-str new-uid)) + (let [sentry-tx (close-and-get-sentry-tx "enter/new-block") + op (atomic-graph-ops/make-block-new-op new-uid {:block/uid (:block/uid block) + :relation :after}) + event (common-events/build-atomic-event op)] + {:fx [(transact-async-flow :enter-new-block event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) (reg-event-fx - :block/save - (fn [{:keys [db]} [_ {:keys [uid string] :as args}]] - (log/debug ":block/save args" (pr-str args)) - (let [local? (not (db-picker/remote-db? db)) - block-eid (common-db/e-by-av @db/dsdb :block/uid uid) - do-nothing? (or (not block-eid) - (= string (->> block-eid (d/entity @db/dsdb) :block/string))) - op (graph-ops/build-block-save-op @db/dsdb uid string) - event (common-events/build-atomic-event op)] - (log/debug ":block/save local?" local? - ", do-nothing?" do-nothing?) - (when-not do-nothing? - {:fx [[:dispatch [:resolve-transact-forward event]]]})))) + :block/save + (fn [{:keys [db]} [_ {:keys [uid string] :as args}]] + (log/debug ":block/save args" (pr-str args)) + (let [local? (not (db-picker/remote-db? db)) + block-eid (common-db/e-by-av @db/dsdb :block/uid uid) + do-nothing? (or (not block-eid) + (= string (->> block-eid (d/entity @db/dsdb) :block/string))) + op (graph-ops/build-block-save-op @db/dsdb uid string) + event (common-events/build-atomic-event op)] + (log/debug ":block/save local?" local? + ", do-nothing?" do-nothing?) + (when-not do-nothing? + {:fx [[:dispatch [:resolve-transact-forward event]]]})))) (reg-event-fx - :page/new - (fn [_ [_ {:keys [title block-uid shift?] :or {shift? false} :as args}]] - (log/debug ":page/new args" (pr-str args)) - (let [event (common-events/build-atomic-event (graph-ops/build-page-new-op @db/dsdb - title - block-uid))] - {:fx [[:dispatch-n [[:resolve-transact-forward event] - [:page/new-followup title shift?] - [:editing/uid block-uid]]]]}))) + :page/new + (fn [_ [_ {:keys [title block-uid shift?] :or {shift? false} :as args}]] + (log/debug ":page/new args" (pr-str args)) + (let [event (common-events/build-atomic-event (graph-ops/build-page-new-op @db/dsdb + title + block-uid))] + {:fx [[:dispatch-n [[:resolve-transact-forward event] + [:page/new-followup title shift?] + [:editing/uid block-uid]]]]}))) (reg-event-fx - :page/rename - (fn [_ [_ {:keys [old-name new-name callback] :as args}]] - (log/debug ":page/rename args:" (pr-str (select-keys args [:old-name :new-name]))) - (let [event (common-events/build-atomic-event (atomic-graph-ops/make-page-rename-op old-name new-name))] - {:fx [[:dispatch [:resolve-transact-forward event]] - [:invoke-callback callback]]}))) + :page/rename + (fn [_ [_ {:keys [old-name new-name callback] :as args}]] + (log/debug ":page/rename args:" (pr-str (select-keys args [:old-name :new-name]))) + (let [event (common-events/build-atomic-event (atomic-graph-ops/make-page-rename-op old-name new-name))] + {:fx [[:dispatch [:resolve-transact-forward event]] + [:invoke-callback callback]]}))) (reg-event-fx - :page/merge - (fn [_ [_ {:keys [from-name to-name callback] :as args}]] - (log/debug ":page/merge args:" (pr-str (select-keys args [:from-name :to-name]))) - (let [event (common-events/build-atomic-event (atomic-graph-ops/make-page-merge-op from-name to-name))] - {:fx [[:dispatch [:resolve-transact-forward event]] - [:invoke-callback callback]]}))) + :page/merge + (fn [_ [_ {:keys [from-name to-name callback] :as args}]] + (log/debug ":page/merge args:" (pr-str (select-keys args [:from-name :to-name]))) + (let [event (common-events/build-atomic-event (atomic-graph-ops/make-page-merge-op from-name to-name))] + {:fx [[:dispatch [:resolve-transact-forward event]] + [:invoke-callback callback]]}))) (reg-event-fx - :page/new-followup - (fn [_ [_ title shift?]] - (log/debug ":page/new-followup title" title "shift?" shift?) - (let [page-uid (common-db/get-page-uid @db/dsdb title)] - {:fx [[:dispatch-n [(cond - shift? - [:right-sidebar/open-item page-uid] + :page/new-followup + (fn [_ [_ title shift?]] + (log/debug ":page/new-followup title" title "shift?" shift?) + (let [page-uid (common-db/get-page-uid @db/dsdb title)] + {:fx [[:dispatch-n [(cond + shift? + [:right-sidebar/open-item page-uid] - (not (dates/is-daily-note page-uid)) - [:navigate :page {:id page-uid}] + (not (dates/is-daily-note page-uid)) + [:navigate :page {:id page-uid}] - (dates/is-daily-note page-uid) - [:daily-note/add page-uid])]]]}))) + (dates/is-daily-note page-uid) + [:daily-note/add page-uid])]]]}))) (reg-event-fx - :backspace/delete-merge-block - (fn [_ [_ {:keys [uid value prev-block-uid embed-id prev-block] :as args}]] - (log/debug ":backspace/delete-merge-block args:" (pr-str args)) - (let [sentry-tx (close-and-get-sentry-tx "backspace/delete-merge-block") - op (wrap-span-no-new-tx "build-block-remove-merge-op" - (graph-ops/build-block-remove-merge-op @db/dsdb - uid - prev-block-uid - value)) - event (common-events/build-atomic-event op)] - {:fx [(transact-async-flow :backspace-delete-merge-block event sentry-tx - [(focus-on-uid prev-block-uid embed-id - (count (:block/string prev-block)))])]}))) + :backspace/delete-merge-block + (fn [_ [_ {:keys [uid value prev-block-uid embed-id prev-block] :as args}]] + (log/debug ":backspace/delete-merge-block args:" (pr-str args)) + (let [sentry-tx (close-and-get-sentry-tx "backspace/delete-merge-block") + op (wrap-span-no-new-tx "build-block-remove-merge-op" + (graph-ops/build-block-remove-merge-op @db/dsdb + uid + prev-block-uid + value)) + event (common-events/build-atomic-event op)] + {:fx [(transact-async-flow :backspace-delete-merge-block event sentry-tx + [(focus-on-uid prev-block-uid embed-id + (count (:block/string prev-block)))])]}))) (reg-event-fx - :backspace/delete-merge-block-with-save - (fn [_ [_ {:keys [uid value prev-block-uid embed-id local-update] :as args}]] - (log/debug ":backspace/delete-merge-block-with-save args:" (pr-str args)) - (let [sentry-tx (close-and-get-sentry-tx "backspace/delete-merge-block-with-save") - op (wrap-span-no-new-tx "build-block-merge-with-updated-op" - (graph-ops/build-block-merge-with-updated-op @db/dsdb - uid - prev-block-uid - value - local-update)) - event (common-events/build-atomic-event op)] - {:fx [(transact-async-flow :backspace-delete-merge-block-with-save event sentry-tx - [(focus-on-uid prev-block-uid embed-id (count local-update))])]}))) + :backspace/delete-merge-block-with-save + (fn [_ [_ {:keys [uid value prev-block-uid embed-id local-update] :as args}]] + (log/debug ":backspace/delete-merge-block-with-save args:" (pr-str args)) + (let [sentry-tx (close-and-get-sentry-tx "backspace/delete-merge-block-with-save") + op (wrap-span-no-new-tx "build-block-merge-with-updated-op" + (graph-ops/build-block-merge-with-updated-op @db/dsdb + uid + prev-block-uid + value + local-update)) + event (common-events/build-atomic-event op)] + {:fx [(transact-async-flow :backspace-delete-merge-block-with-save event sentry-tx + [(focus-on-uid prev-block-uid embed-id (count local-update))])]}))) ;; Atomic events end ========== (reg-event-fx - :enter/add-child - (fn [_ [_ {:keys [block new-uid embed-id] :as args}]] - (log/debug ":enter/add-child args:" (pr-str args)) - (let [sentry-tx (close-and-get-sentry-tx "enter/add-child") - position (wrap-span-no-new-tx "compat-position" - (common-db/compat-position @db/dsdb {:block/uid (:block/uid block) - :relation :first})) - event (common-events/build-atomic-event (atomic-graph-ops/make-block-new-op new-uid position))] - {:fx [(transact-async-flow :enter-add-child event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) + :enter/add-child + (fn [_ [_ {:keys [block new-uid embed-id] :as args}]] + (log/debug ":enter/add-child args:" (pr-str args)) + (let [sentry-tx (close-and-get-sentry-tx "enter/add-child") + position (wrap-span-no-new-tx "compat-position" + (common-db/compat-position @db/dsdb {:block/uid (:block/uid block) + :relation :first})) + event (common-events/build-atomic-event (atomic-graph-ops/make-block-new-op new-uid position))] + {:fx [(transact-async-flow :enter-add-child event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) (reg-event-fx - :enter/split-block - (fn [_ [_ {:keys [uid new-uid value index embed-id relation] :as args}]] - (log/debug ":enter/split-block" (pr-str args)) - (let [sentry-tx (close-and-get-sentry-tx "enter/split-block") - op (wrap-span-no-new-tx "build-block-split-op" - (graph-ops/build-block-split-op @db/dsdb - {:old-block-uid uid - :new-block-uid new-uid - :string value - :index index - :relation relation})) - event (common-events/build-atomic-event op)] - {:fx [(transact-async-flow :enter-split-block event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) + :enter/split-block + (fn [_ [_ {:keys [uid new-uid value index embed-id relation] :as args}]] + (log/debug ":enter/split-block" (pr-str args)) + (let [sentry-tx (close-and-get-sentry-tx "enter/split-block") + op (wrap-span-no-new-tx "build-block-split-op" + (graph-ops/build-block-split-op @db/dsdb + {:old-block-uid uid + :new-block-uid new-uid + :string value + :index index + :relation relation})) + event (common-events/build-atomic-event op)] + {:fx [(transact-async-flow :enter-split-block event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) (reg-event-fx - :enter/bump-up - (fn [_ [_ {:keys [uid new-uid embed-id] :as args}]] - (log/debug ":enter/bump-up args" (pr-str args)) - (let [sentry-tx (close-and-get-sentry-tx "enter/bump-up") - position (wrap-span-no-new-tx "compat-position" - (common-db/compat-position @db/dsdb {:block/uid uid - :relation :before})) - event (common-events/build-atomic-event (atomic-graph-ops/make-block-new-op new-uid position))] - {:fx [(transact-async-flow :enter-bump-up event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) + :enter/bump-up + (fn [_ [_ {:keys [uid new-uid embed-id] :as args}]] + (log/debug ":enter/bump-up args" (pr-str args)) + (let [sentry-tx (close-and-get-sentry-tx "enter/bump-up") + position (wrap-span-no-new-tx "compat-position" + (common-db/compat-position @db/dsdb {:block/uid uid + :relation :before})) + event (common-events/build-atomic-event (atomic-graph-ops/make-block-new-op new-uid position))] + {:fx [(transact-async-flow :enter-bump-up event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) (reg-event-fx - :enter/open-block-add-child - (fn [_ [_ {:keys [block new-uid embed-id]}]] + :enter/open-block-add-child + (fn [_ [_ {:keys [block new-uid embed-id]}]] ;; Triggered when there is a closed embeded block with no content in the top level block ;; and then one presses enter in the embeded block. - (log/debug ":enter/open-block-add-child" (pr-str block) (pr-str new-uid)) - (let [sentry-tx (close-and-get-sentry-tx "enter/open-block-add-child") - block-uid (:block/uid block) - block-open-op (atomic-graph-ops/make-block-open-op block-uid - true) - position (wrap-span-no-new-tx "compat-position" - (common-db/compat-position @db/dsdb {:block/uid (:block/uid block) - :relation :first})) - add-child-op (atomic-graph-ops/make-block-new-op new-uid position) - open-block-add-child-op (composite-ops/make-consequence-op {:op/type :open-block-add-child} - [block-open-op - add-child-op]) - event (common-events/build-atomic-event open-block-add-child-op)] - {:fx [(transact-async-flow :enter-open-block-add-child event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) + (log/debug ":enter/open-block-add-child" (pr-str block) (pr-str new-uid)) + (let [sentry-tx (close-and-get-sentry-tx "enter/open-block-add-child") + block-uid (:block/uid block) + block-open-op (atomic-graph-ops/make-block-open-op block-uid + true) + position (wrap-span-no-new-tx "compat-position" + (common-db/compat-position @db/dsdb {:block/uid (:block/uid block) + :relation :first})) + add-child-op (atomic-graph-ops/make-block-new-op new-uid position) + open-block-add-child-op (composite-ops/make-consequence-op {:op/type :open-block-add-child} + [block-open-op + add-child-op]) + event (common-events/build-atomic-event open-block-add-child-op)] + {:fx [(transact-async-flow :enter-open-block-add-child event sentry-tx [(focus-on-uid new-uid embed-id)])]}))) (defn enter @@ -1314,10 +1314,10 @@ (reg-event-fx - :enter - [(interceptors/sentry-span-no-new-tx "enter")] - (fn [{rfdb :db} [_ uid d-event]] - (enter rfdb uid d-event))) + :enter + [(interceptors/sentry-span-no-new-tx "enter")] + (fn [{rfdb :db} [_ uid d-event]] + (enter rfdb uid d-event))) (defn get-prev-block-uid-and-target-rel @@ -1346,285 +1346,285 @@ (reg-event-fx - :indent - (fn [{:keys [_db]} [_ {:keys [uid d-key-down local-string] :as args}]] + :indent + (fn [{:keys [_db]} [_ {:keys [uid d-key-down local-string] :as args}]] ;; - `block-zero`: The first block in a page ;; - `value` : The current string inside the block being indented. Otherwise, if user changes block string and indents, ;; the local string is reset to original value, since it has not been unfocused yet (which is currently the ;; transaction that updates the string). - (let [sentry-tx (close-and-get-sentry-tx "indent") - block (wrap-span-no-new-tx "get-block" - (common-db/get-block @db/dsdb [:block/uid uid])) - block-zero? (zero? (:block/order block)) - [prev-block-uid - target-rel] (wrap-span-no-new-tx "get-prev-block-uid-and-target-rel" - (get-prev-block-uid-and-target-rel uid)) - sib-block (wrap-span-no-new-tx "get-block-sib-block" - (common-db/get-block @db/dsdb [:block/uid prev-block-uid])) + (let [sentry-tx (close-and-get-sentry-tx "indent") + block (wrap-span-no-new-tx "get-block" + (common-db/get-block @db/dsdb [:block/uid uid])) + block-zero? (zero? (:block/order block)) + [prev-block-uid + target-rel] (wrap-span-no-new-tx "get-prev-block-uid-and-target-rel" + (get-prev-block-uid-and-target-rel uid)) + sib-block (wrap-span-no-new-tx "get-block-sib-block" + (common-db/get-block @db/dsdb [:block/uid prev-block-uid])) ;; if sibling block is closed with children, open - {sib-open :block/open - sib-children :block/children - sib-uid :block/uid} sib-block - block-closed? (and (not sib-open) sib-children) - sib-block-open-op (when block-closed? - (atomic-graph-ops/make-block-open-op sib-uid true)) - {:keys [start end]} d-key-down - block-save-block-move-op (block-save-block-move-composite-op uid - prev-block-uid - target-rel - local-string) - event (common-events/build-atomic-event - (composite-ops/make-consequence-op {:op/type :indent} - (cond-> [block-save-block-move-op] - block-closed? (conj sib-block-open-op))))] - (log/debug "null-sib-uid" (and block-zero? - prev-block-uid) - ", args:" (pr-str args) - ", block-zero?" block-zero?) - (when (and prev-block-uid - (not block-zero?)) - {:fx [(transact-async-flow :indent event sentry-tx []) - [:set-cursor-position [uid start end]]]})))) - - -(reg-event-fx - :indent/multi - (fn [_ [_ {:keys [uids]}]] - (log/debug ":indent/multi" (pr-str uids)) - (let [sentry-tx (close-and-get-sentry-tx "indent/multi") - sanitized-selected-uids (mapv (comp first common-db/uid-and-embed-id) uids) - f-uid (first sanitized-selected-uids) - dsdb @db/dsdb - [prev-block-uid - target-rel] (wrap-span-no-new-tx "get-prev-block-uid-and-target-rel" - (get-prev-block-uid-and-target-rel f-uid)) - same-parent? (wrap-span-no-new-tx "same-parent" - (common-db/same-parent? dsdb sanitized-selected-uids)) - first-block-order (:block/order (wrap-span-no-new-tx "get-block" - (common-db/get-block dsdb [:block/uid f-uid]))) - block-zero? (zero? first-block-order)] - (log/debug ":indent/multi same-parent?" same-parent? - ", not block-zero?" (not block-zero?)) - (when (and same-parent? (not block-zero?)) - {:fx [[:async-flow {:id :indent-multi-async-flow - :db-path [:async-flow :indent-multi] - :first-dispatch [:drop-multi/sibling {:source-uids sanitized-selected-uids - :target-uid prev-block-uid - :drag-target target-rel}] - :rules (wait-for-rft sentry-tx [])}]]})))) - - -(reg-event-fx - :unindent - (fn [{:keys [_db]} [_ {:keys [uid d-key-down context-root-uid embed-id local-string] :as args}]] - (log/debug ":unindent args" (pr-str args)) - (let [sentry-tx (close-and-get-sentry-tx "unindent") - parent (wrap-span-no-new-tx "parent" - (common-db/get-parent @db/dsdb - (common-db/e-by-av @db/dsdb :block/uid uid))) - is-parent-root-embed? (= (some-> d-key-down - :target - (.. (closest ".block-embed")) - (. -firstChild) - (.getAttribute "data-uid")) - (str (:block/uid parent) "-embed-" embed-id)) - do-nothing? (or is-parent-root-embed? - (:node/title parent) - (= context-root-uid (:block/uid parent))) - {:keys [start end]} d-key-down - block-save-block-move-op (block-save-block-move-composite-op uid - (:block/uid parent) - :after - local-string) - event (common-events/build-atomic-event block-save-block-move-op)] - - (log/debug ":unindent do-nothing?" do-nothing?) - (when-not do-nothing? - {:fx [(transact-async-flow :unindent event sentry-tx [(focus-on-uid uid embed-id)]) - [:set-cursor-position [uid start end]]]})))) - - -(reg-event-fx - :unindent/multi - (fn [{:keys [db]} [_ {:keys [uids]}]] - (log/debug ":unindent/multi" uids) - (let [sentry-tx (close-and-get-sentry-tx "unindent/multi") - [f-uid f-embed-id] (wrap-span-no-new-tx "uid-and-embed-id" - (common-db/uid-and-embed-id (first uids))) - sanitized-selected-uids (mapv (comp - first - common-db/uid-and-embed-id) uids) - {parent-title :node/title - parent-uid :block/uid} (wrap-span-no-new-tx "get-parent" - (common-db/get-parent @db/dsdb [:block/uid f-uid])) - same-parent? (wrap-span-no-new-tx "same-parent" - (common-db/same-parent? @db/dsdb sanitized-selected-uids)) - is-parent-root-embed? (when same-parent? - (some-> "#editable-uid-" - (str f-uid "-embed-" f-embed-id) - js/document.querySelector + {sib-open :block/open + sib-children :block/children + sib-uid :block/uid} sib-block + block-closed? (and (not sib-open) sib-children) + sib-block-open-op (when block-closed? + (atomic-graph-ops/make-block-open-op sib-uid true)) + {:keys [start end]} d-key-down + block-save-block-move-op (block-save-block-move-composite-op uid + prev-block-uid + target-rel + local-string) + event (common-events/build-atomic-event + (composite-ops/make-consequence-op {:op/type :indent} + (cond-> [block-save-block-move-op] + block-closed? (conj sib-block-open-op))))] + (log/debug "null-sib-uid" (and block-zero? + prev-block-uid) + ", args:" (pr-str args) + ", block-zero?" block-zero?) + (when (and prev-block-uid + (not block-zero?)) + {:fx [(transact-async-flow :indent event sentry-tx []) + [:set-cursor-position [uid start end]]]})))) + + +(reg-event-fx + :indent/multi + (fn [_ [_ {:keys [uids]}]] + (log/debug ":indent/multi" (pr-str uids)) + (let [sentry-tx (close-and-get-sentry-tx "indent/multi") + sanitized-selected-uids (mapv (comp first common-db/uid-and-embed-id) uids) + f-uid (first sanitized-selected-uids) + dsdb @db/dsdb + [prev-block-uid + target-rel] (wrap-span-no-new-tx "get-prev-block-uid-and-target-rel" + (get-prev-block-uid-and-target-rel f-uid)) + same-parent? (wrap-span-no-new-tx "same-parent" + (common-db/same-parent? dsdb sanitized-selected-uids)) + first-block-order (:block/order (wrap-span-no-new-tx "get-block" + (common-db/get-block dsdb [:block/uid f-uid]))) + block-zero? (zero? first-block-order)] + (log/debug ":indent/multi same-parent?" same-parent? + ", not block-zero?" (not block-zero?)) + (when (and same-parent? (not block-zero?)) + {:fx [[:async-flow {:id :indent-multi-async-flow + :db-path [:async-flow :indent-multi] + :first-dispatch [:drop-multi/sibling {:source-uids sanitized-selected-uids + :target-uid prev-block-uid + :drag-target target-rel}] + :rules (wait-for-rft sentry-tx [])}]]})))) + + +(reg-event-fx + :unindent + (fn [{:keys [_db]} [_ {:keys [uid d-key-down context-root-uid embed-id local-string] :as args}]] + (log/debug ":unindent args" (pr-str args)) + (let [sentry-tx (close-and-get-sentry-tx "unindent") + parent (wrap-span-no-new-tx "parent" + (common-db/get-parent @db/dsdb + (common-db/e-by-av @db/dsdb :block/uid uid))) + is-parent-root-embed? (= (some-> d-key-down + :target (.. (closest ".block-embed")) (. -firstChild) - (.getAttribute "data-uid") - (= (str parent-uid "-embed-" f-embed-id)))) - context-root-uid (get-in db [:current-route :path-params :id]) - do-nothing? (or parent-title - (not same-parent?) - (and same-parent? is-parent-root-embed?) - (= parent-uid context-root-uid))] - (log/debug ":unindent/multi do-nothing?" do-nothing?) - (when-not do-nothing? - {:fx [[:async-flow {:id :unindent-multi-async-flow - :db-path [:async-flow :unindent-multi] - :first-dispatch [:drop-multi/sibling {:source-uids sanitized-selected-uids - :target-uid parent-uid - :drag-target :after}] - :rules (wait-for-rft sentry-tx [])}]]})))) - - -(reg-event-fx - :block/move - (fn [_ [_ {:keys [source-uid target-uid target-rel] :as args}]] - (log/debug ":block/move args" (pr-str args)) - (let [atomic-event (common-events/build-atomic-event - (atomic-graph-ops/make-block-move-op source-uid - {:block/uid target-uid - :relation target-rel}))] - {:fx [[:dispatch [:resolve-transact-forward atomic-event]]]}))) - - -(reg-event-fx - :block/link - (fn [_ [_ {:keys [source-uid target-uid target-rel] :as args}]] - (log/debug ":block/link args" (pr-str args)) - (let [block-uid (common.utils/gen-block-uid) - atomic-event (common-events/build-atomic-event - (composite-ops/make-consequence-op {:op/type :block/link} - [(atomic-graph-ops/make-block-new-op block-uid - {:block/uid target-uid - :relation target-rel}) - (atomic-graph-ops/make-block-save-op block-uid - (str "((" source-uid "))"))]))] - {:fx [[:dispatch [:resolve-transact-forward atomic-event]]]}))) - - -(reg-event-fx - :drop-multi/child - (fn [_ [_ {:keys [source-uids target-uid] :as args}]] - (log/debug ":drop-multi/child args" (pr-str args)) - (let [atomic-op (graph-ops/block-move-chain target-uid source-uids :first) - event (common-events/build-atomic-event atomic-op)] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) - - -(reg-event-fx - :drop-multi/sibling - (fn [_ [_ {:keys [source-uids target-uid drag-target] :as args}]] + (.getAttribute "data-uid")) + (str (:block/uid parent) "-embed-" embed-id)) + do-nothing? (or is-parent-root-embed? + (:node/title parent) + (= context-root-uid (:block/uid parent))) + {:keys [start end]} d-key-down + block-save-block-move-op (block-save-block-move-composite-op uid + (:block/uid parent) + :after + local-string) + event (common-events/build-atomic-event block-save-block-move-op)] + + (log/debug ":unindent do-nothing?" do-nothing?) + (when-not do-nothing? + {:fx [(transact-async-flow :unindent event sentry-tx [(focus-on-uid uid embed-id)]) + [:set-cursor-position [uid start end]]]})))) + + +(reg-event-fx + :unindent/multi + (fn [{:keys [db]} [_ {:keys [uids]}]] + (log/debug ":unindent/multi" uids) + (let [sentry-tx (close-and-get-sentry-tx "unindent/multi") + [f-uid f-embed-id] (wrap-span-no-new-tx "uid-and-embed-id" + (common-db/uid-and-embed-id (first uids))) + sanitized-selected-uids (mapv (comp + first + common-db/uid-and-embed-id) uids) + {parent-title :node/title + parent-uid :block/uid} (wrap-span-no-new-tx "get-parent" + (common-db/get-parent @db/dsdb [:block/uid f-uid])) + same-parent? (wrap-span-no-new-tx "same-parent" + (common-db/same-parent? @db/dsdb sanitized-selected-uids)) + is-parent-root-embed? (when same-parent? + (some-> "#editable-uid-" + (str f-uid "-embed-" f-embed-id) + js/document.querySelector + (.. (closest ".block-embed")) + (. -firstChild) + (.getAttribute "data-uid") + (= (str parent-uid "-embed-" f-embed-id)))) + context-root-uid (get-in db [:current-route :path-params :id]) + do-nothing? (or parent-title + (not same-parent?) + (and same-parent? is-parent-root-embed?) + (= parent-uid context-root-uid))] + (log/debug ":unindent/multi do-nothing?" do-nothing?) + (when-not do-nothing? + {:fx [[:async-flow {:id :unindent-multi-async-flow + :db-path [:async-flow :unindent-multi] + :first-dispatch [:drop-multi/sibling {:source-uids sanitized-selected-uids + :target-uid parent-uid + :drag-target :after}] + :rules (wait-for-rft sentry-tx [])}]]})))) + + +(reg-event-fx + :block/move + (fn [_ [_ {:keys [source-uid target-uid target-rel] :as args}]] + (log/debug ":block/move args" (pr-str args)) + (let [atomic-event (common-events/build-atomic-event + (atomic-graph-ops/make-block-move-op source-uid + {:block/uid target-uid + :relation target-rel}))] + {:fx [[:dispatch [:resolve-transact-forward atomic-event]]]}))) + + +(reg-event-fx + :block/link + (fn [_ [_ {:keys [source-uid target-uid target-rel] :as args}]] + (log/debug ":block/link args" (pr-str args)) + (let [block-uid (common.utils/gen-block-uid) + atomic-event (common-events/build-atomic-event + (composite-ops/make-consequence-op {:op/type :block/link} + [(atomic-graph-ops/make-block-new-op block-uid + {:block/uid target-uid + :relation target-rel}) + (atomic-graph-ops/make-block-save-op block-uid + (str "((" source-uid "))"))]))] + {:fx [[:dispatch [:resolve-transact-forward atomic-event]]]}))) + + +(reg-event-fx + :drop-multi/child + (fn [_ [_ {:keys [source-uids target-uid] :as args}]] + (log/debug ":drop-multi/child args" (pr-str args)) + (let [atomic-op (graph-ops/block-move-chain target-uid source-uids :first) + event (common-events/build-atomic-event atomic-op)] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + + +(reg-event-fx + :drop-multi/sibling + (fn [_ [_ {:keys [source-uids target-uid drag-target] :as args}]] ;; When the selected blocks have same parent and are DnD under the same parent this event is fired. ;; This also applies if on selects multiple Zero level blocks and change the order among other Zero level blocks. - (log/debug ":drop-multi/sibling args" (pr-str args)) - (let [rel-position drag-target - atomic-op (graph-ops/block-move-chain target-uid source-uids rel-position) - event (common-events/build-atomic-event atomic-op)] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) - - -(reg-event-fx - :paste-internal - [(interceptors/sentry-span-no-new-tx "paste-internal")] - (fn [_ [_ uid local-str internal-representation]] - (let [[uid] (db/uid-and-embed-id uid) - op (bfs/build-paste-op @db/dsdb - uid - local-str - internal-representation) - event (common-events/build-atomic-event op)] - (log/debug "paste internal event is" (pr-str event)) - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) - - -(reg-event-fx - :paste-image - [(interceptors/sentry-span-no-new-tx "paste-image")] - (fn [{:keys [db]} [_ items head tail callback]] - (let [local? (not (db-picker/remote-db? db)) - img-regex #"(?i)^image/(p?jpeg|gif|png)$"] - (log/debug ":paste-image : local?" local?) - (if local? - (do - (mapv (fn [item] - (let [datatype (.. item -type)] - (cond - (re-find img-regex datatype) (when electron.utils/electron? - (let [new-str (images/save-image head tail item "png")] - (callback new-str))) - (re-find #"text/html" datatype) (.getAsString item (fn [_] #_(prn "getAsString" _)))))) - items) - {}) - {:fx (util/toast (clj->js {:status "error" - :title "Couldn't paste" - :description "Image paste is not supported in Lan-Party, yet."}))})))) - - -(reg-event-fx - :paste-verbatim - [(interceptors/sentry-span-no-new-tx "paste-verbatim")] - (fn [_ [_ uid text]] + (log/debug ":drop-multi/sibling args" (pr-str args)) + (let [rel-position drag-target + atomic-op (graph-ops/block-move-chain target-uid source-uids rel-position) + event (common-events/build-atomic-event atomic-op)] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + + +(reg-event-fx + :paste-internal + [(interceptors/sentry-span-no-new-tx "paste-internal")] + (fn [_ [_ uid local-str internal-representation]] + (let [[uid] (db/uid-and-embed-id uid) + op (bfs/build-paste-op @db/dsdb + uid + local-str + internal-representation) + event (common-events/build-atomic-event op)] + (log/debug "paste internal event is" (pr-str event)) + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + + +(reg-event-fx + :paste-image + [(interceptors/sentry-span-no-new-tx "paste-image")] + (fn [{:keys [db]} [_ items head tail callback]] + (let [local? (not (db-picker/remote-db? db)) + img-regex #"(?i)^image/(p?jpeg|gif|png)$"] + (log/debug ":paste-image : local?" local?) + (if local? + (do + (mapv (fn [item] + (let [datatype (.. item -type)] + (cond + (re-find img-regex datatype) (when electron.utils/electron? + (let [new-str (images/save-image head tail item "png")] + (callback new-str))) + (re-find #"text/html" datatype) (.getAsString item (fn [_] #_(prn "getAsString" _)))))) + items) + {}) + {:fx (util/toast (clj->js {:status "error" + :title "Couldn't paste" + :description "Image paste is not supported in Lan-Party, yet."}))})))) + + +(reg-event-fx + :paste-verbatim + [(interceptors/sentry-span-no-new-tx "paste-verbatim")] + (fn [_ [_ uid text]] ;; NOTE: use of `value` is questionable, it's the DOM so it's what users sees, ;; but what users sees should taken from DB. How would `value` behave with multiple editors? - (let [{:keys [start value]} (textarea-keydown/destruct-target js/document.activeElement) - block-empty? (string/blank? value) - block-start? (zero? start) - new-string (cond - block-empty? text - (and (not block-empty?) - block-start?) (str text value) - :else (str (subs value 0 start) - text - (subs value start))) - op (graph-ops/build-block-save-op @db/dsdb uid new-string) - event (common-events/build-atomic-event op)] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) - - -(reg-event-fx - :unlinked-references/link - (fn [_ [_ {:block/keys [string uid]} title]] - (log/debug ":unlinked-references/link:" uid) - (let [ignore-case-title (re-pattern (str "(?i)" title)) - new-str (string/replace string ignore-case-title (str "[[" title "]]")) - op (graph-ops/build-block-save-op @db/dsdb - uid - new-str) - event (common-events/build-atomic-event op)] - {:fx [[:dispatch [:resolve-transact-forward event]] - [:dispatch [:posthog/report-feature :unlinked-references]]]}))) - - -(reg-event-fx - :unlinked-references/link-all - (fn [_ [_ unlinked-refs title]] - (log/debug ":unlinked-references/link:" title) - (let [block-save-ops (mapv - (fn [{:block/keys [string uid]}] - (let [ignore-case-title (re-pattern (str "(?i)" title)) - new-str (string/replace string ignore-case-title (str "[[" title "]]"))] - (graph-ops/build-block-save-op @db/dsdb - uid - new-str))) - unlinked-refs) - link-all-op (composite-ops/make-consequence-op {:op/type :block/unlinked-refs-link-all} - block-save-ops) - event (common-events/build-atomic-event link-all-op)] - {:fx [[:dispatch [:resolve-transact-forward event]] - [:dispatch [:posthog/report-feature :unlinked-references]]]}))) + (let [{:keys [start value]} (textarea-keydown/destruct-target js/document.activeElement) + block-empty? (string/blank? value) + block-start? (zero? start) + new-string (cond + block-empty? text + (and (not block-empty?) + block-start?) (str text value) + :else (str (subs value 0 start) + text + (subs value start))) + op (graph-ops/build-block-save-op @db/dsdb uid new-string) + event (common-events/build-atomic-event op)] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + + +(reg-event-fx + :unlinked-references/link + (fn [_ [_ {:block/keys [string uid]} title]] + (log/debug ":unlinked-references/link:" uid) + (let [ignore-case-title (re-pattern (str "(?i)" title)) + new-str (string/replace string ignore-case-title (str "[[" title "]]")) + op (graph-ops/build-block-save-op @db/dsdb + uid + new-str) + event (common-events/build-atomic-event op)] + {:fx [[:dispatch [:resolve-transact-forward event]] + [:dispatch [:posthog/report-feature :unlinked-references]]]}))) + + +(reg-event-fx + :unlinked-references/link-all + (fn [_ [_ unlinked-refs title]] + (log/debug ":unlinked-references/link:" title) + (let [block-save-ops (mapv + (fn [{:block/keys [string uid]}] + (let [ignore-case-title (re-pattern (str "(?i)" title)) + new-str (string/replace string ignore-case-title (str "[[" title "]]"))] + (graph-ops/build-block-save-op @db/dsdb + uid + new-str))) + unlinked-refs) + link-all-op (composite-ops/make-consequence-op {:op/type :block/unlinked-refs-link-all} + block-save-ops) + event (common-events/build-atomic-event link-all-op)] + {:fx [[:dispatch [:resolve-transact-forward event]] + [:dispatch [:posthog/report-feature :unlinked-references]]]}))) (rf/reg-event-fx - :block/open - (fn [_ [_ {:keys [block-uid open?] :as args}]] - (log/debug ":block/open args" args) - (let [event (common-events/build-atomic-event - (atomic-graph-ops/make-block-open-op block-uid open?))] - {:fx [[:dispatch [:resolve-transact-forward event]]]}))) + :block/open + (fn [_ [_ {:keys [block-uid open?] :as args}]] + (log/debug ":block/open args" args) + (let [event (common-events/build-atomic-event + (atomic-graph-ops/make-block-open-op block-uid open?))] + {:fx [[:dispatch [:resolve-transact-forward event]]]}))) diff --git a/src/cljs/athens/parse_renderer.cljs b/src/cljs/athens/parse_renderer.cljs index b4804b17dd..53224cf19e 100644 --- a/src/cljs/athens/parse_renderer.cljs +++ b/src/cljs/athens/parse_renderer.cljs @@ -17,16 +17,18 @@ (def fm-props {:as "b" :class "formatting" :fontWeight "normal" :opacity "0.3"}) -(def link-props {:color "link" - :borderRadius "1px" - :variant "link" - :minWidth "0" - :whiteSpace "normal" - :wordBreak "break-word" - :lineHeight "unset" - :fontSize "inherit" - :fontWeight "inherit" - :textDecoration "none"}) + +(def link-props + {:color "link" + :borderRadius "1px" + :variant "link" + :minWidth "0" + :whiteSpace "normal" + :wordBreak "break-word" + :lineHeight "unset" + :fontSize "inherit" + :fontWeight "inherit" + :textDecoration "none"}) (defn parse-title @@ -66,21 +68,21 @@ :else (into - [:> Button - (merge link-props - {:class "page-link" - :title from - :onClick (fn [e] - (let [parsed-title (parse-title title-coll) - shift? (.-shiftKey e)] - (.. e stopPropagation) ; prevent bubbling up click handler for nested links - (rf/dispatch [:reporting/navigation {:source :pr-page-link - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))})] - title-coll)) + [:> Button + (merge link-props + {:class "page-link" + :title from + :onClick (fn [e] + (let [parsed-title (parse-title title-coll) + shift? (.-shiftKey e)] + (.. e stopPropagation) ; prevent bubbling up click handler for nested links + (rf/dispatch [:reporting/navigation {:source :pr-page-link + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))})] + title-coll)) [:> Text fm-props "]]"]]) @@ -95,53 +97,53 @@ (defn render-block-ref [{:keys [from title]} ref-uid uid] (let [block (reactive/get-reactive-block-or-page-by-uid ref-uid) - parents (reactive/get-reactive-parents-recursively [:block/uid ref-uid]) + parents (reactive/get-reactive-parents-recursively [:block/uid ref-uid]) bc-string (block-breadcrumb-string parents)] (if block - [:> Button {:variant "link" - :as "a" - :title (-> from - (str/replace "](" - "]\n---\n(") - (str/replace (str "((" ref-uid "))") - bc-string)) - :class "block-ref" - :display "inline" - :color "unset" - :whiteSpace "unset" - :textAlign "unset" - :minWidth "0" - :fontSize "inherit" - :fontWeight "inherit" - :lineHeight "inherit" - :marginInline "-2px" - :paddingInline "2px" - :borderBottomWidth "1px" - :borderBottomStyle "solid" - :borderBottomColor "ref.foreground" - :cursor "alias" - :sx {"WebkitBoxDecorationBreak" "clone"} - :_hover {:textDecoration "none" - :borderBottomColor "transparent" - :bg "ref.background"} - :onClick (fn [e] - (.. e stopPropagation) - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :pr-block-ref - :target :block - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-uid ref-uid e)))} - (cond - (= uid ref-uid) - [parse-and-render "{{SELF}}"] - - (not (str/blank? title)) - [parse-and-render title ref-uid] - - :else - [parse-and-render (:block/string block) ref-uid])] + [:> Button {:variant "link" + :as "a" + :title (-> from + (str/replace "](" + "]\n---\n(") + (str/replace (str "((" ref-uid "))") + bc-string)) + :class "block-ref" + :display "inline" + :color "unset" + :whiteSpace "unset" + :textAlign "unset" + :minWidth "0" + :fontSize "inherit" + :fontWeight "inherit" + :lineHeight "inherit" + :marginInline "-2px" + :paddingInline "2px" + :borderBottomWidth "1px" + :borderBottomStyle "solid" + :borderBottomColor "ref.foreground" + :cursor "alias" + :sx {"WebkitBoxDecorationBreak" "clone"} + :_hover {:textDecoration "none" + :borderBottomColor "transparent" + :bg "ref.background"} + :onClick (fn [e] + (.. e stopPropagation) + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :pr-block-ref + :target :block + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-uid ref-uid e)))} + (cond + (= uid ref-uid) + [parse-and-render "{{SELF}}"] + + (not (str/blank? title)) + [parse-and-render title ref-uid] + + :else + [parse-and-render (:block/string block) ref-uid])] from))) @@ -186,110 +188,110 @@ "Transforms Instaparse output to Hiccup." [tree uid] (insta/transform - {:block (fn [& contents] - (apply clean-single-p-appending - [:span {:class "block"}] - contents)) - :heading (fn [{n :n} & contents] - (apply clean-single-p-appending - [({1 :h1 - 2 :h2 - 3 :h3 - 4 :h4 - 5 :h5 - 6 :h6} n)] - contents)) + {:block (fn [& contents] + (apply clean-single-p-appending + [:span {:class "block"}] + contents)) + :heading (fn [{n :n} & contents] + (apply clean-single-p-appending + [({1 :h1 + 2 :h2 + 3 :h3 + 4 :h4 + 5 :h5 + 6 :h6} n)] + contents)) ;; for more information regarding how custom components are parsed, see ;; https://athensresearch.gitbook.io/handbook/athens/athens-components-documentation/ - :component (fn [& contents] - (component (first contents) uid)) - :page-link (fn [{_from :from :as attr} & title-coll] - (render-page-link attr title-coll)) - :hashtag (fn [{_from :from} & title-coll] - [:> Button (merge link-props - {:variant "link" - :class "hashtag" - :color "inherit" - :fontWeight "inherit" - :_hover {:textDecoration "none"} - :onClick (fn [e] - (let [parsed-title (parse-title title-coll) - shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :pr-hashtag - :target :hashtag - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))}) - [:> Text fm-props "#"] - [:span {:class "contents"} title-coll]]) - :block-ref (fn [{_from :from :as attr} ref-uid] - (render-block-ref attr ref-uid uid)) - :url-image (fn [{url :src alt :alt}] - [:> Box {:class "url-image" - :as "img" - :borderRadius "md" - :alt alt - :src url}]) - :url-link (fn [{url :url} text] - [:> Button - (merge link-props {:class "url-link" - :href url - :target "_blank"}) - text]) - :link (fn [{:keys [text target title]}] - [:> Button (cond-> (merge link-props - {:class "url-link contents" - :as "a" - :href target - :target "_blank"}) - (string? title) - (assoc :title title)) - text]) - :autolink (fn [{:keys [text target]}] - [:<> - [:> Text fm-props "<"] - [:> Link (merge - link-props - {:class "autolink contents" - :href target - :target "_blank"}) - text] - [:> Text fm-props ">"]]) - :text-run (fn [& contents] - (apply conj [:span {:class "text-run"}] contents)) - :paragraph (fn [& contents] - (apply conj [:p] contents)) - :bold (fn [& contents] - (apply conj [:strong {:class "contents bold"}] contents)) - :italic (fn [& contents] - (apply conj [:i {:class "contents italic"}] contents)) - :strikethrough (fn [& contents] - (apply conj [:del {:class "contents del"}] contents)) - :underline (fn [& contents] - (apply conj [:u {:class "contents underline"}] contents)) - :highlight (fn [& contents] - (apply conj [:mark {:class "contents highlight"}] contents)) - :pre-formatted (fn [text] - [:code text]) - :inline-pre-formatted (fn [text] - [:code text]) - :indented-code-block (fn [{:keys [_from]} code-text] - (let [text (second code-text)] - [:pre - [:code text]])) - :fenced-code-block (fn [{lang :lang} code-text] - (let [mode (or lang "javascript") - text (second code-text)] - (when config/debug? - (js/console.log "Block code, original-mode:" lang - ", mode:" mode - ", text:" text)) + :component (fn [& contents] + (component (first contents) uid)) + :page-link (fn [{_from :from :as attr} & title-coll] + (render-page-link attr title-coll)) + :hashtag (fn [{_from :from} & title-coll] + [:> Button (merge link-props + {:variant "link" + :class "hashtag" + :color "inherit" + :fontWeight "inherit" + :_hover {:textDecoration "none"} + :onClick (fn [e] + (let [parsed-title (parse-title title-coll) + shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :pr-hashtag + :target :hashtag + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))}) + [:> Text fm-props "#"] + [:span {:class "contents"} title-coll]]) + :block-ref (fn [{_from :from :as attr} ref-uid] + (render-block-ref attr ref-uid uid)) + :url-image (fn [{url :src alt :alt}] + [:> Box {:class "url-image" + :as "img" + :borderRadius "md" + :alt alt + :src url}]) + :url-link (fn [{url :url} text] + [:> Button + (merge link-props {:class "url-link" + :href url + :target "_blank"}) + text]) + :link (fn [{:keys [text target title]}] + [:> Button (cond-> (merge link-props + {:class "url-link contents" + :as "a" + :href target + :target "_blank"}) + (string? title) + (assoc :title title)) + text]) + :autolink (fn [{:keys [text target]}] + [:<> + [:> Text fm-props "<"] + [:> Link (merge + link-props + {:class "autolink contents" + :href target + :target "_blank"}) + text] + [:> Text fm-props ">"]]) + :text-run (fn [& contents] + (apply conj [:span {:class "text-run"}] contents)) + :paragraph (fn [& contents] + (apply conj [:p] contents)) + :bold (fn [& contents] + (apply conj [:strong {:class "contents bold"}] contents)) + :italic (fn [& contents] + (apply conj [:i {:class "contents italic"}] contents)) + :strikethrough (fn [& contents] + (apply conj [:del {:class "contents del"}] contents)) + :underline (fn [& contents] + (apply conj [:u {:class "contents underline"}] contents)) + :highlight (fn [& contents] + (apply conj [:mark {:class "contents highlight"}] contents)) + :pre-formatted (fn [text] + [:code text]) + :inline-pre-formatted (fn [text] + [:code text]) + :indented-code-block (fn [{:keys [_from]} code-text] + (let [text (second code-text)] [:pre - [:code text]] + [:code text]])) + :fenced-code-block (fn [{lang :lang} code-text] + (let [mode (or lang "javascript") + text (second code-text)] + (when config/debug? + (js/console.log "Block code, original-mode:" lang + ", mode:" mode + ", text:" text)) + [:pre + [:code text]] ;; TODO: Followup issue: #989 "Integrate with CodeMirror for code blocks" - #_[:> CodeMirror {:value text + #_[:> CodeMirror {:value text :options {:mode mode :lineNumbers true :matchBrackets true @@ -319,18 +321,18 @@ ;; update value based on `uid` )))}])) - :latex (fn [text] - [:span {:ref (fn [el] - (when el - (try - (katex/render text el (clj->js - {:throwOnError false})) - (catch :default e - (js/console.warn "Unexpected KaTeX error" e) - (aset el "innerHTML" text)))))}]) - :newline (fn [_] - [:br])} - tree)) + :latex (fn [text] + [:span {:ref (fn [el] + (when el + (try + (katex/render text el (clj->js + {:throwOnError false})) + (catch :default e + (js/console.warn "Unexpected KaTeX error" e) + (aset el "innerHTML" text)))))}]) + :newline (fn [_] + [:br])} + tree)) (defn parse-and-render diff --git a/src/cljs/athens/self_hosted/presence/views.cljs b/src/cljs/athens/self_hosted/presence/views.cljs index dadd5f1199..43477a0f5c 100644 --- a/src/cljs/athens/self_hosted/presence/views.cljs +++ b/src/cljs/athens/self_hosted/presence/views.cljs @@ -1,13 +1,13 @@ (ns athens.self-hosted.presence.views (:require - ["/components/PresenceDetails/PresenceDetails" :refer [PresenceDetails]] - ["@chakra-ui/react" :refer [Avatar AvatarGroup]] - [athens.self-hosted.presence.events] - [athens.self-hosted.presence.fx] - [athens.self-hosted.presence.subs] - [athens.util :as util] - [re-frame.core :as rf] - [reagent.core :as r])) + ["/components/PresenceDetails/PresenceDetails" :refer [PresenceDetails]] + ["@chakra-ui/react" :refer [Avatar AvatarGroup]] + [athens.self-hosted.presence.events] + [athens.self-hosted.presence.fx] + [athens.self-hosted.presence.subs] + [athens.util :as util] + [re-frame.core :as rf] + [reagent.core :as r])) (defn user->person @@ -34,11 +34,11 @@ (->> (js->clj js-person :keywordize-keys true) :personId (get all-users))] - (if page-uid - ;; TODO: if we support navigating to a block, it should be added here. - (rf/dispatch [:navigate :page {:id page-uid}]) - (util/toast (clj->js {:title "User is not on any page" - :status "warning"}))))) + (if page-uid + ;; TODO: if we support navigating to a block, it should be added here. + (rf/dispatch [:navigate :page {:id page-uid}]) + (util/toast (clj->js {:title "User is not on any page" + :status "warning"}))))) (defn edit-current-user @@ -63,19 +63,19 @@ vals (map user->person) (remove nil?))] - (fn [] - (let [current-user' (user->person @current-user) - current-page-members (others-seq @same-page) - different-page-members (others-seq @diff-page)] - [:> PresenceDetails {:current-user current-user' - :current-page-members current-page-members - :different-page-members different-page-members - :host-address (:url @selected-db) - :handle-copy-host-address copy-host-address-to-clipboard - :handle-press-member #(go-to-user-block @all-users %) - :handle-update-profile #(edit-current-user %) + (fn [] + (let [current-user' (user->person @current-user) + current-page-members (others-seq @same-page) + different-page-members (others-seq @diff-page)] + [:> PresenceDetails {:current-user current-user' + :current-page-members current-page-members + :different-page-members different-page-members + :host-address (:url @selected-db) + :handle-copy-host-address copy-host-address-to-clipboard + :handle-press-member #(go-to-user-block @all-users %) + :handle-update-profile #(edit-current-user %) ;; TODO: show other states when we support them. - :connection-status "connected"}])))) + :connection-status "connected"}])))) ;; inline @@ -85,17 +85,17 @@ (let [users (rf/subscribe [:presence/has-presence (util/embed-uid->original-uid uid)])] (when (seq @users) (into - [:> AvatarGroup {:max 3 - :zIndex 2 - :size "xs" - :position "absolute" - :right "-1.5rem" - :top "0.25rem"} - (->> @users - (map user->person) - (remove nil?) - (map (fn [{:keys [personId] :as person}] - [:> Avatar {:key personId - :bg (:color person) - :name (:username person)}])))])))) + [:> AvatarGroup {:max 3 + :zIndex 2 + :size "xs" + :position "absolute" + :right "-1.5rem" + :top "0.25rem"} + (->> @users + (map user->person) + (remove nil?) + (map (fn [{:keys [personId] :as person}] + [:> Avatar {:key personId + :bg (:color person) + :name (:username person)}])))])))) diff --git a/src/cljs/athens/util.cljs b/src/cljs/athens/util.cljs index 28481df664..7c88491299 100644 --- a/src/cljs/athens/util.cljs +++ b/src/cljs/athens/util.cljs @@ -1,14 +1,14 @@ (ns athens.util (:require - ["/textarea" :as getCaretCoordinates] - ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [createStandaloneToast]] - [athens.config :as config] - [athens.electron.utils :as electron.utils] - [clojure.string :as string] - [cognitect.transit :as tr] - [com.rpl.specter :as s] - [goog.dom :refer [getElement setProperties]]) + ["/textarea" :as getCaretCoordinates] + ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [createStandaloneToast]] + [athens.config :as config] + [athens.electron.utils :as electron.utils] + [clojure.string :as string] + [cognitect.transit :as tr] + [com.rpl.specter :as s] + [goog.dom :refer [getElement setProperties]]) (:require-macros [com.rpl.specter :refer [recursive-path]]) (:import @@ -19,7 +19,6 @@ (def toast (createStandaloneToast (clj->js {:theme theme}))) - ;; Electron ipcMain Channels (def ipcMainChannels diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 0f7db8ede6..989b6e633d 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -1,29 +1,28 @@ (ns athens.views (:require - ["/theme/theme" :refer [theme]] - ["@chakra-ui/react" :refer [ChakraProvider Flex Grid Spinner Center]] - ["@react-aria/overlays" :refer [OverlayProvider]] - [athens.config] - [athens.electron.db-modal :as db-modal] - [athens.electron.utils :as electron.utils] - [athens.style :refer [zoom]] - [athens.subs] - [athens.util :refer [get-os]] - [athens.views.app-toolbar :as app-toolbar] - [athens.views.athena :refer [athena-component]] - [athens.views.devtool :refer [devtool-component]] - [athens.views.help :refer [help-popup]] - [athens.views.left-sidebar :as left-sidebar] - [athens.views.pages.core :as pages] - [athens.views.right-sidebar :as right-sidebar] - [re-frame.core :as rf])) + ["/theme/theme" :refer [theme]] + ["@chakra-ui/react" :refer [ChakraProvider Flex Grid Spinner Center]] + ["@react-aria/overlays" :refer [OverlayProvider]] + [athens.config] + [athens.electron.db-modal :as db-modal] + [athens.electron.utils :as electron.utils] + [athens.style :refer [zoom]] + [athens.subs] + [athens.util :refer [get-os]] + [athens.views.app-toolbar :as app-toolbar] + [athens.views.athena :refer [athena-component]] + [athens.views.devtool :refer [devtool-component]] + [athens.views.help :refer [help-popup]] + [athens.views.left-sidebar :as left-sidebar] + [athens.views.pages.core :as pages] + [athens.views.right-sidebar :as right-sidebar] + [re-frame.core :as rf])) ;; Components - (defn alert [] (let [alert- (rf/subscribe [:alert])] diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 4c68d68f4b..84116c4ce4 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,21 +1,20 @@ (ns athens.views.athena (:require - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] - ["@material-ui/icons/Close" :default Close] - [athens.common.utils :as utils] - [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] - [athens.router :as router] - [athens.subs] - [athens.util :refer [scroll-into-view]] - [clojure.string :as str] - [goog.dom :refer [getElement]] - [goog.events :as events] - [re-frame.core :as rf :refer [subscribe dispatch]] - [reagent.core :as r]) + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] + ["@material-ui/icons/Close" :default Close] + [athens.common.utils :as utils] + [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] + [athens.router :as router] + [athens.subs] + [athens.util :refer [scroll-into-view]] + [clojure.string :as str] + [goog.dom :refer [getElement]] + [goog.events :as events] + [re-frame.core :as rf :refer [subscribe dispatch]] + [reagent.core :as r]) (:import - (goog.events - KeyCodes))) - + (goog.events + KeyCodes))) ;; Utilities @@ -25,12 +24,12 @@ [query txt] (let [query-pattern (re-case-insensitive (str "((?<=" query ")|(?=" query "))"))] (doall - (map-indexed (fn [i part] - (if (re-find query-pattern part) - [:> Text {:class "result-highlight" - :key i} part] - part)) - (str/split txt query-pattern))))) + (map-indexed (fn [i part] + (if (re-find query-pattern part) + [:> Text {:class "result-highlight" + :key i} part] + part)) + (str/split txt query-pattern))))) (defn create-search-handler @@ -43,10 +42,10 @@ (reset! state {:index 0 :query query :results (vec - (concat - [(search-exact-node-title query)] - (search-in-node-title query 20 true) - (search-in-block-content query)))})))) + (concat + [(search-exact-node-title query)] + (search-in-node-title query 20 true) + (search-in-block-content query)))})))) (defn key-down-handler @@ -179,19 +178,18 @@ :overflowY "overlay" :_empty {:display "none"}} (doall - (for [[i x] (map-indexed list recent-items)] - (when x - (let [{:keys [query :node/title :block/string]} x] - [result-el {:key i - :title title - :query query - :preview string - :on-click (fn [e] - (rf/dispatch [:reporting/navigation {:source :athena - :target :page - :pane :main-pane}]) - (router/navigate-page title e))}]))))])])) - + (for [[i x] (map-indexed list recent-items)] + (when x + (let [{:keys [query :node/title :block/string]} x] + [result-el {:key i + :title title + :query query + :preview string + :on-click (fn [e] + (rf/dispatch [:reporting/navigation {:source :athena + :target :page + :pane :main-pane}]) + (router/navigate-page title e))}]))))])])) (defn search-results-el @@ -207,49 +205,49 @@ :overflowY "overlay" :_empty {:display "none"}} (doall - (for [[i x] (map-indexed list results) - :let [block-uid (:block/uid x) - parent (:block/parent x) - title (or (:node/title parent) (:node/title x)) - uid (or (:block/uid parent) (:block/uid x)) - string (:block/string x)]] - (if (nil? x) - ^{:key i} - [result-el {:key i - :title query - :prefix "Create page " - :preview nil - :query query - :active? (= i index) - :on-click (fn [e] - (rf/dispatch [:athena/toggle]) - (rf/dispatch [:right-sidebar/open-page (:node/title x) e]) - (rf/dispatch [:reporting/navigation {:source :athena - :target :page - :pane :right-pane}]))}] - [result-el {:key i - :title title - :query query - :preview string - :active? (= i index) - :on-click (fn [e] - (let [selected-page {:node/title title - :block/uid uid - :block/string string - :query query} - shift? (.-shiftKey e)] - (dispatch [:athena/toggle]) - (dispatch [:athena/update-recent-items selected-page]) - (dispatch [:reporting/navigation {:source :athena - :target (if parent - :block - :page) - :pane (if shift? - :right-pane - :main-pane)}]) - (if parent - (router/navigate-uid block-uid) - (router/navigate-page title e))))}])))]) + (for [[i x] (map-indexed list results) + :let [block-uid (:block/uid x) + parent (:block/parent x) + title (or (:node/title parent) (:node/title x)) + uid (or (:block/uid parent) (:block/uid x)) + string (:block/string x)]] + (if (nil? x) + ^{:key i} + [result-el {:key i + :title query + :prefix "Create page " + :preview nil + :query query + :active? (= i index) + :on-click (fn [e] + (rf/dispatch [:athena/toggle]) + (rf/dispatch [:right-sidebar/open-page (:node/title x) e]) + (rf/dispatch [:reporting/navigation {:source :athena + :target :page + :pane :right-pane}]))}] + [result-el {:key i + :title title + :query query + :preview string + :active? (= i index) + :on-click (fn [e] + (let [selected-page {:node/title title + :block/uid uid + :block/string string + :query query} + shift? (.-shiftKey e)] + (dispatch [:athena/toggle]) + (dispatch [:athena/update-recent-items selected-page]) + (dispatch [:reporting/navigation {:source :athena + :target (if parent + :block + :page) + :pane (if shift? + :right-pane + :main-pane)}]) + (if parent + (router/navigate-uid block-uid) + (router/navigate-page title e))))}])))]) (defn athena-component diff --git a/src/cljs/athens/views/blocks/autocomplete_search.cljs b/src/cljs/athens/views/blocks/autocomplete_search.cljs index 9417cae7ef..76d23bb5b0 100644 --- a/src/cljs/athens/views/blocks/autocomplete_search.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_search.cljs @@ -1,8 +1,8 @@ (ns athens.views.blocks.autocomplete-search (:require - ["@chakra-ui/react" :refer [Portal Text Menu MenuList MenuItem]] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [clojure.string :as string])) + ["@chakra-ui/react" :refer [Portal Text Menu MenuList MenuItem]] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [clojure.string :as string])) (defn inline-item-click @@ -35,11 +35,11 @@ (empty? results)) [:> Text (str "Search for a " (symbol type))] (doall - (for [[i {:keys [node/title block/string block/uid]}] (map-indexed list results)] - [:> MenuItem {:key (str "inline-search-item-" uid) - :id (str "dropdown-item-" i) - :class (when (= i index) "isActive") - ;; if page link, expand to title. otherwise expand to uid for a block ref - :onClick (fn [_] (inline-item-click state (:block/uid block) (or title uid)))} - (or title string)])))]]])))) - + (for [[i {:keys [node/title block/string block/uid]}] (map-indexed list results)] + [:> MenuItem {:key (str "inline-search-item-" uid) + :id (str "dropdown-item-" i) + :class (when (= i index) "isActive") + ;; if page link, expand to title. otherwise expand to uid for a block ref + :onClick (fn [_] (inline-item-click state (:block/uid block) (or title uid)))} + (or title string)])))]]])))) + diff --git a/src/cljs/athens/views/blocks/autocomplete_slash.cljs b/src/cljs/athens/views/blocks/autocomplete_slash.cljs index abb07facfd..c2b36280ee 100644 --- a/src/cljs/athens/views/blocks/autocomplete_slash.cljs +++ b/src/cljs/athens/views/blocks/autocomplete_slash.cljs @@ -25,12 +25,12 @@ :left (str left "px") :top (str (+ top 24) "px")} (doall - (for [[i [text icon _expansion kbd _pos :as item]] (map-indexed list results)] - [:> MenuItem {:key text - :id (str "dropdown-item-" i) - :command kbd - :class (when (= i index) "isActive") - :onClick (fn [_] (slash-item-click state block item))} - [:<> - [(r/adapt-react-class icon)] - text]]))]]]))) \ No newline at end of file + (for [[i [text icon _expansion kbd _pos :as item]] (map-indexed list results)] + [:> MenuItem {:key text + :id (str "dropdown-item-" i) + :command kbd + :class (when (= i index) "isActive") + :onClick (fn [_] (slash-item-click state block item))} + [:<> + [(r/adapt-react-class icon)] + text]]))]]]))) diff --git a/src/cljs/athens/views/blocks/content.cljs b/src/cljs/athens/views/blocks/content.cljs index 7914c03790..ca2ba006cb 100644 --- a/src/cljs/athens/views/blocks/content.cljs +++ b/src/cljs/athens/views/blocks/content.cljs @@ -1,20 +1,20 @@ (ns athens.views.blocks.content (:require - ["@chakra-ui/react" :refer [Box]] - [athens.config :as config] - [athens.db :as db] - [athens.events.selection :as select-events] - [athens.parse-renderer :refer [parse-and-render]] - [athens.subs.selection :as select-subs] - [athens.util :as util] - [athens.views.blocks.internal-representation :as internal-representation] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [clojure.edn :as edn] - [clojure.set :as set] - [clojure.string :as str] - [goog.events :as goog-events] - [komponentit.autosize :as autosize] - [re-frame.core :as rf]) + ["@chakra-ui/react" :refer [Box]] + [athens.config :as config] + [athens.db :as db] + [athens.events.selection :as select-events] + [athens.parse-renderer :refer [parse-and-render]] + [athens.subs.selection :as select-subs] + [athens.util :as util] + [athens.views.blocks.internal-representation :as internal-representation] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [clojure.edn :as edn] + [clojure.set :as set] + [clojure.string :as str] + [goog.events :as goog-events] + [komponentit.autosize :as autosize] + [re-frame.core :as rf]) (:import (goog.events EventType))) @@ -23,87 +23,88 @@ ;; Styles -(def block-inner-content-style {"textarea" {:display "block" - :lineHeight 0 - :appearance "none" - :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :outline "none" - :overflow "hidden" - :padding "0" - :background "var(--block-surface-color)" - :grid-area "main" - :min-height "100%" - :margin "0" - :font-size "inherit" - :border-radius "0.25rem" - :border "0" - :opacity "0" - :font-family "inherit"} - "&:hover textarea:not(.is-editing)" {:lineHeight "2"} - "textarea.is-editing + *" {:opacity "0"} - ".is-editing" {:zIndex 3 - :lineHeight "inherit" - :opacity 1} - "span.text-run" {:pointerEvents "none" - "& > a" {:position "relative" - :zIndex 2 - :pointerEvents "all"}} - "span" {:gridArea "main" - "& > span" {:position "relative" - :zIndex 2}} - "abbr" {:gridArea "main" - :zIndex 4 - "& > span" {:position "relative" - :zIndex 2}} - "code, pre" {:fontFamily "code" - :fontSize "0.85em"} - ".media-16-9" {:height 0 - :width "calc(100% - 0.25rem)" - :zIndex 1 - :transformOrigin "right center" - :transitionDuration "0.2s" - :transitionTimingFunction "ease-in-out" - :transitionProperty "common" - :paddingBottom "56.25%" - :marginBlock "0.25rem" - :marginInlineEnd "0.25rem" - :position "relative"} - "iframe" {:border 0 - :boxShadow "inset 0 0 0 0.125rem" - :position "absolute" - :height "100%" - :width "100%" - :cursor "default" - :top 0 - :right 0 - :left 0 - :bottom 0 - :borderRadius "0.25rem"} - "img" {:borderRadius "0.25rem" - :maxWidth "calc(100% - 0.25rem)"} - "h1" {:fontSize "xl"} - "h2" {:fontSize "lg"} - "h3" {:fontSize "md"} - "h4" {:fontSize "sm"} - "h5" {:fontSize "xs"} - "h6" {:fontSize "xs"} - "blockquote" {:marginInline "0.5em" - :marginBlock "0.125rem" - :paddingBlock "calc(0.5em - 0.125rem - 0.125rem)" - :paddingInline "1.5em" - :borderRadius "0.25em" - :background "background.basement" - :borderInlineStart "1px solid" - :borderColor "separator.divider" - :color "foreground.primary"} - "p" {:paddingBottom "1em" - "&:last-child" {:paddingBottom 0}} - "mark.contents.highlight" {:padding "0 0.2em" - :borderRadius "0.125rem" - :background "highlight"}}) +(def block-inner-content-style + {"textarea" {:display "block" + :lineHeight 0 + :appearance "none" + :cursor "text" + :resize "none" + :transform "translate3d(0,0,0)" + :color "inherit" + :outline "none" + :overflow "hidden" + :padding "0" + :background "var(--block-surface-color)" + :grid-area "main" + :min-height "100%" + :margin "0" + :font-size "inherit" + :border-radius "0.25rem" + :border "0" + :opacity "0" + :font-family "inherit"} + "&:hover textarea:not(.is-editing)" {:lineHeight "2"} + "textarea.is-editing + *" {:opacity "0"} + ".is-editing" {:zIndex 3 + :lineHeight "inherit" + :opacity 1} + "span.text-run" {:pointerEvents "none" + "& > a" {:position "relative" + :zIndex 2 + :pointerEvents "all"}} + "span" {:gridArea "main" + "& > span" {:position "relative" + :zIndex 2}} + "abbr" {:gridArea "main" + :zIndex 4 + "& > span" {:position "relative" + :zIndex 2}} + "code, pre" {:fontFamily "code" + :fontSize "0.85em"} + ".media-16-9" {:height 0 + :width "calc(100% - 0.25rem)" + :zIndex 1 + :transformOrigin "right center" + :transitionDuration "0.2s" + :transitionTimingFunction "ease-in-out" + :transitionProperty "common" + :paddingBottom "56.25%" + :marginBlock "0.25rem" + :marginInlineEnd "0.25rem" + :position "relative"} + "iframe" {:border 0 + :boxShadow "inset 0 0 0 0.125rem" + :position "absolute" + :height "100%" + :width "100%" + :cursor "default" + :top 0 + :right 0 + :left 0 + :bottom 0 + :borderRadius "0.25rem"} + "img" {:borderRadius "0.25rem" + :maxWidth "calc(100% - 0.25rem)"} + "h1" {:fontSize "xl"} + "h2" {:fontSize "lg"} + "h3" {:fontSize "md"} + "h4" {:fontSize "sm"} + "h5" {:fontSize "xs"} + "h6" {:fontSize "xs"} + "blockquote" {:marginInline "0.5em" + :marginBlock "0.125rem" + :paddingBlock "calc(0.5em - 0.125rem - 0.125rem)" + :paddingInline "1.5em" + :borderRadius "0.25em" + :background "background.basement" + :borderInlineStart "1px solid" + :borderColor "separator.divider" + :color "foreground.primary"} + "p" {:paddingBottom "1em" + "&:last-child" {:paddingBottom 0}} + "mark.contents.highlight" {:padding "0 0.2em" + :borderRadius "0.125rem" + :background "highlight"}}) (defn find-selected-items diff --git a/src/cljs/athens/views/blocks/context_menu.cljs b/src/cljs/athens/views/blocks/context_menu.cljs index c833c18b4b..8efca8d9b6 100644 --- a/src/cljs/athens/views/blocks/context_menu.cljs +++ b/src/cljs/athens/views/blocks/context_menu.cljs @@ -1,11 +1,11 @@ (ns athens.views.blocks.context-menu (:require - [athens.db :as db] - [athens.listeners :as listeners] - [athens.subs.selection :as select-subs] - [athens.util :refer [toast]] - [clojure.string :as string] - [re-frame.core :as rf])) + [athens.db :as db] + [athens.listeners :as listeners] + [athens.subs.selection :as select-subs] + [athens.util :refer [toast]] + [clojure.string :as string] + [re-frame.core :as rf])) (defn handle-copy-refs diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index dade4b94f6..be3e38d4d5 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -1,32 +1,32 @@ (ns athens.views.blocks.core (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Block/components/Toggle" :refer [Toggle]] - ["@chakra-ui/react" :refer [VStack Box Button Breadcrumb BreadcrumbItem BreadcrumbLink HStack]] - [athens.common.logging :as log] - [athens.db :as db] - [athens.electron.images :as images] - [athens.electron.utils :as electron.utils] - [athens.events.selection :as select-events] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.self-hosted.presence.views :as presence] - [athens.subs.selection :as select-subs] - [athens.util :as util :refer [mouse-offset vertical-center - ; specter-recursive-path - ]] - [athens.views.blocks.autocomplete-search :as autocomplete-search] - [athens.views.blocks.autocomplete-slash :as autocomplete-slash] - [athens.views.blocks.bullet :refer [bullet-drag-start bullet-drag-end]] - [athens.views.blocks.content :as content] - [athens.views.blocks.context-menu :refer [handle-copy-unformatted handle-copy-refs]] - [athens.views.blocks.drop-area-indicator :as drop-area-indicator] - [athens.views.references :refer [reference-group reference-block]] - ;; [com.rpl.specter :as s] - [goog.functions :as gfns] - [re-frame.core :as rf] - [reagent.core :as r])) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Block/components/Toggle" :refer [Toggle]] + ["@chakra-ui/react" :refer [VStack Box Button Breadcrumb BreadcrumbItem BreadcrumbLink HStack]] + [athens.common.logging :as log] + [athens.db :as db] + [athens.electron.images :as images] + [athens.electron.utils :as electron.utils] + [athens.events.selection :as select-events] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.self-hosted.presence.views :as presence] + [athens.subs.selection :as select-subs] + [athens.util :as util :refer [mouse-offset vertical-center + ;; specter-recursive-path + ]] + [athens.views.blocks.autocomplete-search :as autocomplete-search] + [athens.views.blocks.autocomplete-slash :as autocomplete-slash] + [athens.views.blocks.bullet :refer [bullet-drag-start bullet-drag-end]] + [athens.views.blocks.content :as content] + [athens.views.blocks.context-menu :refer [handle-copy-unformatted handle-copy-refs]] + [athens.views.blocks.drop-area-indicator :as drop-area-indicator] + [athens.views.references :refer [reference-group reference-block]] + ;; [com.rpl.specter :as s] + [goog.functions :as gfns] + [re-frame.core :as rf] + [reagent.core :as r])) ;; Styles @@ -143,8 +143,8 @@ [:> BreadcrumbItem {:key (str "breadcrumb-" uid)} [:> BreadcrumbLink {:onClick #(let [new-B (db/get-block [:block/uid uid]) new-P (concat - (take-while (fn [b] (not= (:block/uid b) uid)) parents) - [breadcrumb-block])] + (take-while (fn [b] (not= (:block/uid b) uid)) parents) + [breadcrumb-block])] (.. % stopPropagation) (swap! state assoc :block new-B :parents new-P :focus? false))} [parse-renderer/parse-and-render (or title string) uid]]]))]] @@ -186,31 +186,31 @@ :borderRadius "sm" :background "background.basement"} (doall - (for [[group-title group] refs] - [reference-group {:title group-title - :key (str "group-" group-title)} - (doall - (for [block' group] - [reference-block {:key (str "ref-" (:block/uid block'))} - [ref-comp block' state]]))]))]))) + (for [[group-title group] refs] + [reference-group {:title group-title + :key (str "group-" group-title)} + (doall + (for [block' group] + [reference-block {:key (str "ref-" (:block/uid block'))} + [ref-comp block' state]]))]))]))) ;; Components (defn block-refs-count-el [count click-fn active?] - [:> Button {:gridArea "refs" - :size "xs" - :ml "1em" - :mt 1 - :mr 1 - :zIndex 10 - :visibility (if (pos? count) "visible" "hidden") - :isActive active? - :onClick (fn [e] - (.. e stopPropagation) - (click-fn e))} - count]) + [:> Button {:gridArea "refs" + :size "xs" + :ml "1em" + :mt 1 + :mr 1 + :zIndex 10 + :visibility (if (pos? count) "visible" "hidden") + :isActive active? + :onClick (fn [e] + (.. e stopPropagation) + (click-fn e))} + count]) (defn block-drag-over @@ -438,15 +438,15 @@ [:div.block-body (when (seq children) [:> Toggle {:isOpen (if (or (and (true? linked-ref) (:linked-ref/open @state)) - (and (false? linked-ref) open)) - true - false) - :onClick (fn [e] - (.. e stopPropagation) - (if (true? linked-ref) - (swap! state update :linked-ref/open not) - (toggle uid (not open))))}]) - [:> Anchor {:isClosedWithChildren (when (and (seq children) + (and (false? linked-ref) open)) + true + false) + :onClick (fn [e] + (.. e stopPropagation) + (if (true? linked-ref) + (swap! state update :linked-ref/open not) + (toggle uid (not open))))}]) + [:> Anchor {:isClosedWithChildren (when (and (seq children) (or (and (true? linked-ref) (not (:linked-ref/open @state))) (and (false? linked-ref) (not open)))) "closed-with-children") @@ -468,7 +468,7 @@ [presence/inline-presence-el uid] - (when (and (> (count _refs) 0) (not= :block-embed? opts)) + (when (and (> (count _refs) 0) (not= :block-embed? opts)) [block-refs-count-el (count _refs) (fn [e] @@ -478,11 +478,11 @@ (:inline-refs/open @state)])] - [autocomplete-search/inline-search-el block state] + [autocomplete-search/inline-search-el block state] [autocomplete-slash/slash-menu-el block state] ;; Inline refs - (when (and (> (count _refs) 0) + (when (and (> (count _refs) 0) (not= :block-embed? opts) (:inline-refs/open @state)) [inline-linked-refs-el state uid]) diff --git a/src/cljs/athens/views/blocks/drop_area_indicator.cljs b/src/cljs/athens/views/blocks/drop_area_indicator.cljs index 26cc09e778..2d9c532a96 100644 --- a/src/cljs/athens/views/blocks/drop_area_indicator.cljs +++ b/src/cljs/athens/views/blocks/drop_area_indicator.cljs @@ -1,6 +1,7 @@ (ns athens.views.blocks.drop-area-indicator (:require - ["@chakra-ui/react" :refer [Box]])) + ["@chakra-ui/react" :refer [Box]])) + (defn drop-area-indicator ([{:keys [placement child?]}] diff --git a/src/cljs/athens/views/blocks/textarea_keydown.cljs b/src/cljs/athens/views/blocks/textarea_keydown.cljs index aa3a43acaa..2b4a99b2ef 100644 --- a/src/cljs/athens/views/blocks/textarea_keydown.cljs +++ b/src/cljs/athens/views/blocks/textarea_keydown.cljs @@ -1,28 +1,28 @@ (ns athens.views.blocks.textarea-keydown (:require - ["@material-ui/icons/DesktopWindows" :default DesktopWindows] - ["@material-ui/icons/Done" :default Done] - ["@material-ui/icons/FlipToFront" :default FlipToFront] - ["@material-ui/icons/Timer" :default Timer] - ["@material-ui/icons/Today" :default Today] - ["@material-ui/icons/ViewDayRounded" :default ViewDayRounded] - ["@material-ui/icons/YouTube" :default YouTube] - [athens.common-db :as common-db] - [athens.common.utils :as common.utils] - [athens.dates :as dates] - [athens.db :as db] - [athens.events.selection :as select-events] - [athens.router :as router] - [athens.subs.selection :as select-subs] - [athens.util :as util :refer [scroll-if-needed get-caret-position shortcut-key? escape-str]] - [athens.views.blocks.internal-representation :as internal-representation] - [clojure.string :refer [replace-first blank? includes? lower-case]] - [goog.dom :refer [getElement]] - [goog.dom.selection :refer [setStart setEnd getText setCursorPosition getEndPoints]] - [goog.events.KeyCodes :refer [isCharacterKey]] - [goog.functions :refer [throttle #_debounce]] - [goog.style :refer [getClientPosition]] - [re-frame.core :as rf :refer [dispatch dispatch-sync subscribe]]) + ["@material-ui/icons/DesktopWindows" :default DesktopWindows] + ["@material-ui/icons/Done" :default Done] + ["@material-ui/icons/FlipToFront" :default FlipToFront] + ["@material-ui/icons/Timer" :default Timer] + ["@material-ui/icons/Today" :default Today] + ["@material-ui/icons/ViewDayRounded" :default ViewDayRounded] + ["@material-ui/icons/YouTube" :default YouTube] + [athens.common-db :as common-db] + [athens.common.utils :as common.utils] + [athens.dates :as dates] + [athens.db :as db] + [athens.events.selection :as select-events] + [athens.router :as router] + [athens.subs.selection :as select-subs] + [athens.util :as util :refer [scroll-if-needed get-caret-position shortcut-key? escape-str]] + [athens.views.blocks.internal-representation :as internal-representation] + [clojure.string :refer [replace-first blank? includes? lower-case]] + [goog.dom :refer [getElement]] + [goog.dom.selection :refer [setStart setEnd getText setCursorPosition getEndPoints]] + [goog.events.KeyCodes :refer [isCharacterKey]] + [goog.functions :refer [throttle #_debounce]] + [goog.style :refer [getClientPosition]] + [re-frame.core :as rf :refer [dispatch dispatch-sync subscribe]]) (:import (goog.events KeyCodes))) @@ -816,7 +816,7 @@ ;; update caret position for search dropdowns and for up/down (when (nil? (:search/type @state)) - + (let [caret-position (get-caret-position (.. e -target)) textarea-position (js->clj (getClientPosition (.. e -target)) :keywordize-keys true) position {:left (+ (:left caret-position) (.. textarea-position -x)) diff --git a/src/cljs/athens/views/devtool.cljs b/src/cljs/athens/views/devtool.cljs index df6bb01e24..41ee5291b3 100644 --- a/src/cljs/athens/views/devtool.cljs +++ b/src/cljs/athens/views/devtool.cljs @@ -1,20 +1,20 @@ (ns athens.views.devtool (:require - ["@chakra-ui/react" :refer [Box Button Table Thead Tbody Th Tr Td Input ButtonGroup]] - ["@material-ui/icons/ChevronLeft" :default ChevronLeft] - ["@material-ui/icons/Clear" :default Clear] - [athens.config :as config] - [athens.db :as db :refer [dsdb]] - [cljs.pprint :as pp] - [clojure.core.protocols :as core-p] - [clojure.datafy :refer [nav datafy]] - [datascript.core :as d] - [datascript.db] - [me.tonsky.persistent-sorted-set] - [re-frame.core :refer [subscribe dispatch]] - [reagent.core :as r] - [reagent.ratom] - [sci.core :as sci]) + ["@chakra-ui/react" :refer [Box Button Table Thead Tbody Th Tr Td Input ButtonGroup]] + ["@material-ui/icons/ChevronLeft" :default ChevronLeft] + ["@material-ui/icons/Clear" :default Clear] + [athens.config :as config] + [athens.db :as db :refer [dsdb]] + [cljs.pprint :as pp] + [clojure.core.protocols :as core-p] + [clojure.datafy :refer [nav datafy]] + [datascript.core :as d] + [datascript.db] + [me.tonsky.persistent-sorted-set] + [re-frame.core :refer [subscribe dispatch]] + [reagent.core :as r] + [reagent.ratom] + [sci.core :as sci]) (:import (goog.events KeyCodes))) @@ -76,20 +76,20 @@ [:> Table {:width "100%"} [:> Thead [:> Tr (for [h headers] - ^{:key h} [:> Th h])]] + ^{:key h} [:> Th h])]] [:> Tbody (doall (for [row (take @limit rows)] ^{:key row} [:> Tr {:on-click #(add-nav! [(first row) - (-> row meta :row-value)])} + (-> row meta :row-value)])} (for [i (range (count row))] (let [cell (get row i)] ^{:key (str row i cell)} [:> Td (if (nil? cell) - "" - (pr-str cell))]))]))]] ; use the edn-viewer here as well? + "" + (pr-str cell))]))]))]] ; use the edn-viewer here as well? (when (< @limit (count rows)) [:> Button {:onClick #(swap! limit + 10) :width "100%"} @@ -233,7 +233,7 @@ (dissoc :viewer))))} [:<> [:> ChevronLeft] [:span (first nav)]]]))) [:h3 (pr-str (type navved-data))] - [:div + [:div [:span "View as "] (for [v applicable-vs] (let [click-fn #(swap! state assoc :viewer v)] @@ -380,7 +380,7 @@ :mr "auto" :isActive (= active-panel :txes)} "Transactions"] - + [devtool-close-el]] [:> Box {:overflowY "auto" :padding "0.5rem"} diff --git a/src/cljs/athens/views/help.cljs b/src/cljs/athens/views/help.cljs index 754ed26938..80fa7027a6 100644 --- a/src/cljs/athens/views/help.cljs +++ b/src/cljs/athens/views/help.cljs @@ -1,10 +1,10 @@ (ns athens.views.help (:require - ["@chakra-ui/react" :refer [Text Heading Box Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] - [athens.util :as util] - [clojure.string :as str] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r])) + ["@chakra-ui/react" :refer [Text Heading Box Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] + [athens.util :as util] + [clojure.string :as str] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Helpers to create the help content @@ -54,11 +54,11 @@ :userSelect "all" :wordBreak "break-word"} (as-> template t - (str/split t #"\$text") - (interleave t (concat faded-texts [nil])) - (map insert-spaces t) - (add-keys t) - (into [:<>] t))])) + (str/split t #"\$text") + (interleave t (concat faded-texts [nil])) + (map insert-spaces t) + (add-keys t) + (into [:<>] t))])) ;; Help content @@ -185,7 +185,7 @@ :color "highlightContrast" :borderRadius "0.1rem" :padding "0 0.125em"} - "Athens"] + "Athens"] :shortcut "mod+h"}]} {:name "Graph" :items [{:description "Open Node in Sidebar" @@ -223,25 +223,26 @@ (str/replace #"minus" "-") (str/replace #"plus" "+"))) keys (as-> shortcut-str s - (str/split s #"\+") - (map key-to-display s))] + (str/split s #"\+") + (map key-to-display s))] [:> Box {:display "flex" :alignItems "center" :gap "0.3rem"} (doall - (for [key keys] - ^{:key key} - [:> Text {:fontFamily "inherit" - :display "inline-flex" - :gap "0.3em" - :textTransform "uppercase" - :fontSize "0.8em" - :paddingInline "0.35em" - :background "background.basement" - :borderRadius "0.25rem" - :fontWeight 600} - key]))])) + (for [key keys] + ^{:key key} + [:> Text {:fontFamily "inherit" + :display "inline-flex" + :gap "0.3em" + :textTransform "uppercase" + :fontSize "0.8em" + :paddingInline "0.35em" + :background "background.basement" + :borderRadius "0.25rem" + :fontWeight 600} + key]))])) + (defn help-section [title & children] @@ -256,9 +257,9 @@ :padding "1rem 1.5rem"} title] (doall - (for [child children] - ^{:key (hash child)} - child))]) + (for [child children] + ^{:key (hash child)} + child))]) (defn help-section-group @@ -276,9 +277,9 @@ title] [:div (doall - (for [child children] - ^{:key (hash child)} - child))]]) + (for [child children] + ^{:key (hash child)} + child))]]) (defn help-item @@ -307,28 +308,28 @@ [] (r/with-let [open? (subscribe [:help/open?]) close #(dispatch [:help/toggle])] - [:> Modal {:isOpen @open? - :onClose close - :scrollBehavior "outside" - :size "full"} - [:> ModalOverlay] - [:> ModalContent {:maxWidth "calc(100% - 8rem)" - :width "max-content" - :my "4rem"} - [:> ModalHeader "Help" - [:> ModalCloseButton]] - [:> ModalBody {:flexDirection "column"} - (doall - (for [section content] - ^{:key section} - [help-section (:name section) - (doall - (for [group (:groups section)] - ^{:key group} - [help-section-group (:name group) - (doall - (for [item (:items group)] - ^{:key item} - [help-item item]))]))]))]]])) + [:> Modal {:isOpen @open? + :onClose close + :scrollBehavior "outside" + :size "full"} + [:> ModalOverlay] + [:> ModalContent {:maxWidth "calc(100% - 8rem)" + :width "max-content" + :my "4rem"} + [:> ModalHeader "Help" + [:> ModalCloseButton]] + [:> ModalBody {:flexDirection "column"} + (doall + (for [section content] + ^{:key section} + [help-section (:name section) + (doall + (for [group (:groups section)] + ^{:key group} + [help-section-group (:name group) + (doall + (for [item (:items group)] + ^{:key item} + [help-item item]))]))]))]]])) diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index 1fabd1339e..3f5766f677 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -1,18 +1,19 @@ (ns athens.views.left-sidebar (:require - ["@chakra-ui/react" :refer [VStack Flex Heading Button Link Flex]] - ["framer-motion" :refer [AnimatePresence motion]] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.util :as util] - [re-frame.core :as rf] - [reagent.core :as r])) + ["@chakra-ui/react" :refer [VStack Flex Heading Button Link Flex]] + ["framer-motion" :refer [AnimatePresence motion]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.util :as util] + [re-frame.core :as rf] + [reagent.core :as r])) ;; Components (def expanded-sidebar-width "clamp(12rem, 25vw, 18rem)") + (defn shortcut-component [_] (let [drag (r/atom nil)] @@ -56,8 +57,8 @@ (.. e preventDefault) (let [offset (util/mouse-offset e) middle-y (util/vertical-center (.. e -target)) - ;; find closest li because sometimes event.target is anchor tag - ;; if nextSibling is null, then target is last li and therefore end of list + ;; find closest li because sometimes event.target is anchor tag + ;; if nextSibling is null, then target is last li and therefore end of list closest-li (.. e -target (closest "li")) next-sibling (.. closest-li -nextElementSibling) last-child? (nil? next-sibling)] @@ -82,6 +83,7 @@ (reset! drag nil))} title]]))) + (defn left-sidebar [] (let [open? (rf/subscribe [:left-sidebar/open]) @@ -91,7 +93,7 @@ (when @open? [:> (.-div motion) {:style {:display "flex" - ;; :paddingTop "7.5rem" + ;; :paddingTop "7.5rem" :flex-direction "column" :height "100%" :alignItems "stretch" @@ -105,7 +107,7 @@ :exit {:width 0 :opacity 0}} - ;; SHORTCUTS + ;; SHORTCUTS [:> VStack {:as "ol" :align "stretch" :width expanded-sidebar-width @@ -122,11 +124,11 @@ :color "foreground.secondary"} "Shortcuts"] (doall - (for [sh shortcuts] - ^{:key (str "left-sidebar-" (second sh))} - [shortcut-component sh]))] + (for [sh shortcuts] + ^{:key (str "left-sidebar-" (second sh))} + [shortcut-component sh]))] - ;; LOGO + BOTTOM BUTTONS + ;; LOGO + BOTTOM BUTTONS [:> Flex {:as "footer" :width expanded-sidebar-width :flexWrap "wrap" diff --git a/src/cljs/athens/views/pages/all_pages.cljs b/src/cljs/athens/views/pages/all_pages.cljs index fddd792410..1a1a76de2e 100644 --- a/src/cljs/athens/views/pages/all_pages.cljs +++ b/src/cljs/athens/views/pages/all_pages.cljs @@ -1,6 +1,6 @@ (ns athens.views.pages.all-pages (:require - ["@chakra-ui/react" :refer [Table Thead Tr Th Tbody Td Button Box]] + ["@chakra-ui/react" :refer [Table Thead Tr Th Tbody Td Button Box]] ["@material-ui/icons/ArrowDropDown" :default ArrowDropDown] ["@material-ui/icons/ArrowDropUp" :default ArrowDropUp] [athens.common-db :as common-db] @@ -94,25 +94,25 @@ [sortable-header :created "Created" "16rem" false {:date? true}]]] [:> Tbody (doall - (for [{:keys [block/uid node/title block/_refs] - modified :edit/time - created :create/time} sorted-pages] - [:> Tr {:key uid} - [:> Td {:overflow "hidden"} - [:> Button {:variant "link" - :color "link" - :display "block" - :maxWidth "100%" - :whiteSpace "nowrap" - :onClick (fn [e] - (let [shift? (.-shiftKey e)] - (rf/dispatch [:reporting/navigation {:source :all-pages - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page title e)))} - title]] - [:> Td {:width "12rem" :whiteSpace "nowrap" :color "foreground.secondary" :isNumeric true} (count _refs)] - [:> Td {:width "16rem" :whiteSpace "nowrap" :color "foreground.secondary"} (dates/date-string modified)] - [:> Td {:width "16rem" :whiteSpace "nowrap" :color "foreground.secondary"} (dates/date-string created)]]))]]])))) + (for [{:keys [block/uid node/title block/_refs] + modified :edit/time + created :create/time} sorted-pages] + [:> Tr {:key uid} + [:> Td {:overflow "hidden"} + [:> Button {:variant "link" + :color "link" + :display "block" + :maxWidth "100%" + :whiteSpace "nowrap" + :onClick (fn [e] + (let [shift? (.-shiftKey e)] + (rf/dispatch [:reporting/navigation {:source :all-pages + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page title e)))} + title]] + [:> Td {:width "12rem" :whiteSpace "nowrap" :color "foreground.secondary" :isNumeric true} (count _refs)] + [:> Td {:width "16rem" :whiteSpace "nowrap" :color "foreground.secondary"} (dates/date-string modified)] + [:> Td {:width "16rem" :whiteSpace "nowrap" :color "foreground.secondary"} (dates/date-string created)]]))]]])))) diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index 8dc5ba8dbf..6b801acc16 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -1,16 +1,16 @@ (ns athens.views.pages.block-page (:require - ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.views.blocks.core :as blocks] - [athens.views.pages.header :refer [page-header editable-title-container]] - [athens.views.pages.node-page :as node-page] - [athens.views.references :refer [reference-group reference-block]] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r])) + ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.views.blocks.core :as blocks] + [athens.views.pages.header :refer [page-header editable-title-container]] + [athens.views.pages.node-page :as node-page] + [athens.views.references :refer [reference-group reference-block]] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Helpers @@ -52,15 +52,15 @@ (let [linked-refs (reactive/get-reactive-linked-references id)] (when (seq linked-refs) [:> Accordion - [:> AccordionItem - [:h2 - [:> AccordionButton - [:> AccordionIcon "LinkedReferences"]]] - [:> AccordionPanel {:px 0} - [:> VStack {:spacing 6 - :pl 6 - :align "stretch"} - (doall + [:> AccordionItem + [:h2 + [:> AccordionButton + [:> AccordionIcon "LinkedReferences"]]] + [:> AccordionPanel {:px 0} + [:> VStack {:spacing 6 + :pl 6 + :align "stretch"} + (doall (for [[group-title group] linked-refs] [reference-group {:key (str "group-" group-title) :title group-title @@ -74,9 +74,9 @@ :main-pane)}]) (router/navigate-page parsed-title)))} (doall - (for [block group] - [reference-block {:key (str "ref-" (:block/uid block))} - [node-page/ref-comp block]]))]))]]]]))) + (for [block group] + [reference-block {:key (str "ref-" (:block/uid block))} + [node-page/ref-comp block]]))]))]]]]))) (defn parents-el @@ -84,12 +84,12 @@ (let [parents (reactive/get-reactive-parents-recursively id)] [:> Breadcrumb (doall - (for [{:keys [node/title block/string] breadcrumb-uid :block/uid} parents] - ^{:key breadcrumb-uid} - [:> BreadcrumbItem {:key (str "breadcrumb-" breadcrumb-uid)} - [:> BreadcrumbLink {:onClick #(breadcrumb-handle-click % uid breadcrumb-uid)} - [:span {:style {:pointer-events "none"}} - [parse-renderer/parse-and-render (or title string)]]]]))])) + (for [{:keys [node/title block/string] breadcrumb-uid :block/uid} parents] + ^{:key breadcrumb-uid} + [:> BreadcrumbItem {:key (str "breadcrumb-" breadcrumb-uid)} + [:> BreadcrumbLink {:onClick #(breadcrumb-handle-click % uid breadcrumb-uid)} + [:span {:style {:pointer-events "none"}} + [parse-renderer/parse-and-render (or title string)]]]]))])) (defn block-page-el @@ -107,36 +107,36 @@ ;; Header [page-header - [editable-title-container {:onClick (fn [e] - (.. e preventDefault) - (if (.. e -shiftKey) - (do - (rf/dispatch [:reporting/navigation {:source :block-page - :target :block - :pane :right-pane}]) - (router/navigate-uid uid e)) - - (dispatch [:editing/uid uid])))} - [:<> - [autosize/textarea - {:id (str "editable-uid-" uid) - :value (:string/local @state) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :auto-focus true - :on-blur (fn [_] (persist-textarea-string @state uid)) - :on-key-down (fn [e] (node-page/handle-key-down e uid state nil)) - :on-change (fn [e] (block-page-change e uid state))}] - (if (clojure.string/blank? (:string/local @state)) - [:wbr] - [:span [parse-renderer/parse-and-render (:string/local @state) uid]])]]] + [editable-title-container {:onClick (fn [e] + (.. e preventDefault) + (if (.. e -shiftKey) + (do + (rf/dispatch [:reporting/navigation {:source :block-page + :target :block + :pane :right-pane}]) + (router/navigate-uid uid e)) + + (dispatch [:editing/uid uid])))} + [:<> + [autosize/textarea + {:id (str "editable-uid-" uid) + :value (:string/local @state) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :auto-focus true + :on-blur (fn [_] (persist-textarea-string @state uid)) + :on-key-down (fn [e] (node-page/handle-key-down e uid state nil)) + :on-change (fn [e] (block-page-change e uid state))}] + (if (clojure.string/blank? (:string/local @state)) + [:wbr] + [:span [parse-renderer/parse-and-render (:string/local @state) uid]])]]] ;; Children - [:div (for [child children] - (let [{:keys [db/id]} child] - ^{:key id} [blocks/block-el child]))] + [:div (for [child children] + (let [{:keys [db/id]} child] + ^{:key id} [blocks/block-el child]))] ;; Refs - [linked-refs-el id]])))) + [linked-refs-el id]])))) (defn page diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs index 2a16c222df..984db5ec7d 100644 --- a/src/cljs/athens/views/pages/core.cljs +++ b/src/cljs/athens/views/pages/core.cljs @@ -1,15 +1,14 @@ (ns athens.views.pages.core (:require - ["@chakra-ui/react" :refer [Box]] - [athens.util :refer [toast]] - [athens.views.hoc.perf-mon :as perf-mon] - [athens.views.pages.all-pages :as all-pages] - [athens.views.pages.daily-notes :as daily-notes] - [athens.views.pages.graph :as graph] - [athens.views.pages.page :as page] - [athens.views.pages.settings :as settings] - [re-frame.core :as rf])) - + ["@chakra-ui/react" :refer [Box]] + [athens.util :refer [toast]] + [athens.views.hoc.perf-mon :as perf-mon] + [athens.views.pages.all-pages :as all-pages] + [athens.views.pages.daily-notes :as daily-notes] + [athens.views.pages.graph :as graph] + [athens.views.pages.page :as page] + [athens.views.pages.settings :as settings] + [re-frame.core :as rf])) ;; View @@ -37,7 +36,7 @@ black calc(100vh - 5rem), #000000f0 calc(100vh - 4rem), #00000088 100vh)" - "&:before" {:content "''" + "&:before" {:content "''" :position "fixed" :zIndex "-1" :inset 0 diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index 7b7cd39e8d..6f1f3142ff 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -1,11 +1,11 @@ (ns athens.views.pages.daily-notes (:require - ["@chakra-ui/react" :refer [Box VStack]] - [athens.dates :as dates] - [athens.reactive :as reactive] - [athens.views.pages.header :refer [title-container]] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]])) + ["@chakra-ui/react" :refer [Box VStack]] + [athens.dates :as dates] + [athens.reactive :as reactive] + [athens.views.pages.header :refer [title-container]] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]])) (defn reactive-pull-many @@ -17,25 +17,24 @@ (keep #(reactive/get-reactive-block-document [:block/uid %]) ids)) - (defn daily-notes-page ([props children] - (let [{:keys [real?]} props] - [:> Box {:class "node-page daily-notes" - :boxShadow "page", - :bg "background.floor" - :alignSelf "stretch" - :justifySelf "stretch" - :opacity (if real? 1 0.5) - :px {:sm 6 :md 12} - :py {:sm 6 :md 12} - :borderWidth "1px" - :borderStyle "solid" - :borderColor "separator.divider" - :transitionDuration "0s" - :borderRadius "0.5rem" - :minHeight "calc(100vh - 10rem)"} - children]))) + (let [{:keys [real?]} props] + [:> Box {:class "node-page daily-notes" + :boxShadow "page", + :bg "background.floor" + :alignSelf "stretch" + :justifySelf "stretch" + :opacity (if real? 1 0.5) + :px {:sm 6 :md 12} + :py {:sm 6 :md 12} + :borderWidth "1px" + :borderStyle "solid" + :borderColor "separator.divider" + :transitionDuration "0s" + :borderRadius "0.5rem" + :minHeight "calc(100vh - 10rem)"} + children]))) ;; Components @@ -58,9 +57,9 @@ :flex "1 1 100%" :flexDirection "column"} (doall - (for [{:keys [block/uid]} notes] - [daily-notes-page {:key uid - :real? true} - [node-page/page [:block/uid uid]]])) + (for [{:keys [block/uid]} notes] + [daily-notes-page {:key uid + :real? true} + [node-page/page [:block/uid uid]]])) [daily-notes-page {:real? false} [title-container "Earlier"]]]))))) diff --git a/src/cljs/athens/views/pages/graph.cljs b/src/cljs/athens/views/pages/graph.cljs index 565d23baaf..f76ff725ff 100644 --- a/src/cljs/athens/views/pages/graph.cljs +++ b/src/cljs/athens/views/pages/graph.cljs @@ -21,18 +21,19 @@ [reagent.core :as r] [reagent.dom :as dom])) + (def THEME-DARK {:graph-node-normal "hsla(0, 0%, 100%, 0.57)" :graph-node-hlt "#498eda" :graph-link-normal "#ffffff11"}) + (def THEME-LIGHT {:graph-node-normal "#909090" :graph-node-hlt "#0075E1" :graph-link-normal "#cfcfcf"}) - ;; all graph refs(react refs) reside in this atom ;; saving this to re-frame db is not ideal because of serialization ;; and objects losing their refs @@ -54,28 +55,28 @@ (rf/reg-sub - :graph/conf - (fn [db _] - (-> db :athens/persist :graph-conf))) + :graph/conf + (fn [db _] + (-> db :athens/persist :graph-conf))) (rf/reg-event-fx - :graph/set-conf - (fn [{:keys [db]} [_ k v]] - {:db (update-in db [:athens/persist :graph-conf] #(assoc % k v)) - :dispatch [:posthog/report-feature :graph]})) + :graph/set-conf + (fn [{:keys [db]} [_ k v]] + {:db (update-in db [:athens/persist :graph-conf] #(assoc % k v)) + :dispatch [:posthog/report-feature :graph]})) (rf/reg-sub - :graph/ref - (fn [db [_ key]] - (get-in db [:graph-ref key]))) + :graph/ref + (fn [db [_ key]] + (get-in db [:graph-ref key]))) (rf/reg-event-db - :graph/set-graph-ref - (fn [db [_ key val]] - (assoc-in db [:graph-ref key] val))) + :graph/set-graph-ref + (fn [db [_ key val]] + (assoc-in db [:graph-ref key] val))) ;; ------------------------------------------------------------------- @@ -178,20 +179,19 @@ heading] [:> AccordionPanel (doall - (for [{:keys [key comp label onChange no-simulation-reheat? props class]} controls] - ^{:key key} - [:div {:class class} label - [comp - (merge - props - {:value (key graph-conf) - :color "primary" - :onChange (fn [_ n-val] - (and onChange (onChange n-val)) - (rf/dispatch [:graph/set-conf key n-val]) - (when-not no-simulation-reheat? - (.d3ReheatSimulation graph-ref)))})]]))]])) - + (for [{:keys [key comp label onChange no-simulation-reheat? props class]} controls] + ^{:key key} + [:div {:class class} label + [comp + (merge + props + {:value (key graph-conf) + :color "primary" + :onChange (fn [_ n-val] + (and onChange (onChange n-val)) + (rf/dispatch [:graph/set-conf key n-val]) + (when-not no-simulation-reheat? + (.d3ReheatSimulation graph-ref)))})]]))]])) (defn graph-controls @@ -273,13 +273,13 @@ :top "4rem" :right 0} (doall - (for [{:keys [heading] :as section} (remove nil? [(when-not local-node-eid - node-section) - force-section - (when local-node-eid - local-section)])] - ^{:key heading} - [expansion-panel section local-node-eid]))])))) + (for [{:keys [heading] :as section} (remove nil? [(when-not local-node-eid + node-section) + force-section + (when local-node-eid + local-section)])] + ^{:key heading} + [expansion-panel section local-node-eid]))])))) (defn graph-root @@ -292,167 +292,167 @@ (let [highlight-nodes (r/atom #{}) highlight-links (r/atom #{}) dimensions (r/atom {})] - (r/create-class - {:component-did-mount - (fn [this] - (let [dom-node (dom/dom-node this) - graph-conf @(subscribe [:graph/conf]) - graph-ref (get @graph-ref-map (or local-node-eid :global))] + (r/create-class + {:component-did-mount + (fn [this] + (let [dom-node (dom/dom-node this) + graph-conf @(subscribe [:graph/conf]) + graph-ref (get @graph-ref-map (or local-node-eid :global))] ;; set canvas dimensions - (swap! dimensions assoc :width (-> dom-node (.. (closest "#app")) - .-parentNode .-clientWidth)) - (swap! dimensions assoc :height (-> dom-node (.. (closest "#app")) - .-parentNode .-clientHeight)) + (swap! dimensions assoc :width (-> dom-node (.. (closest "#app")) + .-parentNode .-clientWidth)) + (swap! dimensions assoc :height (-> dom-node (.. (closest "#app")) + .-parentNode .-clientHeight)) ;; set init forces for graph - (when graph-ref - (.. (.. graph-ref (d3Force "charge")) - (distanceMax (/ (min (:width @dimensions) - (:height @dimensions)) - 2))) - (let [c-force (.. graph-ref (d3Force "center"))] - (c-force (/ (:width @dimensions) 2) (/ (:height @dimensions) 2))) - - (.. (.. graph-ref (d3Force "charge")) (strength (:charge-strength graph-conf))) - (.. (.. graph-ref (d3Force "link")) (distance (:link-distance graph-conf))) - (.d3ReheatSimulation graph-ref)))) - - :component-will-unmount - (fn [_this] - (swap! graph-ref-map assoc (or local-node-eid :global) nil)) - - :reagent-render - (fn [local-node-eid] - (let [dark? @(rf/subscribe [:theme/dark]) - graph-conf @(subscribe [:graph/conf]) - all-links (build-links) - all-nodes-with-links (->> all-links (mapcat #(vals %)) set) - linked-nodes-without-daily-notes (->> all-links - (remove (fn [link] - (or (dates/is-daily-note (get link "source-uid")) - (dates/is-daily-note (get link "target-uid"))))) - (mapcat #(vals %)) - set) - nodes (cond->> (if local-node-eid - (->> (n-level-linked all-links local-node-eid (:local-depth graph-conf)) - (d/q '[:find ?e ?u ?t (count ?r) - :in $ [?e ...] - :where - [?e :node/title ?t] - [?e :block/uid ?u] - [?r :block/refs ?e]] - @db/dsdb) - (map (fn [[e u t _val]] - {"id" e - "uid" u - "label" t - "val" (if (= e local-node-eid) 8 1)})) - (remove (fn [node-obj] - (nil? (get node-obj "uid")))) - doall) - (build-nodes)) - - (not (:daily-notes? graph-conf)) - (remove (fn [node] - (dates/is-daily-note (get node "uid")))) - - (not (:orphans? graph-conf)) - (filter (fn [node] - (contains? all-nodes-with-links (get node "id")))) - - (and (not (:daily-notes? graph-conf)) + (when graph-ref + (.. (.. graph-ref (d3Force "charge")) + (distanceMax (/ (min (:width @dimensions) + (:height @dimensions)) + 2))) + (let [c-force (.. graph-ref (d3Force "center"))] + (c-force (/ (:width @dimensions) 2) (/ (:height @dimensions) 2))) + + (.. (.. graph-ref (d3Force "charge")) (strength (:charge-strength graph-conf))) + (.. (.. graph-ref (d3Force "link")) (distance (:link-distance graph-conf))) + (.d3ReheatSimulation graph-ref)))) + + :component-will-unmount + (fn [_this] + (swap! graph-ref-map assoc (or local-node-eid :global) nil)) + + :reagent-render + (fn [local-node-eid] + (let [dark? @(rf/subscribe [:theme/dark]) + graph-conf @(subscribe [:graph/conf]) + all-links (build-links) + all-nodes-with-links (->> all-links (mapcat #(vals %)) set) + linked-nodes-without-daily-notes (->> all-links + (remove (fn [link] + (or (dates/is-daily-note (get link "source-uid")) + (dates/is-daily-note (get link "target-uid"))))) + (mapcat #(vals %)) + set) + nodes (cond->> (if local-node-eid + (->> (n-level-linked all-links local-node-eid (:local-depth graph-conf)) + (d/q '[:find ?e ?u ?t (count ?r) + :in $ [?e ...] + :where + [?e :node/title ?t] + [?e :block/uid ?u] + [?r :block/refs ?e]] + @db/dsdb) + (map (fn [[e u t _val]] + {"id" e + "uid" u + "label" t + "val" (if (= e local-node-eid) 8 1)})) + (remove (fn [node-obj] + (nil? (get node-obj "uid")))) + doall) + (build-nodes)) + + (not (:daily-notes? graph-conf)) + (remove (fn [node] + (dates/is-daily-note (get node "uid")))) + + (not (:orphans? graph-conf)) + (filter (fn [node] + (contains? all-nodes-with-links (get node "id")))) + + (and (not (:daily-notes? graph-conf)) + (not (:orphans? graph-conf))) + (filter (fn [node] + (contains? linked-nodes-without-daily-notes (get node "id"))))) + + filtered-nodes-set (->> nodes (map #(get % "id")) set) + + links (cond->> all-links + + (or local-node-eid + (not (:daily-notes? graph-conf)) (not (:orphans? graph-conf))) - (filter (fn [node] - (contains? linked-nodes-without-daily-notes (get node "id"))))) - - filtered-nodes-set (->> nodes (map #(get % "id")) set) - - links (cond->> all-links - - (or local-node-eid - (not (:daily-notes? graph-conf)) - (not (:orphans? graph-conf))) - (filter (fn [link-obj] - (and (contains? filtered-nodes-set (get link-obj "source")) - (contains? filtered-nodes-set (get link-obj "target"))))) - - (and local-node-eid - (:root-links-only? graph-conf) - (= (:local-depth graph-conf) 1)) - (filter (fn [link-obj] - (or (= (get link-obj "source") local-node-eid) - (= (get link-obj "target") local-node-eid)))) - - true - (filter (fn [link-obj] - (or (contains? filtered-nodes-set (get link-obj "source")) - (contains? filtered-nodes-set (get link-obj "target")))))) - - theme (if dark? - THEME-DARK - THEME-LIGHT)] - [:> ForceGraph2D - {:graphData {:nodes nodes - :links links} + (filter (fn [link-obj] + (and (contains? filtered-nodes-set (get link-obj "source")) + (contains? filtered-nodes-set (get link-obj "target"))))) + + (and local-node-eid + (:root-links-only? graph-conf) + (= (:local-depth graph-conf) 1)) + (filter (fn [link-obj] + (or (= (get link-obj "source") local-node-eid) + (= (get link-obj "target") local-node-eid)))) + + true + (filter (fn [link-obj] + (or (contains? filtered-nodes-set (get link-obj "source")) + (contains? filtered-nodes-set (get link-obj "target")))))) + + theme (if dark? + THEME-DARK + THEME-LIGHT)] + [:> ForceGraph2D + {:graphData {:nodes nodes + :links links} ;; example data - #_{:nodes [{"id" "foo", "name" "name1", "val" 1} + #_{:nodes [{"id" "foo", "name" "name1", "val" 1} {"id" "bar", "name" "name2", "val" 10}] :links [{"source" "foo", "target" "bar"}]} - :width (:width @dimensions) - :height (:height @dimensions) - :ref #(swap! graph-ref-map assoc (or local-node-eid :global) %) + :width (:width @dimensions) + :height (:height @dimensions) + :ref #(swap! graph-ref-map assoc (or local-node-eid :global) %) ;; link - :linkColor (fn [] (:graph-link-normal theme)) + :linkColor (fn [] (:graph-link-normal theme)) ;; node - :nodeCanvasObject (fn [^js node ^js ctx global-scale] - (let [label (.. node -label) - val (.. node -val) - node-id (.. node -id) - x (.. node -x) - y (.. node -y) - scale-factor 3 - font-size (/ 10 global-scale) - text-width (.. ctx (measureText label) -width) - radius (max 1.3 (-> (js/Math.sqrt val) - (/ global-scale) - (* scale-factor))) - highlighted? (contains? @highlight-nodes node-id) - local-root-node? (and local-node-eid node-id (= local-node-eid node-id))] + :nodeCanvasObject (fn [^js node ^js ctx global-scale] + (let [label (.. node -label) + val (.. node -val) + node-id (.. node -id) + x (.. node -x) + y (.. node -y) + scale-factor 3 + font-size (/ 10 global-scale) + text-width (.. ctx (measureText label) -width) + radius (max 1.3 (-> (js/Math.sqrt val) + (/ global-scale) + (* scale-factor))) + highlighted? (contains? @highlight-nodes node-id) + local-root-node? (and local-node-eid node-id (= local-node-eid node-id))] ;; node color - (set! (.-fillStyle ctx) - (cond - local-root-node? (:graph-node-hlt theme) - (and highlighted? (not local-node-eid)) (:graph-node-hlt theme) - :else (:graph-node-normal theme))) + (set! (.-fillStyle ctx) + (cond + local-root-node? (:graph-node-hlt theme) + (and highlighted? (not local-node-eid)) (:graph-node-hlt theme) + :else (:graph-node-normal theme))) ;; text - (when (> global-scale 1.75) - (set! (.-font ctx) (str (when (and highlighted? (not local-node-eid)) - "bold ") - font-size "px IBM Plex Sans, Sans-Serif")) - (.fillText ctx label - (- x (/ text-width 2)) - (+ y radius font-size))) - - (.beginPath ctx) + (when (> global-scale 1.75) + (set! (.-font ctx) (str (when (and highlighted? (not local-node-eid)) + "bold ") + font-size "px IBM Plex Sans, Sans-Serif")) + (.fillText ctx label + (- x (/ text-width 2)) + (+ y radius font-size))) + + (.beginPath ctx) ;; https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc - (.arc ctx x y radius 0 (* js/Math.PI 2)) - (.fill ctx))) + (.arc ctx x y radius 0 (* js/Math.PI 2)) + (.fill ctx))) ;; node actions - :onNodeClick (fn [^js node ^js event] - (let [shift? (.-shiftKey event)] - (rf/dispatch [:reporting/navigation {:source :graph - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page (.. node -label) event))) - :onNodeHover (fn [^js node] - (let [_ (reset! highlight-nodes #{}) - _ (reset! highlight-links #{}) - graph-conf @(rf/subscribe [:graph/conf])] - (when-let [node-id (some-> node (.. -id))] - (reset! highlight-nodes (n-level-linked all-links node-id (:hlt-link-levels graph-conf))))))}]))})))) + :onNodeClick (fn [^js node ^js event] + (let [shift? (.-shiftKey event)] + (rf/dispatch [:reporting/navigation {:source :graph + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page (.. node -label) event))) + :onNodeHover (fn [^js node] + (let [_ (reset! highlight-nodes #{}) + _ (reset! highlight-links #{}) + graph-conf @(rf/subscribe [:graph/conf])] + (when-let [node-id (some-> node (.. -id))] + (reset! highlight-nodes (n-level-linked all-links node-id (:hlt-link-levels graph-conf))))))}]))})))) (defn page diff --git a/src/cljs/athens/views/pages/header.cljs b/src/cljs/athens/views/pages/header.cljs index b51ffac0fa..c3d241d87f 100644 --- a/src/cljs/athens/views/pages/header.cljs +++ b/src/cljs/athens/views/pages/header.cljs @@ -1,6 +1,6 @@ (ns athens.views.pages.header (:require - ["@chakra-ui/react" :refer [Box]])) + ["@chakra-ui/react" :refer [Box]])) (def title-style-props @@ -16,10 +16,10 @@ (defn page-header ([_ children] - [:> Box {:as "header" - :class "page-header" - :position "relative"} - children])) + [:> Box {:as "header" + :class "page-header" + :position "relative"} + children])) (defn title-container @@ -32,35 +32,35 @@ ([props children] (let [{:keys [_]} props] [:> Box (merge - title-style-props - {:as "header" - :class "page-header" - :sx {"textarea" {:appearance "none" - :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :fontWeight "inherit" - :padding "0" - :letterSpacing "inherit" - :width "100%" - :minHeight "100%" - :caretColor "link" - :background "transparent" - :margin "0" - :fontSize "inherit" - :lineHeight "inherit" - :borderRadius "0.25rem" - :transition "opacity 0.15s ease" - :border "0" - :fontFamily "inherit" - :visibility "hidden" - :position "absolute"} - {"textarea ::WebkitScrollbar" {:display "none"}} - {".is-editing textarea:focus" {:outline "none" - :visibility "visible" - :position "relative"}} - "abbr" {:z-index 4} - ".is-editing span" {:visibility "hidden" - :position "absolute"}}}) + title-style-props + {:as "header" + :class "page-header" + :sx {"textarea" {:appearance "none" + :cursor "text" + :resize "none" + :transform "translate3d(0,0,0)" + :color "inherit" + :fontWeight "inherit" + :padding "0" + :letterSpacing "inherit" + :width "100%" + :minHeight "100%" + :caretColor "link" + :background "transparent" + :margin "0" + :fontSize "inherit" + :lineHeight "inherit" + :borderRadius "0.25rem" + :transition "opacity 0.15s ease" + :border "0" + :fontFamily "inherit" + :visibility "hidden" + :position "absolute"} + {"textarea ::WebkitScrollbar" {:display "none"}} + {".is-editing textarea:focus" {:outline "none" + :visibility "visible" + :position "relative"}} + "abbr" {:z-index 4} + ".is-editing span" {:visibility "hidden" + :position "absolute"}}}) children]))) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 8d76e6fe8c..0730df8db2 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -1,35 +1,35 @@ (ns athens.views.pages.node-page (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Dialog/Dialog" :refer [Dialog]] - ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] - ["@material-ui/icons/Bookmark" :default Bookmark] - ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] - ["@material-ui/icons/BubbleChart" :default BubbleChart] - ["@material-ui/icons/Delete" :default Delete] - ["@material-ui/icons/MoreHoriz" :default MoreHoriz] - [athens.common-db :as common-db] - [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] - [athens.common.utils :as utils] - [athens.dates :as dates] - [athens.db :as db :refer [get-unlinked-references]] - [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] - [athens.views.blocks.core :as blocks] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.hoc.perf-mon :as perf-mon] - [athens.views.pages.header :refer [page-header editable-title-container]] - [athens.views.references :refer [reference-group reference-block]] - [clojure.string :as str] - [datascript.core :as d] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r]) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Dialog/Dialog" :refer [Dialog]] + ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] + ["@material-ui/icons/Bookmark" :default Bookmark] + ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] + ["@material-ui/icons/BubbleChart" :default BubbleChart] + ["@material-ui/icons/Delete" :default Delete] + ["@material-ui/icons/MoreHoriz" :default MoreHoriz] + [athens.common-db :as common-db] + [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] + [athens.common.utils :as utils] + [athens.dates :as dates] + [athens.db :as db :refer [get-unlinked-references]] + [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] + [athens.views.blocks.core :as blocks] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [athens.views.hoc.perf-mon :as perf-mon] + [athens.views.pages.header :refer [page-header editable-title-container]] + [athens.views.references :refer [reference-group reference-block]] + [clojure.string :as str] + [datascript.core :as d] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r]) (:import - (goog.events - KeyCodes))) + (goog.events + KeyCodes))) ;; Helpers @@ -239,17 +239,17 @@ [:span "Show Local Graph"]]] [:> MenuDivider] [:> MenuItem {:onClick (fn [] - ;; if page being deleted is in right sidebar, remove from right sidebar + ;; if page being deleted is in right sidebar, remove from right sidebar (when (contains? @(subscribe [:right-sidebar/items]) uid) (dispatch [:right-sidebar/close-item uid])) - ;; if page being deleted is open, navigate to all pages + ;; if page being deleted is open, navigate to all pages (when (or (= @(subscribe [:current-route/page-title]) title) (= @(subscribe [:current-route/uid]) uid)) (rf/dispatch [:reporting/navigation {:source :page-title-delete :target :all-pages :pane :main-pane}]) (router/navigate :pages)) - ;; if daily note, delete page and remove from daily notes, otherwise just delete page + ;; if daily note, delete page and remove from daily notes, otherwise just delete page (if daily-note? (dispatch [:daily-note/delete uid title]) (dispatch [:page/delete title])))} @@ -271,13 +271,13 @@ [:<> [:> Breadcrumb {:fontSize "0.7em" :pl 6} (doall - (for [{:keys [node/title block/string block/uid]} parents] - [:> BreadcrumbItem {:key (str "breadcrumb-" uid)} - [:> BreadcrumbLink - {:onClick #(let [new-B (db/get-block [:block/uid uid]) - new-P (drop-last parents)] - (swap! state assoc :block new-B :parents new-P))} - [parse-and-render (or title string) uid]]]))] + (for [{:keys [node/title block/string block/uid]} parents] + [:> BreadcrumbItem {:key (str "breadcrumb-" uid)} + [:> BreadcrumbLink + {:onClick #(let [new-B (db/get-block [:block/uid uid]) + new-P (drop-last parents)] + (swap! state assoc :block new-B :parents new-P))} + [parse-and-render (or title string) uid]]]))] [:> Box {:class "block-embed"} [blocks/block-el (recursively-modify-block-for-embed block embed-id) @@ -308,23 +308,22 @@ :pl 9 :align "stretch"} (doall - (for [[group-title group] linked-refs] - [reference-group {:key (str "group-" group-title) - :title group-title - :on-click-title (fn [e] - (let [shift? (.-shiftKey e) - parsed-title (parse-renderer/parse-title group-title)] - (rf/dispatch [:reporting/navigation {:source :main-page-linked-refs ; NOTE: this might be also used in right-pane situation - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))} - (doall - (for [block group] - [reference-block {:key (str "ref-" (:block/uid block))} - [ref-comp block]]))]))]]]]))) - + (for [[group-title group] linked-refs] + [reference-group {:key (str "group-" group-title) + :title group-title + :on-click-title (fn [e] + (let [shift? (.-shiftKey e) + parsed-title (parse-renderer/parse-title group-title)] + (rf/dispatch [:reporting/navigation {:source :main-page-linked-refs ; NOTE: this might be also used in right-pane situation + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))} + (doall + (for [block group] + [reference-block {:key (str "ref-" (:block/uid block))} + [ref-comp block]]))]))]]]]))) (defn unlinked-ref-el @@ -367,40 +366,39 @@ :pl 1 :align "stretch"} (doall - (for [[[group-title] group] @unlinked-refs] - [reference-group - {:title group-title - :on-click-title (fn [e] - (let [shift? (.-shiftKey e) - parsed-title (parse-renderer/parse-title group-title)] - (rf/dispatch [:reporting/navigation {:source :main-unlinked-refs ; NOTE: this isn't always `:main-unlinked-refs` it can also be `:right-pane-unlinked-refs` - :target :page - :pane (if shift? - :right-pane - :main-pane)}]) - (router/navigate-page parsed-title e)))} - (doall - (for [block group] - [reference-block - {:key (str "ref-" (:block/uid block)) - :actions (when unlinked? - [:> Button {:marginTop "1.5em" - :size "xs" - :flex "0 0" - :float "right" - :variant "link" - :onClick (fn [] - (let [hm (into (hash-map) @unlinked-refs) - new-unlinked-refs (->> (update-in hm [group-title] #(filter (fn [{:keys [block/uid]}] - (= uid (:block/uid block))) - %)) - seq)] - ;; ctrl-z doesn't work though, because Unlinked Refs aren't reactive to datascript. - (reset! unlinked-refs new-unlinked-refs) - (dispatch [:unlinked-references/link block title])))} - "Link"])} - [ref-comp block]]))]))]]]]))) - + (for [[[group-title] group] @unlinked-refs] + [reference-group + {:title group-title + :on-click-title (fn [e] + (let [shift? (.-shiftKey e) + parsed-title (parse-renderer/parse-title group-title)] + (rf/dispatch [:reporting/navigation {:source :main-unlinked-refs ; NOTE: this isn't always `:main-unlinked-refs` it can also be `:right-pane-unlinked-refs` + :target :page + :pane (if shift? + :right-pane + :main-pane)}]) + (router/navigate-page parsed-title e)))} + (doall + (for [block group] + [reference-block + {:key (str "ref-" (:block/uid block)) + :actions (when unlinked? + [:> Button {:marginTop "1.5em" + :size "xs" + :flex "0 0" + :float "right" + :variant "link" + :onClick (fn [] + (let [hm (into (hash-map) @unlinked-refs) + new-unlinked-refs (->> (update-in hm [group-title] #(filter (fn [{:keys [block/uid]}] + (= uid (:block/uid block))) + %)) + seq)] + ;; ctrl-z doesn't work though, because Unlinked Refs aren't reactive to datascript. + (reset! unlinked-refs new-unlinked-refs) + (dispatch [:unlinked-references/link block title])))} + "Link"])} + [ref-comp block]]))]))]]]]))) ;; TODO: where to put page-level link filters? diff --git a/src/cljs/athens/views/pages/settings.cljs b/src/cljs/athens/views/pages/settings.cljs index 09ee22e656..9d2d454587 100644 --- a/src/cljs/athens/views/pages/settings.cljs +++ b/src/cljs/athens/views/pages/settings.cljs @@ -1,14 +1,14 @@ (ns athens.views.pages.settings (:require - ["@chakra-ui/react" :refer [Text Heading Box FormControl FormLabel ButtonGroup Grid Input Button Switch Modal ModalOverlay ModalContent ModalHeader ModalBody ModalCloseButton]] - [athens.db :refer [default-athens-persist]] - [athens.util :refer [toast]] - [cljs-http.client :as http] - [cljs.core.async :refer [js {:title "Account not found" :status "error" :description "No OpenCollective account was found with this email address."}))) - + ;; Something else, e.g. networking error - :else - (toast (clj->js {:title "Unknown error" - :status "error" - :description resp}))))))) + :else + (toast (clj->js {:title "Unknown error" + :status "error" + :description resp}))))))) (defn handle-reset-email @@ -80,21 +80,27 @@ [:> Heading {:size "md"} children]) -(defn header [children] + +(defn header + [children] [:> Box {:gridArea "header"} children]) + (defn glance [children] [:> Box children]) + (defn form [children] [:> Box {:gridArea "form"} children]) + (defn help [children] - [:> Text {:color "foreground.secondary" - :gridArea "help"} children]) + [:> Text {:color "foreground.secondary" + :gridArea "help"} children]) + (defn setting-wrapper ([children] @@ -201,7 +207,6 @@ [:> Button {:isDisabled true} "Backup my DB to the cloud"]]]]) - (defn reset-settings-comp [reset-fn] [setting-wrapper @@ -218,16 +223,16 @@ (reg-event-fx - :settings/update - (fn [{:keys [db]} [_ k v]] - {:db (assoc-in db [:athens/persist :settings k] v)})) + :settings/update + (fn [{:keys [db]} [_ k v]] + {:db (assoc-in db [:athens/persist :settings k] v)})) (reg-event-fx - :settings/reset - (fn [{:keys [db]} _] - {:db (assoc db :athens/persist default-athens-persist) - :dispatch [:boot]})) + :settings/reset + (fn [{:keys [db]} _] + {:db (assoc db :athens/persist default-athens-persist) + :dispatch [:boot]})) (defn page diff --git a/src/cljs/athens/views/references.cljs b/src/cljs/athens/views/references.cljs index 2c4e656a04..8dc8bc756e 100644 --- a/src/cljs/athens/views/references.cljs +++ b/src/cljs/athens/views/references.cljs @@ -1,6 +1,6 @@ (ns athens.views.references (:require - ["@chakra-ui/react" :refer [Box Button Heading VStack]])) + ["@chakra-ui/react" :refer [Box Button Heading VStack]])) (defn reference-header diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 1469e086f9..7b9e094d2b 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,15 +1,16 @@ (ns athens.views.right-sidebar (:require - ["/components/Icons/Icons" :refer [RightSidebarAddIcon]] - ["@chakra-ui/react" :refer [Flex Text Box AddIcon IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] - ["@material-ui/icons/Close" :default Close] - ["framer-motion" :refer [AnimatePresence motion]] - [athens.parse-renderer :as parse-renderer] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.graph :as graph] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Icons/Icons" :refer [RightSidebarAddIcon]] + ["@chakra-ui/react" :refer [Flex Text Box AddIcon IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] + ["@material-ui/icons/Close" :default Close] + ["framer-motion" :refer [AnimatePresence motion]] + [athens.parse-renderer :as parse-renderer] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.graph :as graph] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) + ;; Components @@ -52,91 +53,91 @@ (swap! state assoc :dragging false) (dispatch [:right-sidebar/set-width (:width @state)])))] (r/create-class - {:display-name "right-sidebar" - :component-did-mount (fn [] - (js/document.addEventListener "mousemove" move-handler) - (js/document.addEventListener "mouseup" mouse-up-handler)) - :component-will-unmount (fn [] - (js/document.removeEventListener "mousemove" move-handler) - (js/document.removeEventListener "mouseup" mouse-up-handler)) - :reagent-render (fn [open? items _] - [:> AnimatePresence {:initial false} - (when open? - [:> (.-div motion) - {:style {:display "flex" - :WebkitAppRegion "no-drag" - :flex-direction "column" - :height "calc(100% - 3.25rem)" - :marginTop "3.25rem" - :alignItems "stretch" - :justifySelf "stretch" - :transformOrigin "right" - :justifyContent "space-between" - :overflowX "visible" - :position "relative" - :gridArea "secondary-content"} - :initial {:width 0 - :opacity 0} - :transition (if (:dragging @state) - {:type "tween" - :duration 0} - nil) - :animate {:width (str (:width @state) "vw") - :opacity 1} - :exit {:width 0 - :opacity 0}} - [:> Box {:role "separator" - :aria-orientation "vertical" - :cursor "col-resize" - :position "absolute" - :top 0 - :bottom 0 - :width "1px" - :zIndex 1 - :transitionDuration "0.2s" - :transitionTimingFunction "ease-in-out" - :transitionProperty "common" - :bg "separator.divider" - :sx {:WebkitAppRegion "no-drag"} - :_hover {:bg "link"} - :_active {:bg "link"} - :_after {:content "''" - :position "absolute" - :sx {:WebkitAppRegion "no-drag"} - :inset "-4px"} - :on-mouse-down #(swap! state assoc :dragging true) - :class (when (:dragging @state) "is-dragging")}] - [:> Flex {:flexDirection "column" - :flex 1; - :maxHeight "calc(100vh - 3.25rem - 1px)" - :width (str (:width @state) "vw") - :overflowY "overlay"} - (if (empty? items) - [empty-message] - [:> Accordion {:allowMultiple true} - (doall - (for [[uid {:keys [node/title block/string is-graph?]}] items] - ^{:key uid} - [:> AccordionItem {:_first {:borderTop 0} :borderBottom 0} - [:> Box {:as "h2" :position "relative"} - [:> AccordionButton {:borderBottom "1px solid" - :borderRadius "0" - :borderBottomColor "separator.divider"} - [:> AccordionIcon {:as AddIcon}] - [parse-renderer/parse-and-render (or title string) uid]] - [:> IconButton {:size "xs" - :position "absolute" - :color "foreground.secondary" - :right 5 - :top 2 - :background "transparent" - :onClick #(dispatch [:right-sidebar/close-item uid])} - [:> Close]]] - [:> AccordionPanel {:p 0} - (cond - is-graph? [graph/page uid] - title [node-page/page [:block/uid uid]] - :else [block-page/page [:block/uid uid]])]]))])]])])}))) + {:display-name "right-sidebar" + :component-did-mount (fn [] + (js/document.addEventListener "mousemove" move-handler) + (js/document.addEventListener "mouseup" mouse-up-handler)) + :component-will-unmount (fn [] + (js/document.removeEventListener "mousemove" move-handler) + (js/document.removeEventListener "mouseup" mouse-up-handler)) + :reagent-render (fn [open? items _] + [:> AnimatePresence {:initial false} + (when open? + [:> (.-div motion) + {:style {:display "flex" + :WebkitAppRegion "no-drag" + :flex-direction "column" + :height "calc(100% - 3.25rem)" + :marginTop "3.25rem" + :alignItems "stretch" + :justifySelf "stretch" + :transformOrigin "right" + :justifyContent "space-between" + :overflowX "visible" + :position "relative" + :gridArea "secondary-content"} + :initial {:width 0 + :opacity 0} + :transition (if (:dragging @state) + {:type "tween" + :duration 0} + nil) + :animate {:width (str (:width @state) "vw") + :opacity 1} + :exit {:width 0 + :opacity 0}} + [:> Box {:role "separator" + :aria-orientation "vertical" + :cursor "col-resize" + :position "absolute" + :top 0 + :bottom 0 + :width "1px" + :zIndex 1 + :transitionDuration "0.2s" + :transitionTimingFunction "ease-in-out" + :transitionProperty "common" + :bg "separator.divider" + :sx {:WebkitAppRegion "no-drag"} + :_hover {:bg "link"} + :_active {:bg "link"} + :_after {:content "''" + :position "absolute" + :sx {:WebkitAppRegion "no-drag"} + :inset "-4px"} + :on-mouse-down #(swap! state assoc :dragging true) + :class (when (:dragging @state) "is-dragging")}] + [:> Flex {:flexDirection "column" + :flex 1; + :maxHeight "calc(100vh - 3.25rem - 1px)" + :width (str (:width @state) "vw") + :overflowY "overlay"} + (if (empty? items) + [empty-message] + [:> Accordion {:allowMultiple true} + (doall + (for [[uid {:keys [node/title block/string is-graph?]}] items] + ^{:key uid} + [:> AccordionItem {:_first {:borderTop 0} :borderBottom 0} + [:> Box {:as "h2" :position "relative"} + [:> AccordionButton {:borderBottom "1px solid" + :borderRadius "0" + :borderBottomColor "separator.divider"} + [:> AccordionIcon {:as AddIcon}] + [parse-renderer/parse-and-render (or title string) uid]] + [:> IconButton {:size "xs" + :position "absolute" + :color "foreground.secondary" + :right 5 + :top 2 + :background "transparent" + :onClick #(dispatch [:right-sidebar/close-item uid])} + [:> Close]]] + [:> AccordionPanel {:p 0} + (cond + is-graph? [graph/page uid] + title [node-page/page [:block/uid uid]] + :else [block-page/page [:block/uid uid]])]]))])]])])}))) (defn right-sidebar From 04210326adc43d83f6b04cc5832c489df9d89cb6 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 30 Mar 2022 21:23:38 -0400 Subject: [PATCH 34/79] fix: some athena tests passing --- playwright.electron.config.ts | 4 +-- src/cljs/athens/events.cljs | 15 --------- src/cljs/athens/views/athena.cljs | 28 ++++++++--------- src/cljs/athens/views/pages/header.cljs | 21 +++++++------ src/cljs/athens/views/pages/node_page.cljs | 35 +++++++++++---------- src/cljs/athens/views/pages/page.cljs | 2 +- src/js/components/Icons/icons.tsx | 8 +++++ src/js/theme/index.js | 2 -- test/e2e/utils.ts | 36 +++++++++++----------- 9 files changed, 72 insertions(+), 79 deletions(-) delete mode 100644 src/js/theme/index.js diff --git a/playwright.electron.config.ts b/playwright.electron.config.ts index 41290fa5a8..e7e900c146 100644 --- a/playwright.electron.config.ts +++ b/playwright.electron.config.ts @@ -18,7 +18,7 @@ const config: PlaywrightTestConfig = { ...baseConfig, workers: 1, use: {}, - projects: [{ + projects: [ { name: 'chromium', use: { browserName: 'chromium', @@ -32,7 +32,7 @@ const config: PlaywrightTestConfig = { mode: 'default', video: false, } - }], + } ], }; export default config; diff --git a/src/cljs/athens/events.cljs b/src/cljs/athens/events.cljs index 2b76d3e59f..4cc8318307 100644 --- a/src/cljs/athens/events.cljs +++ b/src/cljs/athens/events.cljs @@ -471,21 +471,6 @@ (assoc-in db [:selection :items] ordered-selection)))) -;; Alerts - -(reg-event-db - :alert/unset - (fn-traced [db] - (assoc db :alert nil))) - - -;; Use native js/alert rather than custom UI alert -(reg-event-fx - :alert/js - (fn [_ [_ message]] - {:alert/js! message})) - - (reg-event-fx :confirm/js (fn [_ [_ message true-cb false-cb]] diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 84116c4ce4..6d06ec5d19 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,17 +1,17 @@ (ns athens.views.athena (:require - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] - ["@material-ui/icons/Close" :default Close] - [athens.common.utils :as utils] - [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] - [athens.router :as router] - [athens.subs] - [athens.util :refer [scroll-into-view]] - [clojure.string :as str] - [goog.dom :refer [getElement]] - [goog.events :as events] - [re-frame.core :as rf :refer [subscribe dispatch]] - [reagent.core :as r]) + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] + ["/components/Icons/Icons" :refer [XmarkIcon]] + [athens.common.utils :as utils] + [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] + [athens.router :as router] + [athens.subs] + [athens.util :refer [scroll-into-view]] + [clojure.string :as str] + [goog.dom :refer [getElement]] + [goog.events :as events] + [re-frame.core :as rf :refer [subscribe dispatch]] + [reagent.core :as r]) (:import (goog.events KeyCodes))) @@ -297,7 +297,7 @@ :on-key-down (fn [e] (key-down-handler e state))}] (when (:query @state) [:> IconButton {:background "none" - :color "inherit" + :color "foreground.secondary" :position "absolute" :transition "opacity 0.1s ease, background 0.1s ease" :cursor "pointer" @@ -311,6 +311,6 @@ :display "flex" :top "2rem" :onClick #(set! (.-value (getElement "athena-input")) nil)} - [:> Close]]) + [:> XmarkIcon {:boxSize 6}]]) [results-el state] [search-results-el @state]]]))) diff --git a/src/cljs/athens/views/pages/header.cljs b/src/cljs/athens/views/pages/header.cljs index c3d241d87f..b8fdfe84dd 100644 --- a/src/cljs/athens/views/pages/header.cljs +++ b/src/cljs/athens/views/pages/header.cljs @@ -15,17 +15,18 @@ (defn page-header - ([_ children] - [:> Box {:as "header" - :class "page-header" - :position "relative"} - children])) + [children] + [:> Box {:as "header" + :class "page-header" + :position "relative"} + children]) (defn title-container - [children] - [:> Box title-style-props - children]) + ([props children] + (let [{:keys [_]} props] + [:> Box title-style-props + children]))) (defn editable-title-container @@ -33,8 +34,8 @@ (let [{:keys [_]} props] [:> Box (merge title-style-props - {:as "header" - :class "page-header" + {:as "h1" + :class "page-title" :sx {"textarea" {:appearance "none" :cursor "text" :resize "none" diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 0730df8db2..973f07d725 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -434,30 +434,31 @@ ;; Header [page-header + [:<> ;; Dropdown - [menu-dropdown node daily-note?] + [menu-dropdown node daily-note?] - [editable-title-container + [editable-title-container ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. - (when-not daily-note? - [autosize/textarea - {:value (:title/local @state) - :id (str "editable-uid-" uid) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :on-blur (fn [_] + (when-not daily-note? + [autosize/textarea + {:value (:title/local @state) + :id (str "editable-uid-" uid) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :on-blur (fn [_] ;; add title Untitled-n for empty titles - (when (empty? (:title/local @state)) - (swap! state assoc :title/local (auto-inc-untitled))) - (handle-blur node state)) - :on-key-down (fn [e] (handle-key-down e uid state children)) - :on-change (fn [e] (handle-change e state))}]) + (when (empty? (:title/local @state)) + (swap! state assoc :title/local (auto-inc-untitled))) + (handle-blur node state)) + :on-key-down (fn [e] (handle-key-down e uid state children)) + :on-change (fn [e] (handle-change e state))}]) ;; empty word break to keep span on full height else it will collapse to 0 height (weird ui) - (if (str/blank? (:title/local @state)) - [:wbr] - [perf-mon/hoc-perfmon {:span-name "parse-and-render"} - [parse-renderer/parse-and-render (:title/local @state) uid]])]] + (if (str/blank? (:title/local @state)) + [:wbr] + [perf-mon/hoc-perfmon {:span-name "parse-and-render"} + [parse-renderer/parse-and-render (:title/local @state) uid]])]]] ;; Children (if (empty? children) diff --git a/src/cljs/athens/views/pages/page.cljs b/src/cljs/athens/views/pages/page.cljs index 537ed741cf..776b539955 100644 --- a/src/cljs/athens/views/pages/page.cljs +++ b/src/cljs/athens/views/pages/page.cljs @@ -18,7 +18,7 @@ :flexDirection "column" :display "flex" :margin "2rem auto" - :padding "1rem 2rem 10rem 3rem" + :padding "1rem 4rem 10rem" :flexBasis "100%" :maxWidth "75rem"} children])) diff --git a/src/js/components/Icons/icons.tsx b/src/js/components/Icons/icons.tsx index c4b016e699..a19864f591 100644 --- a/src/js/components/Icons/icons.tsx +++ b/src/js/components/Icons/icons.tsx @@ -16,6 +16,14 @@ export const AllPagesIcon = createIcon({ ), }) +export const XmarkIcon = createIcon({ + displayName: 'XmarkIcon', + viewBox: '0 0 24 24', + path: ( + + ), +}) + export const DailyNotesIcon = createIcon({ displayName: 'DailyNotesIcon', viewBox: '0 0 24 24', diff --git a/src/js/theme/index.js b/src/js/theme/index.js deleted file mode 100644 index 76aed6f668..0000000000 --- a/src/js/theme/index.js +++ /dev/null @@ -1,2 +0,0 @@ -import { theme } from './theme' -export { theme }; \ No newline at end of file diff --git a/test/e2e/utils.ts b/test/e2e/utils.ts index c1501ea0d6..30469be700 100644 --- a/test/e2e/utils.ts +++ b/test/e2e/utils.ts @@ -6,7 +6,7 @@ export const isMac = process.platform === "darwin"; // NOTE: this is not supported by Playwright right now. -export const createLocalAthensDB = async (page:Page, dbName:string) => { +export const createLocalAthensDB = async (page: Page, dbName: string) => { // click db picker await page.click('button:nth-child(1)'); // click "Add Database" @@ -21,11 +21,11 @@ export const createLocalAthensDB = async (page:Page, dbName:string) => { // Fill [placeholder="DB Name"] await page.fill('[placeholder="DB Name"]', dbName); - const [fileChooser] = await Promise.all([ + const [ fileChooser ] = await Promise.all([ // TODO this is broken in Playwright for electron, no fix in sight page.waitForEvent('filechooser'), page.click('text=Browse') - ]); + ]); await fileChooser.setFiles('~/my-e2e-dbs'); await page.pause() @@ -33,19 +33,19 @@ export const createLocalAthensDB = async (page:Page, dbName:string) => { export const lastBlockSelector = '.textarea >> nth=-1'; -export const inputInLastBlock = async (page:Page, text:string) => { +export const inputInLastBlock = async (page: Page, text: string) => { await page.click(lastBlockSelector); await page.fill(lastBlockSelector, text); }; -export const saveLastBlock = async (page:Page, text:string) => { +export const saveLastBlock = async (page: Page, text: string) => { await inputInLastBlock(page, text); // Move away from the block to force a save. return page.press(lastBlockSelector, 'ArrowUp'); }; -export const saveLastBlockAndEnter = async (page:Page, text:string) => { - if (text=="") { +export const saveLastBlockAndEnter = async (page: Page, text: string) => { + if (text == "") { // This is a side effect of how we're waiting for the new block to appear below. // If someone finds a better way to do this you can remove this restriction. throw new Error("Cannot use saveLastBlockAndEnter with empty string."); @@ -57,25 +57,25 @@ export const saveLastBlockAndEnter = async (page:Page, text:string) => { await page.locator('.textarea.is-editing:text-is("")').waitFor(); }; -export const indentLastBlock = async (page:Page) => { +export const indentLastBlock = async (page: Page) => { await page.click(lastBlockSelector); return page.press(lastBlockSelector, 'Tab'); }; -export const unindentLastBlock = async (page:Page) => { +export const unindentLastBlock = async (page: Page) => { await page.click(lastBlockSelector); return page.press(lastBlockSelector, 'Shift+Tab'); }; -export const goToDailyPages = async (page:Page) => { +export const goToDailyPages = async (page: Page) => { // The sixth button is the daily notes button. // TODO: find a better way to address this button, maybe tooltip? await page.click('button:nth-child(6)'); } -export const waitForBoot = async (page:Page) => { - if (!isElectron){ +export const waitForBoot = async (page: Page) => { + if (!isElectron) { await page.goto('/'); } // Wait for an element that signals the app has finished loading. @@ -86,15 +86,15 @@ export const waitForBoot = async (page:Page) => { await page.waitForSelector("text=Find"); } -export const inputInAthena = async (page:Page, query:string) => { +export const inputInAthena = async (page: Page, query: string) => { await page.click('button:has-text("Find or create a page")'); await page.fill('[placeholder="Find or Create Page"]', query); } -export const pageTitleLocator = ".node-page > header > h1 > span"; +export const pageTitleLocator = ".node-page > .page-header > h1.page-title > .block"; -export const createPage = async (page:Page, title:string) => { +export const createPage = async (page: Page, title: string) => { await inputInAthena(page, title); // Press Enter @@ -107,18 +107,18 @@ export const createPage = async (page:Page, title:string) => { await page.locator(`${pageTitleLocator}:has-text("${title}")`).waitFor(); } -export const deleteCurrentPage = async (page:Page) => { +export const deleteCurrentPage = async (page: Page) => { // Open page elipsis menu await page.click(".node-page > header > button"); await page.click('button:has-text("Delete Page")'); await page.click('button:nth-child(6)'); } -export const todaysDate = async (page:Page) => { +export const todaysDate = async (page: Page) => { // This gets today's date as formatted by athens itself. // TODO: this doesn't work in the prod build, disabled usage for now. // Need to match the date formatting logic to use again. const todaysDate = await page.evaluate(`athens.dates.get_day()`); - const dateTitle = todaysDate.arr[3]; + const dateTitle = todaysDate.arr[ 3 ]; return dateTitle; }; From d445d5bfb00a6ee4906365937719f583542efbfd Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 30 Mar 2022 23:01:24 -0400 Subject: [PATCH 35/79] test: more tests passing --- src/cljs/athens/parse_renderer.cljs | 17 +++-- src/cljs/athens/views/athena.cljs | 4 +- .../athens/views/blocks/context_menu.cljs | 10 ++- src/cljs/athens/views/blocks/core.cljs | 4 +- src/cljs/athens/views/pages/node_page.cljs | 36 +++++----- src/cljs/athens/views/right_sidebar.cljs | 68 ++++++++++++------- src/js/components/Block/components/Anchor.tsx | 7 +- src/js/components/Icons/icons.tsx | 22 +++++- src/js/theme/theme.js | 3 + test/e2e/athena-navigation.spec.ts | 2 +- test/e2e/block-context-menu.spec.ts | 8 +-- 11 files changed, 110 insertions(+), 71 deletions(-) diff --git a/src/cljs/athens/parse_renderer.cljs b/src/cljs/athens/parse_renderer.cljs index 53224cf19e..14395bca36 100644 --- a/src/cljs/athens/parse_renderer.cljs +++ b/src/cljs/athens/parse_renderer.cljs @@ -15,17 +15,24 @@ (declare parse-and-render) -(def fm-props {:as "b" :class "formatting" :fontWeight "normal" :opacity "0.3"}) - +(def fm-props + {:as "b" + :class "formatting" + :whiteSpace "nowrap" + :fontWeight "normal" + :opacity "0.3"}) (def link-props {:color "link" :borderRadius "1px" :variant "link" :minWidth "0" - :whiteSpace "normal" - :wordBreak "break-word" + :whiteSpace "inherit" + :wordBreak "inherit" + :alignItems "flex-start" + :justifyContent "flex-start" :lineHeight "unset" + :textAlign "inherit" :fontSize "inherit" :fontWeight "inherit" :textDecoration "none"}) @@ -337,7 +344,7 @@ (defn parse-and-render "Converts a string of block syntax to Hiccup, with fallback formatting if it can’t be parsed." - [string uid] + [string uid interactive?] (when config/measure-parser? (js/console.group string)) (let [pt-n-1 (js/performance.now) diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 6d06ec5d19..301d3f3107 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,7 +1,7 @@ (ns athens.views.athena (:require - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] ["/components/Icons/Icons" :refer [XmarkIcon]] + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] [athens.common.utils :as utils] [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] [athens.router :as router] @@ -215,7 +215,7 @@ ^{:key i} [result-el {:key i :title query - :prefix "Create page " + :prefix "Create page: " :preview nil :query query :active? (= i index) diff --git a/src/cljs/athens/views/blocks/context_menu.cljs b/src/cljs/athens/views/blocks/context_menu.cljs index 8efca8d9b6..8f8135f4cf 100644 --- a/src/cljs/athens/views/blocks/context_menu.cljs +++ b/src/cljs/athens/views/blocks/context_menu.cljs @@ -9,7 +9,7 @@ (defn handle-copy-refs - [_ uid state] + [_ uid] (let [selected-items @(rf/subscribe [::select-subs/items]) ;; use this when using datascript-transit ;; uids (map (fn [x] [:block/uid x]) selected-items) @@ -19,13 +19,12 @@ (->> (map (fn [uid] (str "((" uid "))\n")) selected-items) (string/join "")))] (.. js/navigator -clipboard (writeText data)) - (toast (clj->js {:title "Copied ref to clipboard"})) - (swap! state assoc :context-menu/show false))) + (toast (clj->js {:title "Copied ref to clipboard"})))) (defn handle-copy-unformatted "If copying only a single block, dissoc children to not copy subtree." - [^js uid state] + [^js uid] (let [uids @(rf/subscribe [::select-subs/items])] (if (empty? uids) (let [block (dissoc (db/get-block [:block/uid uid]) :block/children) @@ -35,5 +34,4 @@ (map #(listeners/blocks-to-clipboard-data 0 % true)) (apply str))] (.. js/navigator -clipboard (writeText data))))) - (toast (clj->js {:title "Copied content to clipboard" :status "success"})) - (swap! state assoc :context-menu/show false)) + (toast (clj->js {:title "Copied content to clipboard" :status "success"}))) diff --git a/src/cljs/athens/views/blocks/core.cljs b/src/cljs/athens/views/blocks/core.cljs index be3e38d4d5..4ccdeac4f7 100644 --- a/src/cljs/athens/views/blocks/core.cljs +++ b/src/cljs/athens/views/blocks/core.cljs @@ -452,8 +452,8 @@ "closed-with-children") :block block :shouldShowDebugDetails (util/re-frame-10x-open?) - :onCopyRefs #(handle-copy-refs nil uid state) - :onCopyUnformatted #(handle-copy-unformatted uid state) + :onCopyRef #(handle-copy-refs nil uid) + :onCopyUnformatted #(handle-copy-unformatted uid) :onClick (fn [e] (let [shift? (.-shiftKey e)] (rf/dispatch [:reporting/navigation {:source :block-bullet diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 973f07d725..7c6f283b6a 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -434,31 +434,31 @@ ;; Header [page-header - [:<> +[:<> ;; Dropdown - [menu-dropdown node daily-note?] + [menu-dropdown node daily-note?] - [editable-title-container + [editable-title-container ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. - (when-not daily-note? - [autosize/textarea - {:value (:title/local @state) - :id (str "editable-uid-" uid) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :on-blur (fn [_] + (when-not daily-note? + [autosize/textarea + {:value (:title/local @state) + :id (str "editable-uid-" uid) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :on-blur (fn [_] ;; add title Untitled-n for empty titles - (when (empty? (:title/local @state)) - (swap! state assoc :title/local (auto-inc-untitled))) - (handle-blur node state)) - :on-key-down (fn [e] (handle-key-down e uid state children)) - :on-change (fn [e] (handle-change e state))}]) + (when (empty? (:title/local @state)) + (swap! state assoc :title/local (auto-inc-untitled))) + (handle-blur node state)) + :on-key-down (fn [e] (handle-key-down e uid state children)) + :on-change (fn [e] (handle-change e state))}]) ;; empty word break to keep span on full height else it will collapse to 0 height (weird ui) - (if (str/blank? (:title/local @state)) - [:wbr] - [perf-mon/hoc-perfmon {:span-name "parse-and-render"} - [parse-renderer/parse-and-render (:title/local @state) uid]])]]] + (if (str/blank? (:title/local @state)) + [:wbr] + [perf-mon/hoc-perfmon {:span-name "parse-and-render"} + [parse-renderer/parse-and-render (:title/local @state) uid]])]]] ;; Children (if (empty? children) diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 7b9e094d2b..76bef4bd21 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,8 +1,7 @@ (ns athens.views.right-sidebar (:require - ["/components/Icons/Icons" :refer [RightSidebarAddIcon]] - ["@chakra-ui/react" :refer [Flex Text Box AddIcon IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] - ["@material-ui/icons/Close" :default Close] + ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon ChevronDownIcon]] + ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] ["framer-motion" :refer [AnimatePresence motion]] [athens.parse-renderer :as parse-renderer] [athens.views.pages.block-page :as block-page] @@ -64,7 +63,9 @@ [:> AnimatePresence {:initial false} (when open? [:> (.-div motion) - {:style {:display "flex" + {:aria-role "sidebar" + :class "right-sidebar" + :style {:display "flex" :WebkitAppRegion "no-drag" :flex-direction "column" :height "calc(100% - 3.25rem)" @@ -116,28 +117,43 @@ [empty-message] [:> Accordion {:allowMultiple true} (doall - (for [[uid {:keys [node/title block/string is-graph?]}] items] - ^{:key uid} - [:> AccordionItem {:_first {:borderTop 0} :borderBottom 0} - [:> Box {:as "h2" :position "relative"} - [:> AccordionButton {:borderBottom "1px solid" - :borderRadius "0" - :borderBottomColor "separator.divider"} - [:> AccordionIcon {:as AddIcon}] - [parse-renderer/parse-and-render (or title string) uid]] - [:> IconButton {:size "xs" - :position "absolute" - :color "foreground.secondary" - :right 5 - :top 2 - :background "transparent" - :onClick #(dispatch [:right-sidebar/close-item uid])} - [:> Close]]] - [:> AccordionPanel {:p 0} - (cond - is-graph? [graph/page uid] - title [node-page/page [:block/uid uid]] - :else [block-page/page [:block/uid uid]])]]))])]])])}))) + (for [[uid {:keys [node/title block/string is-graph?]}] items] + ^{:key uid} + [:> AccordionItem {:borderWidth 0 + :borderColor "separator.divider" + :borderBottomWidth "1px"} + [:> Box {:as "h2" :position "relative"} + [:> AccordionButton {:borderRadius "0" + :py 4 + :pl 3 + :pr 4 + :height "auto" + :textAlign "left" + :overflow "hidden" + :whiteSpace "nowrap" + :border 0} + [:> AccordionIcon] + [:> Box {:flex "1 1 100%" + :mx 3 + :tabIndex -1 + :pointerEvents "none" + :position "relative" + :bottom "1px" + :overflow "hidden" + :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] + [:> IconButton {:size "sm" + :position "absolute" + :color "foreground.secondary" + :right 5 + :top 3 + :background "transparent" + :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} + [:> XmarkIcon]]] + [:> AccordionPanel {:p 4} + (cond + is-graph? [graph/page uid] + title [node-page/page [:block/uid uid]] + :else [block-page/page [:block/uid uid]])]]))])]])])}))) (defn right-sidebar diff --git a/src/js/components/Block/components/Anchor.tsx b/src/js/components/Block/components/Anchor.tsx index af940b0141..d9d94e36da 100644 --- a/src/js/components/Block/components/Anchor.tsx +++ b/src/js/components/Block/components/Anchor.tsx @@ -69,7 +69,7 @@ export interface AnchorProps { shouldShowDebugDetails: boolean; as: ReactNode; onContextMenu: (event: React.MouseEvent) => void; - onCopyRefs: () => void; + onCopyRef: () => void; onCopyUnformatted: () => void; onDragStart: () => void; onDragEnd: () => void; @@ -136,7 +136,7 @@ export const Anchor = (props: AnchorProps) => { const { isClosedWithChildren, anchorElement, shouldShowDebugDetails, - onCopyRefs, + onCopyRef, onCopyUnformatted, onDragStart, onDragEnd, @@ -148,6 +148,7 @@ export const Anchor = (props: AnchorProps) => { return ( setIsOpen(false)}> { - Copy block refs + Copy block ref Copy unformatted {shouldShowDebugDetails && ( <> diff --git a/src/js/components/Icons/icons.tsx b/src/js/components/Icons/icons.tsx index a19864f591..59bce212ed 100644 --- a/src/js/components/Icons/icons.tsx +++ b/src/js/components/Icons/icons.tsx @@ -20,7 +20,7 @@ export const XmarkIcon = createIcon({ displayName: 'XmarkIcon', viewBox: '0 0 24 24', path: ( - + ), }) @@ -72,11 +72,19 @@ export const MenuIcon = createIcon({ ), }) +export const ChevronUpIcon = createIcon({ + displayName: 'ChevronUpIcon', + viewBox: '0 0 24 24', + path: ( + + ), +}) + export const ChevronLeftIcon = createIcon({ displayName: 'ChevronLeftIcon', viewBox: '0 0 24 24', path: ( - + ), }) @@ -84,7 +92,15 @@ export const ChevronRightIcon = createIcon({ displayName: 'ChevronRightIcon', viewBox: '0 0 24 24', path: ( - + + ), +}) + +export const ChevronDownIcon = createIcon({ + displayName: 'ChevronDownIcon', + viewBox: '0 0 24 24', + path: ( + ), }) diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js index 31e6ea2909..044e0658f7 100644 --- a/src/js/theme/theme.js +++ b/src/js/theme/theme.js @@ -286,6 +286,9 @@ const components = { }, Breadcrumb: { baseStyle: { + container: { + lineHeight: 1.5, + }, separator: { color: 'separator.border' }, diff --git a/test/e2e/athena-navigation.spec.ts b/test/e2e/athena-navigation.spec.ts index 85c2bdb90c..9e7256b27b 100644 --- a/test/e2e/athena-navigation.spec.ts +++ b/test/e2e/athena-navigation.spec.ts @@ -24,7 +24,7 @@ test('athena create new page then click create page', async ({ page }) => { await inputInAthena(page, title); await Promise.all([ - page.click('text=Create Page: ' + title), + page.click('text=Create page: ' + title), page.waitForNavigation() ]); await expect(page.locator(pageTitleLocator)).toHaveText(title); diff --git a/test/e2e/block-context-menu.spec.ts b/test/e2e/block-context-menu.spec.ts index 14168acfdd..7705f42030 100644 --- a/test/e2e/block-context-menu.spec.ts +++ b/test/e2e/block-context-menu.spec.ts @@ -4,9 +4,9 @@ import { saveLastBlockAndEnter, waitForBoot, createPage, deleteCurrentPage } fro const rightClickFirstBullet = async (page: Page) => { - await page.click('.block-body >> nth=0 >> svg', { - button: 'right' - }); + await page.click('.block-body >> nth=0 >> [aria-label="Block anchor"]', { + button: 'right' + }); }; test.describe("no blocks selected", () => { @@ -32,12 +32,10 @@ test.describe("no blocks selected", () => { }); // This should close the context menu but doesn't yet. - /* test('clicking out of the context menu on the block itself closes context menu', async ({ page }) => { await page.click('text=alice'); await expect(page.locator('text="Copy block ref"')).not.toBeVisible(); }); - */ }) From 9205337402428229cd975d517c2d82ae1f0a41f6 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 30 Mar 2022 23:24:43 -0400 Subject: [PATCH 36/79] chore: cleanup minor redundancies --- src/cljs/athens/util.cljs | 4 ++-- src/cljs/athens/views.cljs | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/cljs/athens/util.cljs b/src/cljs/athens/util.cljs index 7c88491299..67ef5f4857 100644 --- a/src/cljs/athens/util.cljs +++ b/src/cljs/athens/util.cljs @@ -222,8 +222,8 @@ (let [os (.. js/window -navigator -appVersion)] (cond (re-find #"Windows" os) :windows - (re-find #"Linux" os) :linux - (re-find #"Mac" os) :mac))) + (re-find #"Mac" os) :mac + :else :linux))) (defn is-mac? diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 989b6e633d..5beb8fb151 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -72,12 +72,7 @@ 'devtool devtool devtool'" :height "100vh" :overflow "hidden" - :sx {"WebkitAppRegion" "drag"} - :className [(case os - :windows "os-windows" - :mac "os-mac" - :linux "os-linux") - (when electron? "is-electron")]} + :sx {"WebkitAppRegion" "drag"}} [app-toolbar/app-toolbar] [left-sidebar/left-sidebar] [pages/view] From cb636c2ccdc1fbdab445941523c730efe94bd4ba Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 30 Mar 2022 23:25:07 -0400 Subject: [PATCH 37/79] test: another test passing --- src/js/components/Block/components/Anchor.tsx | 2 +- test/e2e/block-context-menu.spec.ts | 6 +++--- test/e2e/utils.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/js/components/Block/components/Anchor.tsx b/src/js/components/Block/components/Anchor.tsx index d9d94e36da..878d31bd09 100644 --- a/src/js/components/Block/components/Anchor.tsx +++ b/src/js/components/Block/components/Anchor.tsx @@ -164,7 +164,7 @@ export const Anchor = (props: AnchorProps) => { - Copy block ref + Copy block refs Copy unformatted {shouldShowDebugDetails && ( <> diff --git a/test/e2e/block-context-menu.spec.ts b/test/e2e/block-context-menu.spec.ts index 7705f42030..390af90ecb 100644 --- a/test/e2e/block-context-menu.spec.ts +++ b/test/e2e/block-context-menu.spec.ts @@ -23,18 +23,18 @@ test.describe("no blocks selected", () => { }); test('right-click one block', async ({ page }) => { - await expect(page.locator('text="Copy block ref"')).toBeVisible(); + await expect(page.locator('text="Copy block refs"')).toBeVisible(); }); test('clicking out of the context menu onto the surrounding page closes context menu', async ({ page }) => { await page.click('.node-page'); - await expect(page.locator('text="Copy block ref"')).not.toBeVisible(); + await expect(page.locator('text="Copy block refs"')).not.toBeVisible(); }); // This should close the context menu but doesn't yet. test('clicking out of the context menu on the block itself closes context menu', async ({ page }) => { await page.click('text=alice'); - await expect(page.locator('text="Copy block ref"')).not.toBeVisible(); + await expect(page.locator('text="Copy block refs"')).not.toBeVisible(); }); }) diff --git a/test/e2e/utils.ts b/test/e2e/utils.ts index 30469be700..2ab97fd968 100644 --- a/test/e2e/utils.ts +++ b/test/e2e/utils.ts @@ -31,7 +31,7 @@ export const createLocalAthensDB = async (page: Page, dbName: string) => { await page.pause() }; -export const lastBlockSelector = '.textarea >> nth=-1'; +export const lastBlockSelector = '.block-input-textarea >> nth=-1'; export const inputInLastBlock = async (page: Page, text: string) => { await page.click(lastBlockSelector); @@ -54,7 +54,7 @@ export const saveLastBlockAndEnter = async (page: Page, text: string) => { await page.press(lastBlockSelector, 'Enter'); // Wait for the new block to be visible. // TODO: we shouldn't need to do this, instead we should have deterministic states from input. - await page.locator('.textarea.is-editing:text-is("")').waitFor(); + await page.locator('.block-input-textarea.is-editing:text-is("")').waitFor(); }; export const indentLastBlock = async (page: Page) => { From a9a9e5a1f49c0321e6520ce604440a15c0ac3479 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Wed, 30 Mar 2022 23:25:15 -0400 Subject: [PATCH 38/79] fix: add missing change --- src/cljs/athens/views/blocks/content.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cljs/athens/views/blocks/content.cljs b/src/cljs/athens/views/blocks/content.cljs index ca2ba006cb..eb14b84571 100644 --- a/src/cljs/athens/views/blocks/content.cljs +++ b/src/cljs/athens/views/blocks/content.cljs @@ -344,7 +344,7 @@ ;; When block is in editing mode or the editing DOM elements are rendered (when (or (:show-editable-dom @state) @editing?) [autosize/textarea {:value (:string/local @state) - :class ["textarea" (when (and (empty? @selected-items) @editing?) "is-editing")] + :class ["block-input-textarea" (when (and (empty? @selected-items) @editing?) "is-editing")] ;; :auto-focus true :id (str "editable-uid-" uid) :on-change (fn [e] (textarea-change e uid state)) From 1bb6750d3ff442d0a06fca7f6c8df08d6cdc3024 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 31 Mar 2022 20:47:17 -0400 Subject: [PATCH 39/79] improvement: updated page content layout --- src/cljs/athens/views.cljs | 4 - src/cljs/athens/views/left_sidebar.cljs | 1 + src/cljs/athens/views/pages/block_page.cljs | 84 ++++----- src/cljs/athens/views/pages/core.cljs | 1 - src/cljs/athens/views/pages/daily_notes.cljs | 47 ++--- src/cljs/athens/views/pages/header.cljs | 67 ------- src/cljs/athens/views/pages/node_page.cljs | 128 ++++++------- src/cljs/athens/views/pages/page.cljs | 33 +--- src/cljs/athens/views/right_sidebar.cljs | 183 ++++++++----------- src/js/components/AppToolbar/AppToolbar.tsx | 2 - src/js/components/Layout/Layout.tsx | 44 +++++ src/js/components/Page/Page.tsx | 155 ++++++++++++++++ src/js/theme/theme.js | 8 +- 13 files changed, 417 insertions(+), 340 deletions(-) delete mode 100644 src/cljs/athens/views/pages/header.cljs create mode 100644 src/js/components/Layout/Layout.tsx create mode 100644 src/js/components/Page/Page.tsx diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 5beb8fb151..74dc9c9424 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -5,10 +5,8 @@ ["@react-aria/overlays" :refer [OverlayProvider]] [athens.config] [athens.electron.db-modal :as db-modal] - [athens.electron.utils :as electron.utils] [athens.style :refer [zoom]] [athens.subs] - [athens.util :refer [get-os]] [athens.views.app-toolbar :as app-toolbar] [athens.views.athena :refer [athena-component]] [athens.views.devtool :refer [devtool-component]] @@ -34,8 +32,6 @@ (defn main [] (let [loading (rf/subscribe [:loading?]) - os (get-os) - electron? electron.utils/electron? modal (rf/subscribe [:modal])] (fn [] [:div (merge {:style {:display "contents"}} diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index 3f5766f677..8f79c7d16b 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -33,6 +33,7 @@ :textAlign "left" :justifyContent "flex-start" :overflow "hidden" + :fontWeight "medium" :whiteSpace "nowrap" :textOverflow "ellipsis" :flex "1" diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index 6b801acc16..a353810f0f 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -1,16 +1,16 @@ (ns athens.views.pages.block-page (:require - ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.views.blocks.core :as blocks] - [athens.views.pages.header :refer [page-header editable-title-container]] - [athens.views.pages.node-page :as node-page] - [athens.views.references :refer [reference-group reference-block]] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] + ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.views.blocks.core :as blocks] + [athens.views.pages.node-page :as node-page] + [athens.views.references :refer [reference-group reference-block]] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Helpers @@ -82,7 +82,7 @@ (defn parents-el [uid id] (let [parents (reactive/get-reactive-parents-recursively id)] - [:> Breadcrumb + [:> Breadcrumb {:gridArea "breadcrumb" :opacity 0.75} (doall (for [{:keys [node/title block/string] breadcrumb-uid :block/uid} parents] ^{:key breadcrumb-uid} @@ -102,41 +102,43 @@ (swap! state assoc :string/previous string :string/local string)) [:<> - ;; Parent Context - [parents-el uid id] ;; Header - [page-header - [editable-title-container {:onClick (fn [e] - (.. e preventDefault) - (if (.. e -shiftKey) - (do - (rf/dispatch [:reporting/navigation {:source :block-page - :target :block - :pane :right-pane}]) - (router/navigate-uid uid e)) - - (dispatch [:editing/uid uid])))} - [:<> - [autosize/textarea - {:id (str "editable-uid-" uid) - :value (:string/local @state) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :auto-focus true - :on-blur (fn [_] (persist-textarea-string @state uid)) - :on-key-down (fn [e] (node-page/handle-key-down e uid state nil)) - :on-change (fn [e] (block-page-change e uid state))}] - (if (clojure.string/blank? (:string/local @state)) - [:wbr] - [:span [parse-renderer/parse-and-render (:string/local @state) uid]])]]] + [:> PageHeader + + ;; Parent Context + [parents-el uid id] + [:> EditableTitleContainer {:onClick (fn [e] + (.. e preventDefault) + (if (.. e -shiftKey) + (do + (rf/dispatch [:reporting/navigation {:source :block-page + :target :block + :pane :right-pane}]) + (router/navigate-uid uid e)) + + (dispatch [:editing/uid uid])))} + [autosize/textarea + {:id (str "editable-uid-" uid) + :value (:string/local @state) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :auto-focus true + :on-blur (fn [_] (persist-textarea-string @state uid)) + :on-key-down (fn [e] (node-page/handle-key-down e uid state nil)) + :on-change (fn [e] (block-page-change e uid state))}] + (if (clojure.string/blank? (:string/local @state)) + [:wbr] + [:span [parse-renderer/parse-and-render (:string/local @state) uid]])]] ;; Children - [:div (for [child children] - (let [{:keys [db/id]} child] - ^{:key id} [blocks/block-el child]))] + [:> PageBody + (for [child children] + (let [{:keys [db/id]} child] + ^{:key id} [blocks/block-el child]))] ;; Refs - [linked-refs-el id]])))) + [:> PageFooter + [linked-refs-el id]]])))) (defn page diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs index 984db5ec7d..34a047f6c0 100644 --- a/src/cljs/athens/views/pages/core.cljs +++ b/src/cljs/athens/views/pages/core.cljs @@ -26,7 +26,6 @@ :gridArea "main-content" :alignItems "flex-start" :justifyContent "stretch" - :paddingTop "3.25rem" :display "flex" :overflowY "overlay" :sx {:maskImage "linear-gradient(to bottom, diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index 6f1f3142ff..f5378d62c0 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -1,11 +1,11 @@ (ns athens.views.pages.daily-notes (:require - ["@chakra-ui/react" :refer [Box VStack]] - [athens.dates :as dates] - [athens.reactive :as reactive] - [athens.views.pages.header :refer [title-container]] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]])) + ["/components/Page/Page" :refer [PageHeader TitleContainer DailyNotesPage]] + ["@chakra-ui/react" :refer [VStack]] + [athens.dates :as dates] + [athens.reactive :as reactive] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]])) (defn reactive-pull-many @@ -17,26 +17,6 @@ (keep #(reactive/get-reactive-block-document [:block/uid %]) ids)) -(defn daily-notes-page - ([props children] - (let [{:keys [real?]} props] - [:> Box {:class "node-page daily-notes" - :boxShadow "page", - :bg "background.floor" - :alignSelf "stretch" - :justifySelf "stretch" - :opacity (if real? 1 0.5) - :px {:sm 6 :md 12} - :py {:sm 6 :md 12} - :borderWidth "1px" - :borderStyle "solid" - :borderColor "separator.divider" - :transitionDuration "0s" - :borderRadius "0.5rem" - :minHeight "calc(100vh - 10rem)"} - children]))) - - ;; Components @@ -51,15 +31,16 @@ :minHeight "calc(100vh + 1px)" :display "flex" :gap "1.5rem" - :py "2rem" + :py "6rem" :px "2rem" :alignItems "stretch" :flex "1 1 100%" :flexDirection "column"} (doall - (for [{:keys [block/uid]} notes] - [daily-notes-page {:key uid - :real? true} - [node-page/page [:block/uid uid]]])) - [daily-notes-page {:real? false} - [title-container "Earlier"]]]))))) + (for [{:keys [block/uid]} notes] + [:> DailyNotesPage {:key uid + :isReal true} + [node-page/page [:block/uid uid]]])) + [:> DailyNotesPage {:isReal false} + [:> PageHeader + [:> TitleContainer "Earlier"]]]]))))) diff --git a/src/cljs/athens/views/pages/header.cljs b/src/cljs/athens/views/pages/header.cljs deleted file mode 100644 index b8fdfe84dd..0000000000 --- a/src/cljs/athens/views/pages/header.cljs +++ /dev/null @@ -1,67 +0,0 @@ -(ns athens.views.pages.header - (:require - ["@chakra-ui/react" :refer [Box]])) - - -(def title-style-props - {:position "relative" - :fontSize "2rem" - :overflow "visible" - :flexGrow "1" - :margin "0" - :whiteSpace "pre-line" - :wordBreak "break-word" - :fontWeight "bold"}) - - -(defn page-header - [children] - [:> Box {:as "header" - :class "page-header" - :position "relative"} - children]) - - -(defn title-container - ([props children] - (let [{:keys [_]} props] - [:> Box title-style-props - children]))) - - -(defn editable-title-container - ([props children] - (let [{:keys [_]} props] - [:> Box (merge - title-style-props - {:as "h1" - :class "page-title" - :sx {"textarea" {:appearance "none" - :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :fontWeight "inherit" - :padding "0" - :letterSpacing "inherit" - :width "100%" - :minHeight "100%" - :caretColor "link" - :background "transparent" - :margin "0" - :fontSize "inherit" - :lineHeight "inherit" - :borderRadius "0.25rem" - :transition "opacity 0.15s ease" - :border "0" - :fontFamily "inherit" - :visibility "hidden" - :position "absolute"} - {"textarea ::WebkitScrollbar" {:display "none"}} - {".is-editing textarea:focus" {:outline "none" - :visibility "visible" - :position "relative"}} - "abbr" {:z-index 4} - ".is-editing span" {:visibility "hidden" - :position "absolute"}}}) - children]))) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index 7c6f283b6a..ee03f218f7 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -1,32 +1,32 @@ (ns athens.views.pages.node-page (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Dialog/Dialog" :refer [Dialog]] - ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] - ["@material-ui/icons/Bookmark" :default Bookmark] - ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] - ["@material-ui/icons/BubbleChart" :default BubbleChart] - ["@material-ui/icons/Delete" :default Delete] - ["@material-ui/icons/MoreHoriz" :default MoreHoriz] - [athens.common-db :as common-db] - [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] - [athens.common.utils :as utils] - [athens.dates :as dates] - [athens.db :as db :refer [get-unlinked-references]] - [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] - [athens.views.blocks.core :as blocks] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.hoc.perf-mon :as perf-mon] - [athens.views.pages.header :refer [page-header editable-title-container]] - [athens.views.references :refer [reference-group reference-block]] - [clojure.string :as str] - [datascript.core :as d] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r]) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Dialog/Dialog" :refer [Dialog]] + ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] + ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] + ["@material-ui/icons/Bookmark" :default Bookmark] + ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] + ["@material-ui/icons/BubbleChart" :default BubbleChart] + ["@material-ui/icons/Delete" :default Delete] + ["@material-ui/icons/MoreHoriz" :default MoreHoriz] + [athens.common-db :as common-db] + [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] + [athens.common.utils :as utils] + [athens.dates :as dates] + [athens.db :as db :refer [get-unlinked-references]] + [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] + [athens.views.blocks.core :as blocks] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [athens.views.hoc.perf-mon :as perf-mon] + [athens.views.references :refer [reference-group reference-block]] + [clojure.string :as str] + [datascript.core :as d] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r]) (:import (goog.events KeyCodes))) @@ -214,12 +214,13 @@ :node/title} node] [:> Menu [:> MenuButton {:as IconButton - :position "absolute" + :gridArea "menu" + :justifySelf "center" + :alignSelf "flex-end" + :mb 1 :bg "transparent" :height "2.5rem" :width "2.5rem" - :right "100%" - :top "0.35rem" :borderRadius "full" :sx {"span" {:display "contents"} "button svg:first-child" {:marginRight "0.25rem"}}} @@ -230,13 +231,13 @@ (if sidebar [:> MenuItem {:onClick #(dispatch [:left-sidebar/remove-shortcut title])} [:> BookmarkBorder] - [:span "Remove Shortcut"]] + "Remove Shortcut"] [:> MenuItem {:onClick #(dispatch [:left-sidebar/add-shortcut title])} [:> Bookmark] [:span "Add Shortcut"]]) [:> MenuItem {:onClick #(dispatch [:right-sidebar/open-item uid true])} [:> BubbleChart] - [:span "Show Local Graph"]]] + "Show Local Graph"]] [:> MenuDivider] [:> MenuItem {:onClick (fn [] ;; if page being deleted is in right sidebar, remove from right sidebar @@ -253,7 +254,7 @@ (if daily-note? (dispatch [:daily-note/delete uid title]) (dispatch [:page/delete title])))} - [:> Delete] [:span "Delete Page"]]]]])) + [:> Delete] "Delete Page"]]]])) (defn ref-comp @@ -269,7 +270,7 @@ (let [{:keys [block parents embed-id]} @state block (reactive/get-reactive-block-document (:db/id block))] [:<> - [:> Breadcrumb {:fontSize "0.7em" :pl 6} + [:> Breadcrumb {:fontSize "0.7em" :pl 6 :opacity 0.75} (doall (for [{:keys [node/title block/string block/uid]} parents] [:> BreadcrumbItem {:key (str "breadcrumb-" uid)} @@ -432,45 +433,46 @@ :onDismiss cancel-fn}]) ;; Header - [page-header + [:> PageHeader -[:<> ;; Dropdown - [menu-dropdown node daily-note?] + [menu-dropdown node daily-note?] - [editable-title-container + [:> EditableTitleContainer ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. - (when-not daily-note? - [autosize/textarea - {:value (:title/local @state) - :id (str "editable-uid-" uid) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :on-blur (fn [_] + (when-not daily-note? + [autosize/textarea + {:value (:title/local @state) + :id (str "editable-uid-" uid) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :on-blur (fn [_] ;; add title Untitled-n for empty titles - (when (empty? (:title/local @state)) - (swap! state assoc :title/local (auto-inc-untitled))) - (handle-blur node state)) - :on-key-down (fn [e] (handle-key-down e uid state children)) - :on-change (fn [e] (handle-change e state))}]) + (when (empty? (:title/local @state)) + (swap! state assoc :title/local (auto-inc-untitled))) + (handle-blur node state)) + :on-key-down (fn [e] (handle-key-down e uid state children)) + :on-change (fn [e] (handle-change e state))}]) ;; empty word break to keep span on full height else it will collapse to 0 height (weird ui) - (if (str/blank? (:title/local @state)) - [:wbr] - [perf-mon/hoc-perfmon {:span-name "parse-and-render"} - [parse-renderer/parse-and-render (:title/local @state) uid]])]]] - - ;; Children - (if (empty? children) - [placeholder-block-el uid] - [:div - (for [{:block/keys [uid] :as child} children] - ^{:key uid} - [perf-mon/hoc-perfmon {:span-name "block-el"} - [blocks/block-el child]])]) + (if (str/blank? (:title/local @state)) + [:wbr] + [perf-mon/hoc-perfmon {:span-name "parse-and-render"} + [parse-renderer/parse-and-render (:title/local @state) uid]])]] + + [:> PageBody + + ;; Children + (if (empty? children) + [placeholder-block-el uid] + [:div + (for [{:block/keys [uid] :as child} children] + ^{:key uid} + [perf-mon/hoc-perfmon {:span-name "block-el"} + [blocks/block-el child]])])] ;; References - [:> Box {:py 10} + [:> PageFooter [perf-mon/hoc-perfmon-no-new-tx {:span-name "linked-ref-el"} [linked-ref-el state on-daily-notes? title]] [perf-mon/hoc-perfmon-no-new-tx {:span-name "unlinked-ref-el"} diff --git a/src/cljs/athens/views/pages/page.cljs b/src/cljs/athens/views/pages/page.cljs index 776b539955..af5d6b6d6e 100644 --- a/src/cljs/athens/views/pages/page.cljs +++ b/src/cljs/athens/views/pages/page.cljs @@ -1,27 +1,12 @@ (ns athens.views.pages.page (:require - ["@chakra-ui/react" :refer [Box]] - [athens.common-db :as common-db] - [athens.db :as db] - [athens.reactive :as reactive] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.node-page :as node-page] - [re-frame.core :as rf])) - - -(defn page-container - [props children] - (let [{:keys [uid type]} props] - [:> Box {:as "article" - :data-ui uid - :class (str type "-page") - :flexDirection "column" - :display "flex" - :margin "2rem auto" - :padding "1rem 4rem 10rem" - :flexBasis "100%" - :maxWidth "75rem"} - children])) + ["/components/Page/Page" :refer [PageContainer]] + [athens.common-db :as common-db] + [athens.db :as db] + [athens.reactive :as reactive] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.node-page :as node-page] + [re-frame.core :as rf])) (defn page-by-title @@ -29,7 +14,7 @@ (let [title (rf/subscribe [:current-route/page-title]) page-eid (common-db/e-by-av @db/dsdb :node/title @title)] (if (int? page-eid) - [page-container {:uid page-eid :type "node"} + [:> PageContainer {:uid page-eid :type "node"} [node-page/page page-eid]] [:h3 (str "404: Page with title '" @title "' doesn't exist")]))) @@ -39,7 +24,7 @@ [] (let [uid (rf/subscribe [:current-route/uid]) {:keys [node/title block/string db/id]} (reactive/get-reactive-block-or-page-by-uid @uid)] - [page-container {:uid @uid :type (if title "node" "block")} + [:> PageContainer {:uid @uid :type (if title "node" "block")} (cond title [node-page/page id] string [block-page/page id] diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 76bef4bd21..6cf2ef53c1 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,14 +1,15 @@ (ns athens.views.right-sidebar (:require - ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon ChevronDownIcon]] - ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] - ["framer-motion" :refer [AnimatePresence motion]] - [athens.parse-renderer :as parse-renderer] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.graph :as graph] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Layout/Layout" :refer [RightSidebarContainer]] + ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon]] + ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] + ["framer-motion" :refer [AnimatePresence motion]] + [athens.parse-renderer :as parse-renderer] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.graph :as graph] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Components @@ -60,100 +61,76 @@ (js/document.removeEventListener "mousemove" move-handler) (js/document.removeEventListener "mouseup" mouse-up-handler)) :reagent-render (fn [open? items _] - [:> AnimatePresence {:initial false} - (when open? - [:> (.-div motion) - {:aria-role "sidebar" - :class "right-sidebar" - :style {:display "flex" - :WebkitAppRegion "no-drag" - :flex-direction "column" - :height "calc(100% - 3.25rem)" - :marginTop "3.25rem" - :alignItems "stretch" - :justifySelf "stretch" - :transformOrigin "right" - :justifyContent "space-between" - :overflowX "visible" - :position "relative" - :gridArea "secondary-content"} - :initial {:width 0 - :opacity 0} - :transition (if (:dragging @state) - {:type "tween" - :duration 0} - nil) - :animate {:width (str (:width @state) "vw") - :opacity 1} - :exit {:width 0 - :opacity 0}} - [:> Box {:role "separator" - :aria-orientation "vertical" - :cursor "col-resize" - :position "absolute" - :top 0 - :bottom 0 - :width "1px" - :zIndex 1 - :transitionDuration "0.2s" - :transitionTimingFunction "ease-in-out" - :transitionProperty "common" - :bg "separator.divider" - :sx {:WebkitAppRegion "no-drag"} - :_hover {:bg "link"} - :_active {:bg "link"} - :_after {:content "''" - :position "absolute" - :sx {:WebkitAppRegion "no-drag"} - :inset "-4px"} - :on-mouse-down #(swap! state assoc :dragging true) - :class (when (:dragging @state) "is-dragging")}] - [:> Flex {:flexDirection "column" - :flex 1; - :maxHeight "calc(100vh - 3.25rem - 1px)" - :width (str (:width @state) "vw") - :overflowY "overlay"} - (if (empty? items) - [empty-message] - [:> Accordion {:allowMultiple true} - (doall - (for [[uid {:keys [node/title block/string is-graph?]}] items] - ^{:key uid} - [:> AccordionItem {:borderWidth 0 - :borderColor "separator.divider" - :borderBottomWidth "1px"} - [:> Box {:as "h2" :position "relative"} - [:> AccordionButton {:borderRadius "0" - :py 4 - :pl 3 - :pr 4 - :height "auto" - :textAlign "left" - :overflow "hidden" - :whiteSpace "nowrap" - :border 0} - [:> AccordionIcon] - [:> Box {:flex "1 1 100%" - :mx 3 - :tabIndex -1 - :pointerEvents "none" - :position "relative" - :bottom "1px" - :overflow "hidden" - :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] - [:> IconButton {:size "sm" - :position "absolute" - :color "foreground.secondary" - :right 5 - :top 3 - :background "transparent" - :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} - [:> XmarkIcon]]] - [:> AccordionPanel {:p 4} - (cond - is-graph? [graph/page uid] - title [node-page/page [:block/uid uid]] - :else [block-page/page [:block/uid uid]])]]))])]])])}))) + [:> RightSidebarContainer {:isOpen open? + :isDragging (:dragging @state) + :width (:width @state)} + [:> Box {:role "separator" + :aria-orientation "vertical" + :cursor "col-resize" + :position "absolute" + :top 0 + :bottom 0 + :width "1px" + :zIndex 1 + :transitionDuration "0.2s" + :transitionTimingFunction "ease-in-out" + :transitionProperty "common" + :bg "separator.divider" + :sx {:WebkitAppRegion "no-drag"} + :_hover {:bg "link"} + :_active {:bg "link"} + :_after {:content "''" + :position "absolute" + :sx {:WebkitAppRegion "no-drag"} + :inset "-4px"} + :on-mouse-down #(swap! state assoc :dragging true) + :class (when (:dragging @state) "is-dragging")}] + [:> Flex {:flexDirection "column" + :flex 1; + :maxHeight "calc(100vh - 3.25rem - 1px)" + :width (str (:width @state) "vw") + :overflowY "overlay"} + (if (empty? items) + [empty-message] + [:> Accordion {:allowMultiple true} + (doall + (for [[uid {:keys [node/title block/string is-graph?]}] items] + ^{:key uid} + [:> AccordionItem {:borderWidth 0 + :borderColor "separator.divider" + :borderBottomWidth "1px"} + [:> Box {:as "h2" :position "relative"} + [:> AccordionButton {:borderRadius "0" + :py 4 + :pl 3 + :pr 4 + :height "auto" + :textAlign "left" + :overflow "hidden" + :whiteSpace "nowrap" + :border 0} + [:> AccordionIcon] + [:> Box {:flex "1 1 100%" + :mx 3 + :tabIndex -1 + :pointerEvents "none" + :position "relative" + :bottom "1px" + :overflow "hidden" + :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] + [:> IconButton {:size "sm" + :position "absolute" + :color "foreground.secondary" + :right 5 + :top 3 + :background "transparent" + :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} + [:> XmarkIcon]]] + [:> AccordionPanel {:p 4} + (cond + is-graph? [graph/page uid] + title [node-page/page [:block/uid uid]] + :else [block-page/page [:block/uid uid]])]]))])]])}))) (defn right-sidebar diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index b9f3e27f95..d6306725bc 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -232,8 +232,6 @@ const SecondaryToolbarOverflowMenu = (items) => { export const AppToolbar = (props: AppToolbarProps): React.ReactElement => { - console.log(electron); - const { os, route, diff --git a/src/js/components/Layout/Layout.tsx b/src/js/components/Layout/Layout.tsx new file mode 100644 index 0000000000..e5c46cb2c1 --- /dev/null +++ b/src/js/components/Layout/Layout.tsx @@ -0,0 +1,44 @@ +import { Box } from '@chakra-ui/react'; +import { AnimatePresence, motion } from 'framer-motion'; + +const Container = motion(Box) + +export const RightSidebarContainer = ({ isOpen, width, isDragging, children }) => { + return + {isOpen && + + {children} + } + +} \ No newline at end of file diff --git a/src/js/components/Page/Page.tsx b/src/js/components/Page/Page.tsx new file mode 100644 index 0000000000..b60449f2ae --- /dev/null +++ b/src/js/components/Page/Page.tsx @@ -0,0 +1,155 @@ +import { Box } from '@chakra-ui/react'; + +const PAGE_PROPS = { + as: "article", + display: "grid", + flexBasis: "100%", + gridTemplateAreas: "'header' 'content' 'footer'", + gridTemplateRows: "auto 1fr auto", + sx: { + "--page-padding-v": "6rem", + "--page-padding-h": "4rem" + } +} + +const TITLE_PROPS = { + position: "relative", + gridArea: "title", + fontSize: "2rem", + overflow: "visible", + flexGrow: "1", + margin: "0", + whiteSpace: "pre-line", + wordBreak: "break-word", + fontWeight: "bold", +} + +export const PageContainer = ({ children, uid, type }) => {children} + +export const HeaderImage = ({ src }) => + +export const PageHeader = ({ children, image }) => + {image && } + {children} + + +export const PageBody = ({ children }) => {children} + +export const PageFooter = ({ children }) => {children} + +export const TitleContainer = ({ children }) => {children} + +export const DailyNotesPage = ({ isReal, children }) => {children} + +export const EditableTitleContainer = ({ children }) => + {children} \ No newline at end of file diff --git a/src/js/theme/theme.js b/src/js/theme/theme.js index 044e0658f7..9bd180680f 100644 --- a/src/js/theme/theme.js +++ b/src/js/theme/theme.js @@ -385,7 +385,8 @@ const components = { zIndex: 3, overflow: 'hidden', py: 0, - bg: 'background.upper', + bg: 'background.vibrancy', + backdropFilter: "blur(20px)", minWidth: '0', width: 'max-content', shadow: 'menu' @@ -403,8 +404,11 @@ const components = { "svg": { flexShrink: 0, fontSize: "1.5em", + }, + // additional selector to catch icons not using the icon prop + "&& > svg:first-child, svg:not(span > svg)": { marginInlineEnd: "0.75rem" - } + }, } }, sizes: { From d7780cb583c7a91ecf0a403ee30da54ae7e25470 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 31 Mar 2022 20:47:47 -0400 Subject: [PATCH 40/79] chore: lint --- src/cljs/athens/parse_renderer.cljs | 2 + src/cljs/athens/views/athena.cljs | 24 ++--- src/cljs/athens/views/pages/block_page.cljs | 24 ++--- src/cljs/athens/views/pages/daily_notes.cljs | 20 ++--- src/cljs/athens/views/pages/node_page.cljs | 90 +++++++++---------- src/cljs/athens/views/pages/page.cljs | 14 +-- src/cljs/athens/views/right_sidebar.cljs | 94 ++++++++++---------- 7 files changed, 135 insertions(+), 133 deletions(-) diff --git a/src/cljs/athens/parse_renderer.cljs b/src/cljs/athens/parse_renderer.cljs index 14395bca36..7393d54727 100644 --- a/src/cljs/athens/parse_renderer.cljs +++ b/src/cljs/athens/parse_renderer.cljs @@ -15,6 +15,7 @@ (declare parse-and-render) + (def fm-props {:as "b" :class "formatting" @@ -22,6 +23,7 @@ :fontWeight "normal" :opacity "0.3"}) + (def link-props {:color "link" :borderRadius "1px" diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 301d3f3107..a71b40c0ea 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,17 +1,17 @@ (ns athens.views.athena (:require - ["/components/Icons/Icons" :refer [XmarkIcon]] - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] - [athens.common.utils :as utils] - [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] - [athens.router :as router] - [athens.subs] - [athens.util :refer [scroll-into-view]] - [clojure.string :as str] - [goog.dom :refer [getElement]] - [goog.events :as events] - [re-frame.core :as rf :refer [subscribe dispatch]] - [reagent.core :as r]) + ["/components/Icons/Icons" :refer [XmarkIcon]] + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] + [athens.common.utils :as utils] + [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] + [athens.router :as router] + [athens.subs] + [athens.util :refer [scroll-into-view]] + [clojure.string :as str] + [goog.dom :refer [getElement]] + [goog.events :as events] + [re-frame.core :as rf :refer [subscribe dispatch]] + [reagent.core :as r]) (:import (goog.events KeyCodes))) diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index a353810f0f..7f0abd2e3a 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -1,16 +1,16 @@ (ns athens.views.pages.block-page (:require - ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] - ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.views.blocks.core :as blocks] - [athens.views.pages.node-page :as node-page] - [athens.views.references :refer [reference-group reference-block]] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] + ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.views.blocks.core :as blocks] + [athens.views.pages.node-page :as node-page] + [athens.views.references :refer [reference-group reference-block]] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Helpers @@ -106,7 +106,7 @@ ;; Header [:> PageHeader - ;; Parent Context + ;; Parent Context [parents-el uid id] [:> EditableTitleContainer {:onClick (fn [e] (.. e preventDefault) diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index f5378d62c0..87222c3373 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -1,11 +1,11 @@ (ns athens.views.pages.daily-notes (:require - ["/components/Page/Page" :refer [PageHeader TitleContainer DailyNotesPage]] - ["@chakra-ui/react" :refer [VStack]] - [athens.dates :as dates] - [athens.reactive :as reactive] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]])) + ["/components/Page/Page" :refer [PageHeader TitleContainer DailyNotesPage]] + ["@chakra-ui/react" :refer [VStack]] + [athens.dates :as dates] + [athens.reactive :as reactive] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]])) (defn reactive-pull-many @@ -37,10 +37,10 @@ :flex "1 1 100%" :flexDirection "column"} (doall - (for [{:keys [block/uid]} notes] - [:> DailyNotesPage {:key uid - :isReal true} - [node-page/page [:block/uid uid]]])) + (for [{:keys [block/uid]} notes] + [:> DailyNotesPage {:key uid + :isReal true} + [node-page/page [:block/uid uid]]])) [:> DailyNotesPage {:isReal false} [:> PageHeader [:> TitleContainer "Earlier"]]]]))))) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index ee03f218f7..d27fea074e 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -1,32 +1,32 @@ (ns athens.views.pages.node-page (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Dialog/Dialog" :refer [Dialog]] - ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] - ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] - ["@material-ui/icons/Bookmark" :default Bookmark] - ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] - ["@material-ui/icons/BubbleChart" :default BubbleChart] - ["@material-ui/icons/Delete" :default Delete] - ["@material-ui/icons/MoreHoriz" :default MoreHoriz] - [athens.common-db :as common-db] - [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] - [athens.common.utils :as utils] - [athens.dates :as dates] - [athens.db :as db :refer [get-unlinked-references]] - [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] - [athens.views.blocks.core :as blocks] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.hoc.perf-mon :as perf-mon] - [athens.views.references :refer [reference-group reference-block]] - [clojure.string :as str] - [datascript.core :as d] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r]) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Dialog/Dialog" :refer [Dialog]] + ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] + ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] + ["@material-ui/icons/Bookmark" :default Bookmark] + ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] + ["@material-ui/icons/BubbleChart" :default BubbleChart] + ["@material-ui/icons/Delete" :default Delete] + ["@material-ui/icons/MoreHoriz" :default MoreHoriz] + [athens.common-db :as common-db] + [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] + [athens.common.utils :as utils] + [athens.dates :as dates] + [athens.db :as db :refer [get-unlinked-references]] + [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] + [athens.views.blocks.core :as blocks] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [athens.views.hoc.perf-mon :as perf-mon] + [athens.views.references :refer [reference-group reference-block]] + [clojure.string :as str] + [datascript.core :as d] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r]) (:import (goog.events KeyCodes))) @@ -433,32 +433,32 @@ :onDismiss cancel-fn}]) ;; Header - [:> PageHeader + [:> PageHeader ;; Dropdown - [menu-dropdown node daily-note?] + [menu-dropdown node daily-note?] - [:> EditableTitleContainer + [:> EditableTitleContainer ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. - (when-not daily-note? - [autosize/textarea - {:value (:title/local @state) - :id (str "editable-uid-" uid) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :on-blur (fn [_] + (when-not daily-note? + [autosize/textarea + {:value (:title/local @state) + :id (str "editable-uid-" uid) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :on-blur (fn [_] ;; add title Untitled-n for empty titles - (when (empty? (:title/local @state)) - (swap! state assoc :title/local (auto-inc-untitled))) - (handle-blur node state)) - :on-key-down (fn [e] (handle-key-down e uid state children)) - :on-change (fn [e] (handle-change e state))}]) + (when (empty? (:title/local @state)) + (swap! state assoc :title/local (auto-inc-untitled))) + (handle-blur node state)) + :on-key-down (fn [e] (handle-key-down e uid state children)) + :on-change (fn [e] (handle-change e state))}]) ;; empty word break to keep span on full height else it will collapse to 0 height (weird ui) - (if (str/blank? (:title/local @state)) - [:wbr] - [perf-mon/hoc-perfmon {:span-name "parse-and-render"} - [parse-renderer/parse-and-render (:title/local @state) uid]])]] + (if (str/blank? (:title/local @state)) + [:wbr] + [perf-mon/hoc-perfmon {:span-name "parse-and-render"} + [parse-renderer/parse-and-render (:title/local @state) uid]])]] [:> PageBody diff --git a/src/cljs/athens/views/pages/page.cljs b/src/cljs/athens/views/pages/page.cljs index af5d6b6d6e..7146879b95 100644 --- a/src/cljs/athens/views/pages/page.cljs +++ b/src/cljs/athens/views/pages/page.cljs @@ -1,12 +1,12 @@ (ns athens.views.pages.page (:require - ["/components/Page/Page" :refer [PageContainer]] - [athens.common-db :as common-db] - [athens.db :as db] - [athens.reactive :as reactive] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.node-page :as node-page] - [re-frame.core :as rf])) + ["/components/Page/Page" :refer [PageContainer]] + [athens.common-db :as common-db] + [athens.db :as db] + [athens.reactive :as reactive] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.node-page :as node-page] + [re-frame.core :as rf])) (defn page-by-title diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 6cf2ef53c1..215d65a5ba 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,15 +1,15 @@ (ns athens.views.right-sidebar (:require - ["/components/Layout/Layout" :refer [RightSidebarContainer]] - ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon]] - ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] - ["framer-motion" :refer [AnimatePresence motion]] - [athens.parse-renderer :as parse-renderer] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.graph :as graph] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon]] + ["/components/Layout/Layout" :refer [RightSidebarContainer]] + ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] + ["framer-motion" :refer [AnimatePresence motion]] + [athens.parse-renderer :as parse-renderer] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.graph :as graph] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Components @@ -94,43 +94,43 @@ [empty-message] [:> Accordion {:allowMultiple true} (doall - (for [[uid {:keys [node/title block/string is-graph?]}] items] - ^{:key uid} - [:> AccordionItem {:borderWidth 0 - :borderColor "separator.divider" - :borderBottomWidth "1px"} - [:> Box {:as "h2" :position "relative"} - [:> AccordionButton {:borderRadius "0" - :py 4 - :pl 3 - :pr 4 - :height "auto" - :textAlign "left" - :overflow "hidden" - :whiteSpace "nowrap" - :border 0} - [:> AccordionIcon] - [:> Box {:flex "1 1 100%" - :mx 3 - :tabIndex -1 - :pointerEvents "none" - :position "relative" - :bottom "1px" - :overflow "hidden" - :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] - [:> IconButton {:size "sm" - :position "absolute" - :color "foreground.secondary" - :right 5 - :top 3 - :background "transparent" - :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} - [:> XmarkIcon]]] - [:> AccordionPanel {:p 4} - (cond - is-graph? [graph/page uid] - title [node-page/page [:block/uid uid]] - :else [block-page/page [:block/uid uid]])]]))])]])}))) + (for [[uid {:keys [node/title block/string is-graph?]}] items] + ^{:key uid} + [:> AccordionItem {:borderWidth 0 + :borderColor "separator.divider" + :borderBottomWidth "1px"} + [:> Box {:as "h2" :position "relative"} + [:> AccordionButton {:borderRadius "0" + :py 4 + :pl 3 + :pr 4 + :height "auto" + :textAlign "left" + :overflow "hidden" + :whiteSpace "nowrap" + :border 0} + [:> AccordionIcon] + [:> Box {:flex "1 1 100%" + :mx 3 + :tabIndex -1 + :pointerEvents "none" + :position "relative" + :bottom "1px" + :overflow "hidden" + :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] + [:> IconButton {:size "sm" + :position "absolute" + :color "foreground.secondary" + :right 5 + :top 3 + :background "transparent" + :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} + [:> XmarkIcon]]] + [:> AccordionPanel {:p 4} + (cond + is-graph? [graph/page uid] + title [node-page/page [:block/uid uid]] + :else [block-page/page [:block/uid uid]])]]))])]])}))) (defn right-sidebar From ebbdf5dfb80655db5c8ef0a55711945754bd2ed5 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 31 Mar 2022 20:47:47 -0400 Subject: [PATCH 41/79] chore: lint --- src/cljs/athens/parse_renderer.cljs | 2 + src/cljs/athens/views/athena.cljs | 24 ++--- src/cljs/athens/views/pages/block_page.cljs | 24 ++--- src/cljs/athens/views/pages/daily_notes.cljs | 20 ++--- src/cljs/athens/views/pages/node_page.cljs | 90 +++++++++---------- src/cljs/athens/views/pages/page.cljs | 14 +-- src/cljs/athens/views/right_sidebar.cljs | 93 ++++++++++---------- 7 files changed, 134 insertions(+), 133 deletions(-) diff --git a/src/cljs/athens/parse_renderer.cljs b/src/cljs/athens/parse_renderer.cljs index 14395bca36..7393d54727 100644 --- a/src/cljs/athens/parse_renderer.cljs +++ b/src/cljs/athens/parse_renderer.cljs @@ -15,6 +15,7 @@ (declare parse-and-render) + (def fm-props {:as "b" :class "formatting" @@ -22,6 +23,7 @@ :fontWeight "normal" :opacity "0.3"}) + (def link-props {:color "link" :borderRadius "1px" diff --git a/src/cljs/athens/views/athena.cljs b/src/cljs/athens/views/athena.cljs index 301d3f3107..a71b40c0ea 100644 --- a/src/cljs/athens/views/athena.cljs +++ b/src/cljs/athens/views/athena.cljs @@ -1,17 +1,17 @@ (ns athens.views.athena (:require - ["/components/Icons/Icons" :refer [XmarkIcon]] - ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] - [athens.common.utils :as utils] - [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] - [athens.router :as router] - [athens.subs] - [athens.util :refer [scroll-into-view]] - [clojure.string :as str] - [goog.dom :refer [getElement]] - [goog.events :as events] - [re-frame.core :as rf :refer [subscribe dispatch]] - [reagent.core :as r]) + ["/components/Icons/Icons" :refer [XmarkIcon]] + ["@chakra-ui/react" :refer [Modal ModalContent ModalOverlay VStack Button IconButton Input HStack Heading Text]] + [athens.common.utils :as utils] + [athens.db :as db :refer [search-in-block-content search-exact-node-title search-in-node-title re-case-insensitive]] + [athens.router :as router] + [athens.subs] + [athens.util :refer [scroll-into-view]] + [clojure.string :as str] + [goog.dom :refer [getElement]] + [goog.events :as events] + [re-frame.core :as rf :refer [subscribe dispatch]] + [reagent.core :as r]) (:import (goog.events KeyCodes))) diff --git a/src/cljs/athens/views/pages/block_page.cljs b/src/cljs/athens/views/pages/block_page.cljs index a353810f0f..7f0abd2e3a 100644 --- a/src/cljs/athens/views/pages/block_page.cljs +++ b/src/cljs/athens/views/pages/block_page.cljs @@ -1,16 +1,16 @@ (ns athens.views.pages.block-page (:require - ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] - ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] - [athens.parse-renderer :as parse-renderer] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.views.blocks.core :as blocks] - [athens.views.pages.node-page :as node-page] - [athens.views.references :refer [reference-group reference-block]] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] + ["@chakra-ui/react" :refer [Breadcrumb BreadcrumbItem BreadcrumbLink VStack AccordionIcon Accordion AccordionItem AccordionButton AccordionPanel]] + [athens.parse-renderer :as parse-renderer] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.views.blocks.core :as blocks] + [athens.views.pages.node-page :as node-page] + [athens.views.references :refer [reference-group reference-block]] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Helpers @@ -106,7 +106,7 @@ ;; Header [:> PageHeader - ;; Parent Context + ;; Parent Context [parents-el uid id] [:> EditableTitleContainer {:onClick (fn [e] (.. e preventDefault) diff --git a/src/cljs/athens/views/pages/daily_notes.cljs b/src/cljs/athens/views/pages/daily_notes.cljs index f5378d62c0..87222c3373 100644 --- a/src/cljs/athens/views/pages/daily_notes.cljs +++ b/src/cljs/athens/views/pages/daily_notes.cljs @@ -1,11 +1,11 @@ (ns athens.views.pages.daily-notes (:require - ["/components/Page/Page" :refer [PageHeader TitleContainer DailyNotesPage]] - ["@chakra-ui/react" :refer [VStack]] - [athens.dates :as dates] - [athens.reactive :as reactive] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]])) + ["/components/Page/Page" :refer [PageHeader TitleContainer DailyNotesPage]] + ["@chakra-ui/react" :refer [VStack]] + [athens.dates :as dates] + [athens.reactive :as reactive] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]])) (defn reactive-pull-many @@ -37,10 +37,10 @@ :flex "1 1 100%" :flexDirection "column"} (doall - (for [{:keys [block/uid]} notes] - [:> DailyNotesPage {:key uid - :isReal true} - [node-page/page [:block/uid uid]]])) + (for [{:keys [block/uid]} notes] + [:> DailyNotesPage {:key uid + :isReal true} + [node-page/page [:block/uid uid]]])) [:> DailyNotesPage {:isReal false} [:> PageHeader [:> TitleContainer "Earlier"]]]]))))) diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index ee03f218f7..d27fea074e 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -1,32 +1,32 @@ (ns athens.views.pages.node-page (:require - ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Dialog/Dialog" :refer [Dialog]] - ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] - ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] - ["@material-ui/icons/Bookmark" :default Bookmark] - ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] - ["@material-ui/icons/BubbleChart" :default BubbleChart] - ["@material-ui/icons/Delete" :default Delete] - ["@material-ui/icons/MoreHoriz" :default MoreHoriz] - [athens.common-db :as common-db] - [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] - [athens.common.utils :as utils] - [athens.dates :as dates] - [athens.db :as db :refer [get-unlinked-references]] - [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] - [athens.reactive :as reactive] - [athens.router :as router] - [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] - [athens.views.blocks.core :as blocks] - [athens.views.blocks.textarea-keydown :as textarea-keydown] - [athens.views.hoc.perf-mon :as perf-mon] - [athens.views.references :refer [reference-group reference-block]] - [clojure.string :as str] - [datascript.core :as d] - [komponentit.autosize :as autosize] - [re-frame.core :as rf :refer [dispatch subscribe]] - [reagent.core :as r]) + ["/components/Block/components/Anchor" :refer [Anchor]] + ["/components/Dialog/Dialog" :refer [Dialog]] + ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] + ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] + ["@material-ui/icons/Bookmark" :default Bookmark] + ["@material-ui/icons/BookmarkBorder" :default BookmarkBorder] + ["@material-ui/icons/BubbleChart" :default BubbleChart] + ["@material-ui/icons/Delete" :default Delete] + ["@material-ui/icons/MoreHoriz" :default MoreHoriz] + [athens.common-db :as common-db] + [athens.common.sentry :refer-macros [wrap-span-no-new-tx]] + [athens.common.utils :as utils] + [athens.dates :as dates] + [athens.db :as db :refer [get-unlinked-references]] + [athens.parse-renderer :as parse-renderer :refer [parse-and-render]] + [athens.reactive :as reactive] + [athens.router :as router] + [athens.util :refer [escape-str get-caret-position recursively-modify-block-for-embed]] + [athens.views.blocks.core :as blocks] + [athens.views.blocks.textarea-keydown :as textarea-keydown] + [athens.views.hoc.perf-mon :as perf-mon] + [athens.views.references :refer [reference-group reference-block]] + [clojure.string :as str] + [datascript.core :as d] + [komponentit.autosize :as autosize] + [re-frame.core :as rf :refer [dispatch subscribe]] + [reagent.core :as r]) (:import (goog.events KeyCodes))) @@ -433,32 +433,32 @@ :onDismiss cancel-fn}]) ;; Header - [:> PageHeader + [:> PageHeader ;; Dropdown - [menu-dropdown node daily-note?] + [menu-dropdown node daily-note?] - [:> EditableTitleContainer + [:> EditableTitleContainer ;; Prevent editable textarea if a node/title is a date ;; Don't allow title editing from daily notes, right sidebar, or node-page itself. - (when-not daily-note? - [autosize/textarea - {:value (:title/local @state) - :id (str "editable-uid-" uid) - :class (when @(subscribe [:editing/is-editing uid]) "is-editing") - :on-blur (fn [_] + (when-not daily-note? + [autosize/textarea + {:value (:title/local @state) + :id (str "editable-uid-" uid) + :class (when @(subscribe [:editing/is-editing uid]) "is-editing") + :on-blur (fn [_] ;; add title Untitled-n for empty titles - (when (empty? (:title/local @state)) - (swap! state assoc :title/local (auto-inc-untitled))) - (handle-blur node state)) - :on-key-down (fn [e] (handle-key-down e uid state children)) - :on-change (fn [e] (handle-change e state))}]) + (when (empty? (:title/local @state)) + (swap! state assoc :title/local (auto-inc-untitled))) + (handle-blur node state)) + :on-key-down (fn [e] (handle-key-down e uid state children)) + :on-change (fn [e] (handle-change e state))}]) ;; empty word break to keep span on full height else it will collapse to 0 height (weird ui) - (if (str/blank? (:title/local @state)) - [:wbr] - [perf-mon/hoc-perfmon {:span-name "parse-and-render"} - [parse-renderer/parse-and-render (:title/local @state) uid]])]] + (if (str/blank? (:title/local @state)) + [:wbr] + [perf-mon/hoc-perfmon {:span-name "parse-and-render"} + [parse-renderer/parse-and-render (:title/local @state) uid]])]] [:> PageBody diff --git a/src/cljs/athens/views/pages/page.cljs b/src/cljs/athens/views/pages/page.cljs index af5d6b6d6e..7146879b95 100644 --- a/src/cljs/athens/views/pages/page.cljs +++ b/src/cljs/athens/views/pages/page.cljs @@ -1,12 +1,12 @@ (ns athens.views.pages.page (:require - ["/components/Page/Page" :refer [PageContainer]] - [athens.common-db :as common-db] - [athens.db :as db] - [athens.reactive :as reactive] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.node-page :as node-page] - [re-frame.core :as rf])) + ["/components/Page/Page" :refer [PageContainer]] + [athens.common-db :as common-db] + [athens.db :as db] + [athens.reactive :as reactive] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.node-page :as node-page] + [re-frame.core :as rf])) (defn page-by-title diff --git a/src/cljs/athens/views/right_sidebar.cljs b/src/cljs/athens/views/right_sidebar.cljs index 6cf2ef53c1..b2ffd29143 100644 --- a/src/cljs/athens/views/right_sidebar.cljs +++ b/src/cljs/athens/views/right_sidebar.cljs @@ -1,15 +1,14 @@ (ns athens.views.right-sidebar (:require - ["/components/Layout/Layout" :refer [RightSidebarContainer]] - ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon]] - ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] - ["framer-motion" :refer [AnimatePresence motion]] - [athens.parse-renderer :as parse-renderer] - [athens.views.pages.block-page :as block-page] - [athens.views.pages.graph :as graph] - [athens.views.pages.node-page :as node-page] - [re-frame.core :refer [dispatch subscribe]] - [reagent.core :as r])) + ["/components/Icons/Icons" :refer [RightSidebarAddIcon XmarkIcon]] + ["/components/Layout/Layout" :refer [RightSidebarContainer]] + ["@chakra-ui/react" :refer [Flex Text Box IconButton Accordion AccordionItem AccordionButton AccordionIcon AccordionPanel]] + [athens.parse-renderer :as parse-renderer] + [athens.views.pages.block-page :as block-page] + [athens.views.pages.graph :as graph] + [athens.views.pages.node-page :as node-page] + [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r])) ;; Components @@ -94,43 +93,43 @@ [empty-message] [:> Accordion {:allowMultiple true} (doall - (for [[uid {:keys [node/title block/string is-graph?]}] items] - ^{:key uid} - [:> AccordionItem {:borderWidth 0 - :borderColor "separator.divider" - :borderBottomWidth "1px"} - [:> Box {:as "h2" :position "relative"} - [:> AccordionButton {:borderRadius "0" - :py 4 - :pl 3 - :pr 4 - :height "auto" - :textAlign "left" - :overflow "hidden" - :whiteSpace "nowrap" - :border 0} - [:> AccordionIcon] - [:> Box {:flex "1 1 100%" - :mx 3 - :tabIndex -1 - :pointerEvents "none" - :position "relative" - :bottom "1px" - :overflow "hidden" - :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] - [:> IconButton {:size "sm" - :position "absolute" - :color "foreground.secondary" - :right 5 - :top 3 - :background "transparent" - :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} - [:> XmarkIcon]]] - [:> AccordionPanel {:p 4} - (cond - is-graph? [graph/page uid] - title [node-page/page [:block/uid uid]] - :else [block-page/page [:block/uid uid]])]]))])]])}))) + (for [[uid {:keys [node/title block/string is-graph?]}] items] + ^{:key uid} + [:> AccordionItem {:borderWidth 0 + :borderColor "separator.divider" + :borderBottomWidth "1px"} + [:> Box {:as "h2" :position "relative"} + [:> AccordionButton {:borderRadius "0" + :py 4 + :pl 3 + :pr 4 + :height "auto" + :textAlign "left" + :overflow "hidden" + :whiteSpace "nowrap" + :border 0} + [:> AccordionIcon] + [:> Box {:flex "1 1 100%" + :mx 3 + :tabIndex -1 + :pointerEvents "none" + :position "relative" + :bottom "1px" + :overflow "hidden" + :sx {:maskImage "linear-gradient(to right, black, black calc(100% - 4rem), transparent calc(100% - 2rem))"}} [parse-renderer/parse-and-render (or title string) uid]]] + [:> IconButton {:size "sm" + :position "absolute" + :color "foreground.secondary" + :right 5 + :top 3 + :background "transparent" + :onClick #(dispatch [:right-sidebar/XmarkIcon-item uid])} + [:> XmarkIcon]]] + [:> AccordionPanel {:p 4} + (cond + is-graph? [graph/page uid] + title [node-page/page [:block/uid uid]] + :else [block-page/page [:block/uid uid]])]]))])]])}))) (defn right-sidebar From d38f45953aec958e7194ad8d6a26346be4d57f89 Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 31 Mar 2022 21:27:52 -0400 Subject: [PATCH 42/79] fix: titlebar border transitions nicely --- src/js/components/AppToolbar/AppToolbar.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index d6306725bc..2f902fff9e 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -83,7 +83,8 @@ const AppToolbarWrapper = ({ children, ...props }) => Date: Thu, 31 Mar 2022 21:28:41 -0400 Subject: [PATCH 43/79] rfct: use chakra for block content element --- src/cljs/athens/views/blocks/content.cljs | 106 +------------- .../components/Block/components/Content.tsx | 133 ++++++++++++++++++ .../components/DetailPopover.stories.tsx | 23 --- .../Block/components/DetailPopover.tsx | 77 ---------- 4 files changed, 136 insertions(+), 203 deletions(-) create mode 100644 src/js/components/Block/components/Content.tsx delete mode 100644 src/js/components/Block/components/DetailPopover.stories.tsx delete mode 100644 src/js/components/Block/components/DetailPopover.tsx diff --git a/src/cljs/athens/views/blocks/content.cljs b/src/cljs/athens/views/blocks/content.cljs index eb14b84571..6cf3a656e7 100644 --- a/src/cljs/athens/views/blocks/content.cljs +++ b/src/cljs/athens/views/blocks/content.cljs @@ -1,6 +1,6 @@ (ns athens.views.blocks.content (:require - ["@chakra-ui/react" :refer [Box]] + ["/components/Block/components/Content" :refer [Content]] [athens.config :as config] [athens.db :as db] [athens.events.selection :as select-events] @@ -20,93 +20,6 @@ EventType))) -;; Styles - - -(def block-inner-content-style - {"textarea" {:display "block" - :lineHeight 0 - :appearance "none" - :cursor "text" - :resize "none" - :transform "translate3d(0,0,0)" - :color "inherit" - :outline "none" - :overflow "hidden" - :padding "0" - :background "var(--block-surface-color)" - :grid-area "main" - :min-height "100%" - :margin "0" - :font-size "inherit" - :border-radius "0.25rem" - :border "0" - :opacity "0" - :font-family "inherit"} - "&:hover textarea:not(.is-editing)" {:lineHeight "2"} - "textarea.is-editing + *" {:opacity "0"} - ".is-editing" {:zIndex 3 - :lineHeight "inherit" - :opacity 1} - "span.text-run" {:pointerEvents "none" - "& > a" {:position "relative" - :zIndex 2 - :pointerEvents "all"}} - "span" {:gridArea "main" - "& > span" {:position "relative" - :zIndex 2}} - "abbr" {:gridArea "main" - :zIndex 4 - "& > span" {:position "relative" - :zIndex 2}} - "code, pre" {:fontFamily "code" - :fontSize "0.85em"} - ".media-16-9" {:height 0 - :width "calc(100% - 0.25rem)" - :zIndex 1 - :transformOrigin "right center" - :transitionDuration "0.2s" - :transitionTimingFunction "ease-in-out" - :transitionProperty "common" - :paddingBottom "56.25%" - :marginBlock "0.25rem" - :marginInlineEnd "0.25rem" - :position "relative"} - "iframe" {:border 0 - :boxShadow "inset 0 0 0 0.125rem" - :position "absolute" - :height "100%" - :width "100%" - :cursor "default" - :top 0 - :right 0 - :left 0 - :bottom 0 - :borderRadius "0.25rem"} - "img" {:borderRadius "0.25rem" - :maxWidth "calc(100% - 0.25rem)"} - "h1" {:fontSize "xl"} - "h2" {:fontSize "lg"} - "h3" {:fontSize "md"} - "h4" {:fontSize "sm"} - "h5" {:fontSize "xs"} - "h6" {:fontSize "xs"} - "blockquote" {:marginInline "0.5em" - :marginBlock "0.125rem" - :paddingBlock "calc(0.5em - 0.125rem - 0.125rem)" - :paddingInline "1.5em" - :borderRadius "0.25em" - :background "background.basement" - :borderInlineStart "1px solid" - :borderColor "separator.divider" - :color "foreground.primary"} - "p" {:paddingBottom "1em" - "&:last-child" {:paddingBottom 0}} - "mark.contents.highlight" {:padding "0 0.2em" - :borderRadius "0.125rem" - :background "highlight"}}) - - (defn find-selected-items "Used by both shift-click and click-drag for multi-block-selection. Given a mouse event, a source block, and a target block, highlight blocks. @@ -325,21 +238,8 @@ 2 "1.7em" 3 "1.3em" "1em")] - [:> Box {:class "block-content" - :display "grid" - :background "var(--block-surface-color)" - :color "foreground.primary" - :gridTemplateAreas "'main'" - :alignItems "stretch" - :justifyContent "stretch" - :position "relative" - :overflow "visible" - :zIndex 2 - :flexGrow 1 - :wordBreak "break-word" - :fontSize font-size - :sx block-inner-content-style - :on-click (fn [e] (.. e stopPropagation) (rf/dispatch [:editing/uid uid]))} + [:> Content {:fontSize font-size + :on-click (fn [e] (.. e stopPropagation) (rf/dispatch [:editing/uid uid]))} ;; NOTE: komponentit forces reflow, likely a performance bottle neck ;; When block is in editing mode or the editing DOM elements are rendered (when (or (:show-editable-dom @state) @editing?) diff --git a/src/js/components/Block/components/Content.tsx b/src/js/components/Block/components/Content.tsx new file mode 100644 index 0000000000..08251b609f --- /dev/null +++ b/src/js/components/Block/components/Content.tsx @@ -0,0 +1,133 @@ +import { Box } from '@chakra-ui/react'; + +export const Content = ({ children, fontSize }) => { + return a": { + position: "relative", + zIndex: 2, + pointerEvents: "all", + } + }, + "span": { + gridArea: "main", + "& > span": { + position: "relative", + zIndex: 2, + } + }, + "abbr": { + gridArea: "main", + zIndex: 4, + "& > span": { + position: "relative", + zIndex: 2, + } + }, + "code, pre": { + fontFamily: "code", + fontSize: "0.85em", + }, + ".media-16-9": { + height: 0, + width: "calc(100% - 0.25rem)", + zIndex: 1, + transformOrigin: "right center", + transitionDuration: "0.2s", + transitionTimingFunction: "ease-in-out", + transitionProperty: "common", + paddingBottom: "56.25%", + marginBlock: "0.25rem", + marginInlineEnd: "0.25rem", + position: "relative", + }, + "iframe": { + border: 0, + boxShadow: "inset 0 0 0 0.125rem", + position: "absolute", + height: "100%", + width: "100%", + cursor: "default", + top: 0, + right: 0, + left: 0, + bottom: 0, + borderRadius: "0.25rem", + }, + "img": { + borderRadius: "0.25rem", + maxWidth: "calc(100% - 0.25rem)", + }, + "h1": { fontSize: "xl" }, + "h2": { fontSize: "lg" }, + "h3": { fontSize: "md" }, + "h4": { fontSize: "sm" }, + "h5": { fontSize: "xs" }, + "h6": { fontSize: "xs" }, + "blockquote": { + marginInline: "0.5em", + marginBlock: "0.125rem", + paddingBlock: "calc(0.5em - 0.125rem - 0.125rem)", + paddingInline: "1.5em", + borderRadius: "0.25em", + background: "background.basement", + borderInlineStart: "1px solid", + borderColor: "separator.divider", + color: "foreground.primary", + }, + "p": { + paddingBottom: "1em", + "&last:-child": { paddingBottom: 0 }, + }, + "mark.contents.highlight": { + padding: "0 0.2em", + borderRadius: "0.125rem", + background: "highlight", + } + } + } + > {children} +} \ No newline at end of file diff --git a/src/js/components/Block/components/DetailPopover.stories.tsx b/src/js/components/Block/components/DetailPopover.stories.tsx deleted file mode 100644 index f57043b3ea..0000000000 --- a/src/js/components/Block/components/DetailPopover.stories.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { DetailPopover } from './DetailPopover'; -import { BADGE, Storybook } from '@/utils/storybook'; - -export default { - title: 'components/DetailPopover', - component: DetailPopover, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV] - }, - decorators: [(Story) => ] -}; - -export const Typical = () => ; diff --git a/src/js/components/Block/components/DetailPopover.tsx b/src/js/components/Block/components/DetailPopover.tsx deleted file mode 100644 index e56a1dd775..0000000000 --- a/src/js/components/Block/components/DetailPopover.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { TooltipTriggerState } from '@react-stately/tooltip'; -import { useTooltip } from '@react-aria/tooltip'; - -import { Overlay } from '@/Overlay'; - -const Details = styled(Overlay)` - height: max-content; - width: max-content; - display: flex; - flex-direction: column; - list-style: none; - margin: 0; - padding: 0.25rem 0.5rem; - font-size: var(--font-size--text-sm); - gap: -0.125rem; - position: relative; - top: 0.25rem; - left: 2.5rem; - z-index: 9999; - line-height: 1.3; -`; - -const Item = styled.li` - margin: 0; - padding: 0; - display: flex; - justify-content: space-between; - - span { - color: var(--body-text-color---opacity-med); - flex: 1 1 50%; - } - span + span { - margin-left: 1ch; - color: var(--body-text-color); - } -`; - -const showValue = (value) => { - if (typeof value === 'object') return (value = JSON.stringify(value)); - else if (typeof value === 'boolean') return (value = value ? 'true' : 'false'); - else return value; -} - -interface DetailPopoverProps extends React.HTMLAttributes { - state: TooltipTriggerState; - block: any; -} - -export const DetailPopover = React.forwardRef((props: DetailPopoverProps, ref) => { - const { block, state, } = props; - let { tooltipProps } = useTooltip(props, state); - - const properties = { - "uid": block.uid, - "db/id": block.id, - "order": block.order, - "open": block.open, - "refs": block._refs?.length || 0, - } - - return ( -
{ e.stopPropagation(); }} - onClick={(e) => { e.stopPropagation(); }} - > - {Object.entries(properties).map(([key, value]) => - {key} {showValue(value)} - )} -
- ); -}); From f0f3a52459237079a03c059a7c855f2d85fb6b2a Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 31 Mar 2022 21:34:33 -0400 Subject: [PATCH 44/79] rfct: retire most storybook components --- src/js/components/Avatar/Avatar.stories.tsx | 109 ------- src/js/components/Avatar/Avatar.tsx | 280 ------------------ src/js/components/Avatar/index.ts | 2 - src/js/components/Avatar/mockData.ts | 98 ------ src/js/components/BrowserApp.stories.tsx | 230 -------------- src/js/components/Button/Button.stories.tsx | 119 -------- src/js/components/Button/Button.tsx | 193 ------------ src/js/components/Button/index.ts | 2 - src/js/components/Design.stories.tsx | 160 ---------- src/js/components/Dialog/Dialog.stories.tsx | 36 --- src/js/components/Dialog/Dialog.tsx | 189 ------------ src/js/components/Dialog/index.ts | 2 - .../Icons/ConnectedGraphConnection.tsx | 7 - .../components/Icons/ConnectedGraphHost.tsx | 10 - src/js/components/Icons/Icon.tsx | 31 -- src/js/components/Icons/X.tsx | 1 - src/js/components/Input/Input.stories.tsx | 76 ----- src/js/components/Input/Input.tsx | 131 -------- src/js/components/Input/index.ts | 2 - src/js/components/Link/Link.stories.tsx | 18 -- src/js/components/Link/Link.ts | 37 --- src/js/components/Link/index.ts | 2 - src/js/components/Menu/Menu.stories.tsx | 54 ---- src/js/components/Menu/Menu.ts | 55 ---- src/js/components/Menu/hooks/useMenu.ts | 79 ----- src/js/components/Menu/index.ts | 2 - .../Notifications/Notification.stories.tsx | 99 ------- .../Notifications/Notifications.tsx | 18 -- .../components/NotificationContainer.tsx | 22 -- .../components/NotificationItem.tsx | 142 --------- src/js/components/Overlay/Backdrop.ts | 14 - src/js/components/Overlay/Overlay.stories.tsx | 63 ---- src/js/components/Overlay/Overlay.ts | 56 ---- src/js/components/Overlay/index.ts | 2 - src/js/components/Page/Page.tsx | 2 +- src/js/components/Spinner/Spinner.stories.tsx | 51 ---- src/js/components/Spinner/Spinner.tsx | 88 ------ .../Spinner/components/Indeterminate.tsx | 24 -- src/js/components/Spinner/index.ts | 2 - src/js/components/StandaloneApp.stories.tsx | 254 ---------------- src/js/components/Toggle/Toggle.stories.tsx | 41 --- src/js/components/Toggle/Toggle.tsx | 189 ------------ src/js/components/Toggle/index.ts | 2 - src/js/components/utils/classnames.ts | 1 - src/js/components/utils/config.ts | 4 - src/js/components/utils/data/People.ts | 98 ------ .../components/utils/data/PeoplePresence.ts | 3 - src/js/components/utils/getOs.ts | 9 - src/js/components/utils/interfaces.ts | 97 ------ src/js/components/utils/storybook.ts | 79 ----- src/js/components/utils/useAppState.ts | 100 ------- src/js/components/utils/useFocusRingEl.tsx | 70 ----- 52 files changed, 1 insertion(+), 3454 deletions(-) delete mode 100644 src/js/components/Avatar/Avatar.stories.tsx delete mode 100644 src/js/components/Avatar/Avatar.tsx delete mode 100644 src/js/components/Avatar/index.ts delete mode 100644 src/js/components/Avatar/mockData.ts delete mode 100644 src/js/components/BrowserApp.stories.tsx delete mode 100644 src/js/components/Button/Button.stories.tsx delete mode 100644 src/js/components/Button/Button.tsx delete mode 100644 src/js/components/Button/index.ts delete mode 100644 src/js/components/Design.stories.tsx delete mode 100644 src/js/components/Dialog/Dialog.stories.tsx delete mode 100644 src/js/components/Dialog/Dialog.tsx delete mode 100644 src/js/components/Dialog/index.ts delete mode 100644 src/js/components/Icons/ConnectedGraphConnection.tsx delete mode 100644 src/js/components/Icons/ConnectedGraphHost.tsx delete mode 100644 src/js/components/Icons/Icon.tsx delete mode 100644 src/js/components/Icons/X.tsx delete mode 100644 src/js/components/Input/Input.stories.tsx delete mode 100644 src/js/components/Input/Input.tsx delete mode 100644 src/js/components/Input/index.ts delete mode 100644 src/js/components/Link/Link.stories.tsx delete mode 100644 src/js/components/Link/Link.ts delete mode 100644 src/js/components/Link/index.ts delete mode 100644 src/js/components/Menu/Menu.stories.tsx delete mode 100644 src/js/components/Menu/Menu.ts delete mode 100644 src/js/components/Menu/hooks/useMenu.ts delete mode 100644 src/js/components/Menu/index.ts delete mode 100644 src/js/components/Notifications/Notification.stories.tsx delete mode 100644 src/js/components/Notifications/Notifications.tsx delete mode 100644 src/js/components/Notifications/components/NotificationContainer.tsx delete mode 100644 src/js/components/Notifications/components/NotificationItem.tsx delete mode 100644 src/js/components/Overlay/Backdrop.ts delete mode 100644 src/js/components/Overlay/Overlay.stories.tsx delete mode 100644 src/js/components/Overlay/Overlay.ts delete mode 100644 src/js/components/Overlay/index.ts delete mode 100644 src/js/components/Spinner/Spinner.stories.tsx delete mode 100644 src/js/components/Spinner/Spinner.tsx delete mode 100644 src/js/components/Spinner/components/Indeterminate.tsx delete mode 100644 src/js/components/Spinner/index.ts delete mode 100644 src/js/components/StandaloneApp.stories.tsx delete mode 100644 src/js/components/Toggle/Toggle.stories.tsx delete mode 100644 src/js/components/Toggle/Toggle.tsx delete mode 100644 src/js/components/Toggle/index.ts delete mode 100644 src/js/components/utils/classnames.ts delete mode 100644 src/js/components/utils/config.ts delete mode 100644 src/js/components/utils/data/People.ts delete mode 100644 src/js/components/utils/data/PeoplePresence.ts delete mode 100644 src/js/components/utils/getOs.ts delete mode 100644 src/js/components/utils/interfaces.ts delete mode 100644 src/js/components/utils/storybook.ts delete mode 100644 src/js/components/utils/useAppState.ts delete mode 100644 src/js/components/utils/useFocusRingEl.tsx diff --git a/src/js/components/Avatar/Avatar.stories.tsx b/src/js/components/Avatar/Avatar.stories.tsx deleted file mode 100644 index f9194f69eb..0000000000 --- a/src/js/components/Avatar/Avatar.stories.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { Avatar } from './Avatar'; -import styled from 'styled-components'; -import { BADGE, Storybook } from '@/utils/storybook'; -import { WithPresence } from '@/concept/Block/Block.stories'; -import { Block } from '@/concept/Block'; - -const Wrapper = styled(Storybook.Wrapper)` - display: flex; - gap: 1rem; -`; - -// Helpers - -export default { - title: 'Components/Avatar', - component: Avatar, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV] - }, - decorators: [(Story) => ] -}; - -// Stories - -const Template = (args) => ; - -export const Basic = Template.bind({}); -Basic.args = { - username: 'Jeff Tang', - size: "3rem", - color: '#0000f7', -}; - -export const WithTooltip = () => ( -
- - - - -
-) - -export const Sizes = () => ( -
- - - - -
-) - -export const Colors = () => ( - <> - - - - - - - -) - -export const isMuted = () => ( - <> - - - - - - - -) - -export const Stack = () => ( - - - - - - - - -) - -export const StackNarrow = () => ( - - - - - - - - -) -export const StackWide = () => ( - - - - - - - - -) - -export const OnBlocks = WithPresence; -OnBlocks.decorators = [(Story) => ]; \ No newline at end of file diff --git a/src/js/components/Avatar/Avatar.tsx b/src/js/components/Avatar/Avatar.tsx deleted file mode 100644 index 4a2054be8a..0000000000 --- a/src/js/components/Avatar/Avatar.tsx +++ /dev/null @@ -1,280 +0,0 @@ -import React from "react"; -import styled, { css } from "styled-components"; -import { Fade, Popper, PopperPlacementType } from "@material-ui/core"; -import { readableColor } from "polished"; - -import { DOMRoot } from "@/utils/config"; - -const Wrapper = styled.svg` - overflow: visible; - cursor: default; - border-radius: 100%; - height: var(--size, 1.5em); - width: var(--size, 1.5em); -`; - -const Name = styled.text` - text-anchor: middle; - color: var(--avatar-text-color); - transform: scale(0.8); - transform-origin: center; -`; - -const FullName = styled.span` - background: var(--tooltip-background-color); - color: var(--tooltip-text-color); - display: inline-flex; - width: max-content; - line-height: 1; - padding: 0.2em 0.5em; - border-radius: 0.2em; - margin: 0.25rem; - pointer-events: none; -`; - -export interface AvatarProps extends React.SVGProps, Person { - /** - * The primary color of the icon - */ - color: string; - /** - * The full username of the person - */ - username: string; - /** - * Height and width of the avatar - */ - size?: string; - /** - * Whether to display the avatar in a muted visual style - */ - isMuted?: boolean; - /** - * Whether to show the user's full name. Set to 'hover' to show it when interacting with the icon. - */ - showTooltip?: boolean | "hover"; - /** - * Where the tooltip should appear relative to the icon. - */ - tooltipPlacement?: PopperPlacementType; - /** - * Whether to draw a colored circle around the icon. - */ - isOutlined?: boolean -} - -/** - * Visual representation of a human user - */ -export const Avatar = ({ - username, - color, - showTooltip = "hover", - tooltipPlacement = "right", - isMuted = false, - size, - isOutlined, - ...props -}: AvatarProps) => { - const [avatarEl, setAvatarEl] = React.useState(); - const [isShowingTooltip, setIsShowingTooltip] = React.useState( - showTooltip === "hover" ? false : showTooltip - ); - - const avatarColors = { - "--avatar-background-opacity": isMuted ? 0.2 : 1, - "--avatar-background-color": color, - "--avatar-text-color": isMuted ? color : readableColor(color), - "--tooltip-text-color": readableColor(color), - "--tooltip-background-color": color, - }; - - let initials; - if (username) { - initials = username - .split(" ") - .map((word) => word[0]) - .join("") - .slice(0, 2) - .toUpperCase(); - } - - return ( - <> - { - if (showTooltip === "hover") setIsShowingTooltip(true); - }} - onMouseLeave={() => { - if (showTooltip === "hover") setIsShowingTooltip(false); - }} - {...props} - style={{ ...avatarColors, "--size": size, ...props.style }} - > - - - {initials || username} - - {isOutlined && ( - - )} - - - {({ TransitionProps }) => ( - - - {username} - - - )} - - - ); -}; - -/* - * Wraps a horizontal series of avatars and causes them to overlap each other. - */ -interface AvatarStackProps extends React.HTMLAttributes { - children: JSX.Element[]; - /** - * The width of the mask added to overlapping Avatars. - */ - limit?: number; - /** - * The width of the mask added to overlapping Avatars. - */ - maskSize?: string; - /** - * The size of Avatars. Can be overridden by the same property on child Avatars. - */ - stackOrder?: "from-left" | "from-right"; - /** - * How much Avatars should overlap. 0.5 is 50% overlap. - */ - size?: string; - /** - * How much Avatars should overlap. 0.5 is 50% overlap. - */ - overlap?: number; -} - -const StackWrapper = styled.div` - --mask-size: ${(props) => props.maskSize || "3px"}; - --size: ${(props) => props.size || undefined}; - --stack-overlap: ${(props) => props.overlap || "0.5"}; - display: inline-flex; - align-items: center; - width: max-content; - height: max-content; - border-radius: 100em; - - ${Wrapper} { - ${(props) => - props.stackOrder === `from-left` - ? css` - &:not(:last-of-type) { - margin-inline-end: calc( - var(--size, 1.5em) * (var(--stack-overlap) * -1) - ); - mask-image: radial-gradient( - calc(var(--size, 1.5em) + var(--mask-size)) - calc((var(--size, 1.5em) * (2 / 3)) + var(--mask-size)) at - calc(100% + (100% * (var(--stack-overlap)))) 50%, - transparent 99%, - #000 100% - ); - } - ` - : css` - &:not(:first-of-type) { - margin-inline-start: calc( - var(--size, 1.5em) * (var(--stack-overlap) * -1) - ); - mask-image: radial-gradient( - calc(var(--size, 1.5em) + var(--mask-size)) - calc((var(--size, 1.5em) * (2 / 3)) + var(--mask-size)) at - calc(-100% + (100% * (var(--stack-overlap)))) 50%, - transparent 99%, - #000 100% - ); - } - `} - } -`; - -Avatar.Stack = React.forwardRef((props: AvatarStackProps, ref) => { - const { - children, - limit = Infinity, - size, - maskSize = "3px", - overlap = 0.5, - stackOrder = "from-right", - style, - ...rest - } = props; - - let Children = React.Children.toArray(children); - let overflow = Children.length - limit; - - return ( - - {Children.slice(0, limit).map((avatar: JSX.Element) => React.cloneElement(avatar, { size }))} - {overflow > 0 && ( - - )} - - ); -}); - -Avatar.Wrapper = Wrapper; -Avatar.Fullname = FullName; -Avatar.Name = Name; diff --git a/src/js/components/Avatar/index.ts b/src/js/components/Avatar/index.ts deleted file mode 100644 index 379dda34bf..0000000000 --- a/src/js/components/Avatar/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Avatar } from './Avatar'; -export { Avatar } \ No newline at end of file diff --git a/src/js/components/Avatar/mockData.ts b/src/js/components/Avatar/mockData.ts deleted file mode 100644 index 9cbc800044..0000000000 --- a/src/js/components/Avatar/mockData.ts +++ /dev/null @@ -1,98 +0,0 @@ -export const mockPeople = - [{ - username: "oorgen0", - personId: "5058615e-b5ce-4e48-9a70-1bb48079883f", - color: "#accb85" - }, { - username: "pcanepe1", - personId: "a22896b5-0cc0-40de-ae64-7105106beb6a", - color: "#12b47e" - }, { - username: "jthorrold2", - personId: "54f83c31-ac3b-412c-b02a-794db3cbff1d", - color: "#c542ed" - }, { - username: "afick3", - personId: "2bb8342d-e276-4333-8bc8-01201adf7778", - color: "#7920ef" - }, { - username: "nhannah4", - personId: "3c48194e-6506-402f-a17b-e979b3ae6026", - color: "#980e37" - }, { - username: "dmcentegart5", - personId: "648994a7-4970-4418-85f5-6710872e4dd2", - color: "#3d53cb" - }, { - username: "tclimar6", - personId: "62201231-bcdd-4b91-9d7e-d3869bfa8c5f", - color: "#594977" - }, { - username: "gchivrall7", - personId: "fd37b6e2-1b9d-4bbd-898c-fc4981835a59", - color: "#4fff47" - }, { - username: "dthomel8", - personId: "f452b384-79e3-4850-b077-770155cbf5ee", - color: "#8e9c1a" - }, { - username: "blinfoot9", - personId: "c547ffaf-63cb-4c45-b8b4-517c46c8eaa5", - color: "#696cf2" - }, { - username: "phardsona", - personId: "390cc8be-0b09-41e5-afa5-341dc69f03c4", - color: "#b33a7c" - }, { - username: "cdowneb", - personId: "dd4a68be-1a92-4afe-856c-7dc4ec4b58b4", - color: "#0f5dfe" - }, { - username: "ahortopc", - personId: "41a06c67-eb68-465c-8190-93a2c9a20875", - color: "#e8487d" - }, { - username: "osuthereld", - personId: "63d40d9a-1615-44c7-aa3b-9a910cc1aabb", - color: "#4f0d1a" - }, { - username: "mgrimblebye", - personId: "e0357779-edf2-490e-9a43-c4918d204e3b", - color: "#77b002" - }, { - username: "ccoochf", - personId: "3d2efbf6-3f43-4fa8-9136-b9d1fb7b7615", - color: "#803b68" - }, { - username: "anasseyg", - personId: "184ffca6-8acb-41cb-ae0e-9683dc234cc7", - color: "#3250c9" - }, { - username: "slasselleh", - personId: "a590cf82-2d5b-49a6-a625-cb2d98022a3c", - color: "#257179" - }, { - username: "ilerouxi", - personId: "aaccec70-7b66-40fe-8186-cbf5660282e7", - color: "#096908" - }, { - username: "fdransfieldj", - personId: "769e3b69-7270-43fc-b3fd-0c5401a352c8", - color: "#e75898" - }, { - username: "dsteinhamk", - personId: "ab64c0e7-4d2d-415d-8b14-6996d363bf10", - color: "#dee1fd" - }, { - username: "glouisetl", - personId: "2886b735-2104-4715-a717-e7041462d507", - color: "#b52850" - }, { - username: "jprozesckym", - personId: "ee321686-ad80-4796-b640-008a3fcb88e8", - color: "#228c57" - }, { - username: "pdrucen", - personId: "beb6085e-1437-438a-a1d6-933a0f9fa870", - color: "#497828" - }]; diff --git a/src/js/components/BrowserApp.stories.tsx b/src/js/components/BrowserApp.stories.tsx deleted file mode 100644 index 593f8e83ad..0000000000 --- a/src/js/components/BrowserApp.stories.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import styled from 'styled-components'; - -import { Storybook } from '@/utils/storybook'; -import { classnames } from '@/utils/classnames'; -import { getOs } from '@/utils/getOs'; - -import { useAppState } from '@/utils/useAppState'; - -import { LeftSidebar } from '@/concept/LeftSidebar'; -import { RightSidebar } from '@/concept/RightSidebar'; -import { AppToolbar } from '@/AppToolbar'; -import { CommandBar } from '@/concept/CommandBar'; -import { AppLayout, MainContent } from '@/concept/App'; -import { Page } from '@/concept/Page'; -import { WithToggle } from '@/concept/Block/Block.stories'; - -export default { - title: 'App/Browser', - component: Window, - argTypes: {}, - parameters: { - layout: 'fullscreen' - }, - decorators: [(Story) => ] -}; - -const BrowserWrapper = styled.div` - width: 100%; - border-radius: 5px; - box-shadow: 0 10px 12px rgb(0 0 0 / 0.1); - overflow: hidden; - position: relative; - background: var(--background-color); - --browser-toolbar-height: 48px; - - > * { - z-index: 1; - } - - &.is-storybook-docs { - height: 700px; - } - - ${AppToolbar} { - height: calc(100vh - var(--browser-toolbar-height)); - margin-top: 52px; - } - - #app-layout { - height: calc(100% - var(--browser-toolbar-height)); - margin-top: var(--browser-toolbar-height); - } -`; - -const BrowserToolbarWrapper = styled.div` - position: absolute; - top: 0; - right: 0; - left: 0; - height: var(--browser-toolbar-height); - display: flex; - align-items: center; - justify-content: center; - background: var(--background-minus-2); - pointer-events: none; - - span { - padding: 0.25rem 1rem; - color: var(--body-text-color---opacity-med); - font-weight: bold; - } - - input { - border-radius: 100em; - padding: 0.25rem; - border: 0; - background: var(--background-plus-1); - color: inherit; - width: max(70%, 70em); - height: 60%; - text-align: center; - margin: auto; - color: var(--body-text-color---opacity-med); - } -`; - -const BrowserToolbar = () => { - return ( - - Browser - - - ) -} - -const Template = (args, context) => { - const { - currentUser, - setCurrentUser, - isSynced, - route, - currentPageMembers, - differentPageMembers, - activeDatabase, - setActiveDatabase, - inactiveDatabases, - connectionStatus, - isElectron, - setRoute, - hostAddress, - isThemeDark, - setIsThemeDark, - isWinFullscreen, - isWinFocused, - isWinMaximized, - isLeftSidebarOpen, - setIsLeftSidebarOpen, - isRightSidebarOpen, - setIsRightSidebarOpen, - setIsSettingsOpen, - isCommandBarOpen, - setIsCommandBarOpen, - isMergeDialogOpen, - setIsMergeDialogOpen, - isDatabaseDialogOpen, - } = useAppState(); - - return ( - - - - setActiveDatabase(database)} - handlePressAddDatabase={() => console.log('pressed add database')} - handlePressRemoveDatabase={() => console.log('pressed remove database')} - handlePressImportDatabase={() => console.log('pressed import database')} - handlePressMoveDatabase={() => console.log('pressed move database')} - handlePressMember={(person) => console.log(person)} - handlePressCommandBar={() => setIsCommandBarOpen(!isCommandBarOpen)} - handlePressDailyNotes={() => setRoute('/daily-notes')} - handlePressAllPages={() => setRoute('/all-pages')} - handlePressGraph={() => setRoute('/graph')} - handlePressThemeToggle={() => setIsThemeDark(!isThemeDark)} - handlePressMerge={() => setIsMergeDialogOpen(true)} - handlePressSettings={() => setIsSettingsOpen(true)} - handlePressHistoryBack={() => console.log('pressed go back')} - handlePressHistoryForward={() => console.log('pressed go forward')} - handlePressLeftSidebarToggle={() => setIsLeftSidebarOpen(!isLeftSidebarOpen)} - handlePressRightSidebarToggle={() => setIsRightSidebarOpen(!isRightSidebarOpen)} - handlePressMinimize={() => console.log('pressed minimize')} - handlePressMaximizeRestore={() => console.log('pressed maximize/restore')} - handlePressClose={() => console.log('pressed close')} - handlePressHostAddress={(hostAddress) => console.log('pressed', hostAddress)} - handleUpdateProfile={(person) => setCurrentUser(person)} - /> - null} - shortcuts={[{ - uid: "4b89dde0-3ccf-481a-875b-d11adfda3f7e", - title: "Passer domesticus", - order: 1 - }, { - uid: "bd4a892f-c7e5-45d8-bab8-68a8ed9d224f", - title: "Spermophilus richardsonii", - order: 2 - }, { - uid: "b60fc12e-bf48-415c-a059-a7a4d5ef686e", - title: "Leprocaulinus vipera", - order: 3 - }, { - uid: "c58d62e5-0e1b-4f30-a156-af8467317c1c", - title: "Rangifer tarandus", - order: 4 - }, { - uid: "dd099e5d-1f6d-4be7-8bf0-9fc0310ba489", - title: "Nycticorax nycticorax", - order: 5 - }]} - version="1.0.0" - /> - - - - - - - {/* */} - {isCommandBarOpen && ( setIsCommandBarOpen(false)} - />) - } - - ) -}; - -export const Browser = Template.bind({}); -Browser.args = { - os: () => getOs(window) -}; diff --git a/src/js/components/Button/Button.stories.tsx b/src/js/components/Button/Button.stories.tsx deleted file mode 100644 index 45607a572c..0000000000 --- a/src/js/components/Button/Button.stories.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import styled from 'styled-components'; - -import { Button } from '@/Button'; -import { BADGE, Storybook } from '@/utils/storybook'; -import { CheckCircledOutline } from 'iconoir-react'; - -const Wrapper = styled.div` - display: flex; - gap: 1rem; -`; - -export default { - title: 'Components/Button', - component: Button, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.BETA, BADGE.IN_USE] - }, - decorators: [(Story) => ] -}; - -const Template = (args) => - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; - - -export const Icon = Template.bind({}); -Icon.args = { - children: - - - - , -}; diff --git a/src/js/components/Button/Button.tsx b/src/js/components/Button/Button.tsx deleted file mode 100644 index 91bef07222..0000000000 --- a/src/js/components/Button/Button.tsx +++ /dev/null @@ -1,193 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { classnames } from '@/utils/classnames'; -import { useFocusRingEl } from '@/utils/useFocusRingEl'; -import { mergeProps } from '@react-aria/utils'; - -export interface ButtonProps extends React.ButtonHTMLAttributes { - /** - * Whether this button should have a stronger style - */ - isPrimary?: boolean; - /** - * Whether the button should appear pressed - */ - isPressed?: boolean; - /** - * Button shape. Set to 'unset' to manually style padding and radius. - */ - shape?: 'rect' | 'round' | 'unset'; - /** - * Button shape style. Set to 'unset' to manually style color and interaction styles. - */ - variant?: 'plain' | 'gray' | 'tinted' | 'filled' | 'unset'; - /** - * Styles provided to the button's focus ring. - */ - focusRingStyle?: React.CSSProperties; -} - - -/** - * Primary UI component for user interaction - */ -export const ButtonWrap = styled.button.attrs(props => { - if (props.isPrimary) props.variant = 'tinted'; - return ({ - "aria-pressed": props.isPressed ? 'true' : undefined, - className: classnames( - 'button', - props.className, - 'shape-' + props.shape, - 'variant-' + props.variant) - }) -}) ` - margin: 0; - font-family: inherit; - font-size: inherit; - font-weight: 500; - border: none; - display: inline-flex; - place-items: center; - place-content: center; - color: var(--body-text-color); - background-color: transparent; - transition-property: background, color; - transition-duration: 0.075s; - transition-timing-function: ease; - gap: 1ch; - text-align: left; - - &:focus { - outline: none; - } - - &:enabled { - cursor: pointer; - } - - span { - flex: 1 0 auto; - } - - /* Shapes */ - &.shape-rect { - --padding-v: 0.375rem; - --padding-h: 0.625rem; - border-radius: 0.25rem; - padding: var(--padding-v) var(--padding-h); - } - - &.shape-round { - --padding-v: 0.375rem; - --padding-h: 0.625rem; - border-radius: 2rem; - padding: var(--padding-v) var(--padding-h); - } - - :where(:not(& * svg), :not(.unset-margin)) svg { - --icon-padding: 0.25rem; - margin: calc((var(--padding-v) * -1) + var(--icon-padding)) calc((var(--padding-h) * -1) + var(--icon-padding)); - - &:not(:first-child) { - margin-left: 0.251em; - } - &:not(:last-child) { - margin-right: 0.251em; - } - } - - /* Variants */ - &.variant-plain { - background: transparent; - - &:hover { - background: var(--body-text-color---opacity-05); - } - - &[aria-pressed="true"], - &:active { - background: var(--body-text-color---opacity-10); - } - } - - &.variant-gray { - color: var(--link-color); - background: var(--body-text-color---opacity-10); - - &:hover { - background: var(--body-text-color---opacity-15); - } - - &[aria-pressed="true"], - &:active { - background: var(--body-text-color---opacity-20); - } - } - - &.variant-tinted { - color: var(--link-color); - background: var(--link-color---opacity-15); - - &:hover { - background: var(--link-color---opacity-20); - } - - &[aria-pressed="true"], - &:active { - background: var(--link-color---opacity-25); - } - } - - &.variant-filled { - color: var(--link-color---contrast); - background: var(--link-color); - - &:hover { - background: var(--link-color---opacity-90); - } - - &[aria-pressed="true"], - &:active { - background: var(--link-color---opacity-80); - } - } - - &:disabled { - &, - &:hover, - &:active { - color: var(--body-text-color---opacity-med); - background: var(---body-text-color---opacity-10); - cursor: not-allowed; - } - } -`; - -interface Result extends React.ForwardRefExoticComponent { - Wrap?: typeof ButtonWrap; -} - -const _Button: Result = React.forwardRef((props: ButtonProps, ref): any => { - ref = ref || React.useRef(); - let { FocusRing, focusProps } = useFocusRingEl(ref); - - return <> - - {props.children} - - {FocusRing} - ; -}); - -_Button.defaultProps = { - shape: 'rect', - variant: 'plain', -} - -export { _Button as Button }; diff --git a/src/js/components/Button/index.ts b/src/js/components/Button/index.ts deleted file mode 100644 index 3b186e1359..0000000000 --- a/src/js/components/Button/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Button, ButtonWrap } from './Button'; -export { Button, ButtonWrap }; \ No newline at end of file diff --git a/src/js/components/Design.stories.tsx b/src/js/components/Design.stories.tsx deleted file mode 100644 index be3da01dab..0000000000 --- a/src/js/components/Design.stories.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import styled, { css } from 'styled-components'; -import { readableColor } from 'polished'; -import { permuteColorOpacities, themeLight, themeDark } from '@/utils/style/style' - -export default { - title: 'Design', - argTypes: {}, - parameters: { - layout: 'fullscreen' - } -}; - -const Stack = styled.div` - width: 40em; - margin: 4em auto; - - h2 { - margin: 0; - text-align: center; - } -`; - -const Title = styled.div` - font-weight: bold; - font-size: var(--font-size--text-xl); -`; - -const Description = styled.div`` - -const Wrapper = styled.div` - padding: 2rem; - display: flex; - gap: 1rem; - flex-direction: column; - - p { - margin: 0; - } - - code { - color: var(--link-color); - padding: 0.25rem 0.5rem; - background: var(--background-minus-2); - border-radius: 0.25rem; - font-size: 0.75rem; - font-family: var(--font-family-code); - user-select: all; - } -`; - -const ColorInstance = styled.div` - width: 3rem; - height: 3rem; - flex: 0 0 3rem; - color: var(--background); - position: relative; - border-radius: 100em; - transition: all 0.12s ease-in-out; - - &:after, - &:before { - content: ''; - position: absolute; - inset: 0; - border-radius: inherit; - background: var(--background); - opacity: var(--opacity); - transition: all 0.12s ease-in-out; - } - - &:before { - opacity: 0; - background: var(--contrast-background, var(--background-color)); - inset: 0.25rem; - filter: blur(0.25rem); - transition: all 0.12s ease-in-out; - } - - &:hover { - transform: scale(1.1); - z-index: 10; - box-shadow: var(--depth-shadow-8); - - &:before { - opacity: 0.7; - } - } -`; - -const ColorStack = styled.div` - display: flex; - - ${props => props.hasContrast && css` - padding: 0.75rem 1.5rem 0.75rem 1rem; - border-radius: 100em; - background: var(--body-text-color); - --contrast-background: var(--body-text-color); - width: max-content; - `} - - > * { - margin-inline-end: -0.5rem; - } -`; - -const DepthStack = styled.div` - display: flex; - gap: 1rem; -`; - -const ColorDemo = ({ name, color, description, hasContrast = false }) => -
- {name} - {description} - {color} -
- - - - - - - - -
- - -export const Design = () => <> - -

Intent colors

- - - - -

Interface colors

- - - - - - - - - -

Depth

- -
-

Depth Shadows

- Use shadows sparingly. Shadows may also be paired with a 1px shadow on the same element to better cut it out of its context. -
- -
-
-
-
- - -
- - \ No newline at end of file diff --git a/src/js/components/Dialog/Dialog.stories.tsx b/src/js/components/Dialog/Dialog.stories.tsx deleted file mode 100644 index ea2dd0d12d..0000000000 --- a/src/js/components/Dialog/Dialog.stories.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Dialog } from './Dialog'; -import { BADGE, Storybook } from '@/utils/storybook'; - -export default { - title: 'Components/Dialog', - component: Dialog, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV, BADGE.IN_USE] - }, - decorators: [(Story) => ] -}; - -const Template = (args) => ; - -export const Default = Template.bind({}); -Default.args = { - title: 'Lorem ipsum dolor sit amet.', - children: 'Lorem ipsum dolor sit amet', - isOpen: true, -}; - -export const Image = Template.bind({}); -Image.args = { - image: , - title: 'Lorem ipsum dolor sit amet.', - children: 'Lorem ipsum dolor sit amet', - isOpen: true, -}; - -export const Minimal = Template.bind({}); -Minimal.args = { - title: 'Lorem ipsum dolor sit amet.', - isOpen: true, -}; diff --git a/src/js/components/Dialog/Dialog.tsx b/src/js/components/Dialog/Dialog.tsx deleted file mode 100644 index f6b3f9ae53..0000000000 --- a/src/js/components/Dialog/Dialog.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -import { - useOverlay, - usePreventScroll, - useModal, - OverlayProps, - OverlayContainer -} from '@react-aria/overlays'; -import { useDialog } from '@react-aria/dialog'; -import { AriaDialogProps } from '@react-types/dialog'; -import { FocusScope } from '@react-aria/focus'; -import { mergeProps } from '@react-aria/utils'; - -import { Button } from '@/Button'; -import { Overlay } from '@/Overlay'; - -const Container = styled(Overlay)` - display: flex; - flex-direction: row; - gap: 1rem; - width: max-content; - padding: 1rem; - position: absolute; - left: 50%; - top: 50%; - transform: translate(-50%, -50%); - min-width: 20rem; -`; - -const Image = styled.div``; - -const Title = styled.h1` - font-size: 1em; - margin: 0; -`; - -const Message = styled.p` - margin: 0; -`; - -const Body = styled.div` - display: flex; - flex-direction: column; - gap: 0.125rem; - min-width: 15rem; - flex: 1 1 100%; -`; - -const Actions = styled.div` - display: grid; - grid-auto-flow: column; - grid-auto-columns: 1fr; - gap: 0.25rem; - width: max-content; - margin-top: auto; - margin-left: auto; - padding-top: 1rem; - align-self: flex-end; -`; - -const Backdrop = styled.div` - position: fixed; - z-index: var(--zindex-modal); - top: 0; - left: 0; - bottom: 0; - right: 0; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; -`; - -const DismissButton = styled(Button)` - font-weight: normal; -`; -const ConfirmButton = styled(Button)` - font-weight: normal; -`; - -interface DialogProps extends OverlayProps, AriaDialogProps { - isOpen: boolean, - title: string, - children?: React.ReactNode, - image?: JSX.Element; - defaultAction?: 'confirm' | 'dismiss'; - dismiss?: { - label?: string; - variant?: 'filled' | 'tinted' | 'gray' | 'plain'; - }, - confirm?: { - label?: string; - variant?: 'filled' | 'tinted' | 'gray' | 'plain'; - } - // onClose?: () => void; - onConfirm?: () => void; -} - -export const Dialog = (props: DialogProps): JSX.Element | null => { - const { - isOpen, - title, - children, - image, - onConfirm: handleConfirm, - onClose: handleClose, - defaultAction, - dismiss, - confirm - } = props; - - let ref = React.useRef(); - let { overlayProps, underlayProps } = useOverlay(props, ref); - let { modalProps } = useModal(); - let { dialogProps, titleProps } = useDialog(props, ref); - usePreventScroll(); - - const dismissProps = { - ...mergeProps({ - onClick: handleClose, - label: 'Cancel', - variant: 'plain', - autoFocus: defaultAction === 'dismiss', - ...dismiss, - }) - } - - const confirmProps = { - ...mergeProps({ - onClick: handleConfirm, - label: 'Cancel', - variant: 'filled', - autoFocus: defaultAction === 'confirm', - ...confirm, - }) - } - - return ( - isOpen ? - - - - - {children - ? children - : ( - <> - {image && {image}} - ( - {title} - {children} - - Cancel - Confirm - - ) - - )} - - - - - : null - ); -}; - -Dialog.defaultProps = { - defaultAction: 'confirm', -} - -Dialog.Container = Container; -Dialog.Image = Image; -Dialog.Title = Title; -Dialog.Message = Message; -Dialog.Body = Body; -Dialog.Actions = Actions; -Dialog.DismissButton = DismissButton; -Dialog.ConfirmButton = ConfirmButton; diff --git a/src/js/components/Dialog/index.ts b/src/js/components/Dialog/index.ts deleted file mode 100644 index 96d19d0055..0000000000 --- a/src/js/components/Dialog/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Dialog } from './Dialog'; -export { Dialog }; \ No newline at end of file diff --git a/src/js/components/Icons/ConnectedGraphConnection.tsx b/src/js/components/Icons/ConnectedGraphConnection.tsx deleted file mode 100644 index 7fc4f5899b..0000000000 --- a/src/js/components/Icons/ConnectedGraphConnection.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export const ConnectedGraphConnection = () => { - return ( - - - - ) -} \ No newline at end of file diff --git a/src/js/components/Icons/ConnectedGraphHost.tsx b/src/js/components/Icons/ConnectedGraphHost.tsx deleted file mode 100644 index 995738cc0e..0000000000 --- a/src/js/components/Icons/ConnectedGraphHost.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export const ConnectedGraphHost = () => { - return ( - <> - - - - - - ) -} \ No newline at end of file diff --git a/src/js/components/Icons/Icon.tsx b/src/js/components/Icons/Icon.tsx deleted file mode 100644 index 4cf4054d4c..0000000000 --- a/src/js/components/Icons/Icon.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import styled from "styled-components"; - -export const Icon = React.memo(styled.svg.attrs({ - viewBox: "0 0 24 24", -})` - width: var(--size, 2em); - height: var(--size, 2em); - - &, - * { - vector-effect: non-scaling-stroke; - stroke-linecap: round; - stroke-linejoin: round; - } - - .fill { - fill: var(--fill, currentColor); - stroke: none; - } - - .stroke { - stroke: var(--stroke, currentColor); - stroke-width: var(--stroke-width, 1.5); - fill: none; - } - - .fill.stroke { - fill: var(--fill, currentColor); - } -`); diff --git a/src/js/components/Icons/X.tsx b/src/js/components/Icons/X.tsx deleted file mode 100644 index cfffd0c99c..0000000000 --- a/src/js/components/Icons/X.tsx +++ /dev/null @@ -1 +0,0 @@ -export const X = () => ; \ No newline at end of file diff --git a/src/js/components/Input/Input.stories.tsx b/src/js/components/Input/Input.stories.tsx deleted file mode 100644 index 046e087e34..0000000000 --- a/src/js/components/Input/Input.stories.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React from 'react' -import { Input } from './Input'; -import { BADGE, Storybook } from '@/utils/storybook'; -import { Mail, Check } from '@material-ui/icons'; -import styled from 'styled-components'; - -const InputStoryWrapper = styled(Storybook.Wrapper)` - display: grid; - grid-template-columns: 1fr 1fr 1fr; - gap: 1rem 2rem; - - hr { - grid-column: 1 / -1; - width: 100%; - border: 0 0 1px; - opacity: var(--opacity-low); - } -`; - -export default { - title: 'Components/Input', - component: Input, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV, BADGE.IN_USE] - }, - decorators: [(Story) => ] -}; - -const Template = (args) => ; - -export const Default = Template.bind({}); -Default.args = { - defaultValue: 'Input', - type: 'text' -}; - -export const Password = () => <> - - - -
- - - - - -export const WithLayout = () => { - return <> - - - - Label - - Help text - - -} - -export const WithValidation = () => { - const [value, setValue] = React.useState(null); - - const regex = /^[_a-zA-Z0-9-+_.]+@[a-zA-Z0-9-\.]+(\.[a-zA-Z]{2,3})$/; - const isValid = regex.exec(value); - - return <> - - - {isValid && } - Email Address - setValue(e.target.value)} /> - Provide a valid email - - -} \ No newline at end of file diff --git a/src/js/components/Input/Input.tsx b/src/js/components/Input/Input.tsx deleted file mode 100644 index 96aae78e91..0000000000 --- a/src/js/components/Input/Input.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { Check, Warning } from '@material-ui/icons'; - -export interface InputProps extends React.InputHTMLAttributes { } - -export const Input = styled.input` - padding: 0.375rem 0.625rem; - margin: 0; - font-family: inherit; - font-size: inherit; - border-radius: 0.25rem; - font-weight: 500; - border: none; - display: inline-flex; - align-items: center; - color: var(--body-text-color); - caret-color: var(--link-color); - background: var(--body-text-color---opacity-lower); - transition-property: filter, background, color, opacity, border-color; - transition-duration: 0.1s; - transition-timing-function: ease-in-out; - gap: 0.5rem; - - &:enabled { - &:hover { - background: var(--body-text-color---opacity-low); - } - - &:active { - background: var(--body-text-color---opacity-low); - } - } - - &:disabled { - color: var(--body-text-color---opacity-low); - background: var(--body-text-color---opacity-lower); - cursor: default; - } - - &.is-invalid { - color: var(--warning-color); - background: var(--warning-color---opacity-lower); - - &:hover { - background: var(--warning-color---opacity-low); - } - - &:active { - background: var(--warning-color---opacity-low); - } - } - - &.is-valid { - color: var(--confirmation-color); - background: var(--confirmation-color---opacity-lower); - - &:hover { - background: var(--confirmation-color---opacity-low); - } - - &:active { - background: var(--confirmation-color---opacity-low); - } - } -`; - -Input.Label = styled.span` - font-weight: bold; -`; - -Input.Help = styled.small``; - -Input.LabelWrapper = styled.label` - display: grid; - grid-template-areas: "label" "input" "help"; - - .label, - ${Input.Label} { - grid-area: label; - } - - .input, - ${Input} { - grid-area: input; - } - - .help, - ${Input.Help} { - grid-area: help; - } - - .input-right { - grid-area: input; - margin: auto 0; - margin-left: auto; - z-index: 1; - } - - .icon-right, - .icon-left { - grid-area: input; - pointer-events: none; - margin: auto; - } - - .icon-right { - margin-right: 0.25rem; - - ~ ${Input} { - padding-right: 2rem; - } - } - - .icon-left { - margin-left: 0.25rem; - - ~ ${Input} { - padding-left: 2rem; - } - } -`; - -Input.Invalid = styled(Warning).attrs({ - className: 'icon-right', -})` -`; - -Input.Valid = styled(Check).attrs({ - className: 'icon-right', -})``; diff --git a/src/js/components/Input/index.ts b/src/js/components/Input/index.ts deleted file mode 100644 index f0fee8fc27..0000000000 --- a/src/js/components/Input/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Input } from './Input'; -export { Input }; \ No newline at end of file diff --git a/src/js/components/Link/Link.stories.tsx b/src/js/components/Link/Link.stories.tsx deleted file mode 100644 index 27d8a93f27..0000000000 --- a/src/js/components/Link/Link.stories.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Link } from './Link'; -import { BADGE, Storybook } from '@/utils/storybook'; - -export default { - title: 'components/Link', - component: Link, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV] - }, - decorators: [(Story) => ] -}; - -export const BidirectionalLink = () => ( -

- Abberton Reservoir is a pumped storage freshwater reservoir in England near the Essex coast, with an area of 700 hectares (1,700 acres). -

); diff --git a/src/js/components/Link/Link.ts b/src/js/components/Link/Link.ts deleted file mode 100644 index cfbca65e87..0000000000 --- a/src/js/components/Link/Link.ts +++ /dev/null @@ -1,37 +0,0 @@ -import styled from 'styled-components'; - -export const Link = styled.a` - display: inline-flex; - color: var(--link-color); - margin-inline: calc(-0.25em + 0.1ch); - padding-inline: calc(0.25em); - border-radius: 0.25em; - text-decoration: none; - cursor: pointer; - transition: background 0.1s ease-in-out; - - &:hover { - opacity: var(--opacity-higher); - } - - &:active { - opacity: var(--opacity-high); - user-select: none; - } - - &:before, - &:after { - color: var(--link-color---opacity-low); - letter-spacing: -0.2ch; - } - - &:before { - content: '[['; - margin-inline-end: 0.1ch; - } - - &:after { - content: ']]'; - margin-inline-start: 0.1ch; - } -`; \ No newline at end of file diff --git a/src/js/components/Link/index.ts b/src/js/components/Link/index.ts deleted file mode 100644 index d60acc35d3..0000000000 --- a/src/js/components/Link/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Link } from './Link'; -export { Link }; \ No newline at end of file diff --git a/src/js/components/Menu/Menu.stories.tsx b/src/js/components/Menu/Menu.stories.tsx deleted file mode 100644 index adcf36871c..0000000000 --- a/src/js/components/Menu/Menu.stories.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { BADGE, Storybook } from '@/utils/storybook'; - -import { Link } from '@material-ui/icons' - -import { Menu } from './Menu'; -import { Overlay } from '@/Overlay'; - -export default { - title: 'Components/Menu', - component: Menu, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV] - }, - decorators: [(Story) => ] -}; - -const Template = (args) => ; - -export const Basic = Template.bind({}); -Basic.args = { - children: <> - Menu Item - Menu Item - Menu Item - - Menu Item - , -}; - -export const InAnOverlay = Template.bind({}); -InAnOverlay.args = { - children: <> - Menu Item - Menu Item - Menu Item - - Menu Item - , -}; -InAnOverlay.decorators = [(Story) => ] - -export const Typical = Template.bind({}); -Typical.args = { - children: <> - Menu Item - Menu Item - Menu Item - - Menu Item - -}; -Typical.decorators = [(Story) => ] diff --git a/src/js/components/Menu/Menu.ts b/src/js/components/Menu/Menu.ts deleted file mode 100644 index bc4f955993..0000000000 --- a/src/js/components/Menu/Menu.ts +++ /dev/null @@ -1,55 +0,0 @@ -import styled from 'styled-components'; - -import { Button } from '@/Button'; - -/** - * Wraps buttons into a menu. - */ -export const Menu = styled.div` - display: flex; - gap: 0.125rem; - min-width: 9em; - align-items: stretch; - flex-direction: column; - &:focus { - outline: none; - } -`; - -/** - * Divider between sections of a menu. - */ -Menu.Separator = styled.hr` - border: 0; - background: var(--border-color); - align-self: stretch; - justify-self: stretch; - height: 1px; - margin: 0.25rem 0; - flex: 0 0 auto; -`; - -/** - * Wraps a menu item. - */ -Menu.Button = styled(Button).attrs({ - shape: 'unset' -})` - font-size: var(--font-size--text-sm); - flex: 0 0 auto; - justify-content: flex-start; - padding: 0.125rem 0.5rem; - border-radius: 0.25rem; -`; - -/** - * Heading for a section of a menu. - */ -Menu.Heading = styled.h3` - margin: 0; - font-weight: 500; - flex: 1 1 100%; - padding: 0.25rem 0.5rem; - font-size: var(--font-size--text-sm); - color: var(--body-text-color---opacity-med); -`; \ No newline at end of file diff --git a/src/js/components/Menu/hooks/useMenu.ts b/src/js/components/Menu/hooks/useMenu.ts deleted file mode 100644 index 5fcc28287c..0000000000 --- a/src/js/components/Menu/hooks/useMenu.ts +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react'; - -const contextMenuAnchor = (e) => ({ - clientHeight: 0, - clientWidth: 0, - getBoundingClientRect: () => ({ - width: 0, - height: 0, - top: e.clientY, - right: e.clientX, - bottom: e.clientY, - left: e.clientX, - }) -}); - -type TriggerType = 'contextMenu' | 'click' | 'hover'; - -export const useMenu = () => { - const [isOpen, setIsOpen] = React.useState(false); - const [position, setPosition] = React.useState(null); - const [anchorEl, setAnchorEl] = React.useState(null); - const [placement, setPlacement] = React.useState('bottom-start'); - const [triggerType, setTriggerType] = React.useState(null); - - const closeMenu = () => { - setIsOpen(false); - setPosition(null); - setTriggerType(null); - }; - - const triggerProps = (type: TriggerType, placement?) => { - if (type === 'contextMenu') { - return ({ - isPressed: triggerType === 'contextMenu', - onContextMenu: (e) => { - setAnchorEl(contextMenuAnchor(e)); - e.preventDefault(); - e.stopPropagation(); - setIsOpen(true); - setPlacement(placement || 'bottom-start'); - setTriggerType('contextMenu'); - } - }); - } else if (type === 'click') { - return ({ - isPressed: triggerType === 'click', - onClick: (e) => { - setAnchorEl(e.currentTarget); - setIsOpen(true); - setPlacement(placement || 'bottom-end'); - setTriggerType('click'); - } - }); - } else if (type === 'hover') { - return ({ - isPressed: triggerType === 'hover', - onMouseEnter: (e) => { - setAnchorEl(e.currentTarget); - setIsOpen(true); - setPlacement(placement || 'bottom-end'); - setTriggerType('hover'); - } - }); - } - }; - - const menuProps = { - position, - anchorEl, - isOpen, - placement - }; - - return { - triggerProps, - menuProps, - closeMenu - }; -}; diff --git a/src/js/components/Menu/index.ts b/src/js/components/Menu/index.ts deleted file mode 100644 index 52361e565f..0000000000 --- a/src/js/components/Menu/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Menu } from './Menu'; -export { Menu }; \ No newline at end of file diff --git a/src/js/components/Notifications/Notification.stories.tsx b/src/js/components/Notifications/Notification.stories.tsx deleted file mode 100644 index d977daaca4..0000000000 --- a/src/js/components/Notifications/Notification.stories.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { Storybook } from "@/utils/storybook"; - -import { notify, Notification } from "@/Notifications/Notifications"; -import { Button } from "@/Button"; -import { Indeterminate } from "@/Spinner/components/Indeterminate"; - -export default { - title: "Components/Notification", - component: Notification, - argTypes: {}, - parameters: { - layout: "centered", - decorators: [ - (Story, args) => ( - - - - ), - ], - }, -}; - -export const Active = () => { - return ( -
- - - - - - -
- -
- ); -}; diff --git a/src/js/components/Notifications/Notifications.tsx b/src/js/components/Notifications/Notifications.tsx deleted file mode 100644 index 6fed3649ca..0000000000 --- a/src/js/components/Notifications/Notifications.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import toast from "react-hot-toast"; - -import { NotificationContainer } from './components/NotificationContainer'; -import { NotificationItem } from './components/NotificationItem'; - -const notify = toast; - -// TODO: Properly extend Toast type with new options: -// id: string; -// isDismissable?: boolean; -// onUndo?: () => void; -// icon?: never; -// iconTheme?: never; -// undoMessage?: string; - -export type Notification = any; - -export { notify, NotificationContainer, NotificationItem }; diff --git a/src/js/components/Notifications/components/NotificationContainer.tsx b/src/js/components/Notifications/components/NotificationContainer.tsx deleted file mode 100644 index 993421b141..0000000000 --- a/src/js/components/Notifications/components/NotificationContainer.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { - Toaster, - ToastPosition, - resolveValue, -} from "react-hot-toast"; -import { NotificationItem } from '../components/NotificationItem'; - -const ToasterProps = { - position: "bottom-right" as ToastPosition, - containerStyle: { - filter: "drop-shadow(0 0.5rem 0.5rem var(--shadow-color---opacity-25)" - }, - gutter: 8, // 1rem -}; - -export const NotificationContainer = () => { - return ( - - {(t) => {resolveValue(t.message, t)}} - - ); -}; diff --git a/src/js/components/Notifications/components/NotificationItem.tsx b/src/js/components/Notifications/components/NotificationItem.tsx deleted file mode 100644 index 851c054fa3..0000000000 --- a/src/js/components/Notifications/components/NotificationItem.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import React from "react"; -import styled, { keyframes } from "styled-components"; -import { mergeProps } from "@react-aria/utils"; - -import { notify, Notification } from '../Notifications'; - -import { Button } from "@/Button"; -import { Icon } from "@/Icons/Icon"; -import { X } from "@/Icons/X"; - -const appear = keyframes` - from { - opacity: 0; - transform: scale(0.95); - } - to { - opacity: 1; - transform: scale(1); - } -`; - -const Wrap = styled.div` - box-shadow: 0 0 0 1px var(--shadow-color---opacity-10); - background: var(--background-plus-2---opacity-med); - color: var(---body-text-color---opacity-80); - padding: 0.5rem 1rem; - border-radius: 1rem; - opacity: 0; - transition: all 0.25s ease-out; - animation: ${appear} 0.25s ease-out; - z-index: 1; - display: flex; - align-items: center; - gap: 0.5rem; - position: relative; - - button:not(& * button):last-child { - margin-right: -0.5rem; - margin-left: auto; - } - - svg:not(& * svg):first-child { - margin-left: -0.5rem; - } - - &:before { - content: ""; - position: absolute; - z-index: -1; - inset: 0; - border-radius: inherit; - background: var(--background-color—-opacity-med); - - @supports (backdrop-filter: blur(10px)) { - background: var(--background-color—-opacity-low); - backdrop-filter: blur(10px); - } - } - - &.visible { - opacity: 1; - } - - &.toast-loading { - padding: 0.75rem 1.5rem; - } - - &.toast-success { - background: var(--confirmation-color---opacity-10); - color: var(--confirmation-color); - } - - &.toast-warning { - background: var(--warning-color---opacity-15); - color: var(--warning-color); - } - - &.toast-error { - background: var(--error-color---opacity-15); - color: var(--error-color); - } -`; - -export const NotificationItem = (t: Notification) => { - const { isDismissable, onUndo, undoMessage, ...rest } = t; - const ref = React.useRef(null); - const [size, setSize] = React.useState({ width: undefined, height: undefined }); - - const setMinSize = () => { - if (ref.current) { - setSize({ width: ref.current.offsetWidth, height: ref.current.offsetHeight }); - } - }; - - const handleUndo = () => { - setMinSize(); - const message = t.undoMessage || "Undone"; - const resultProps = { id: rest.id, onUndo: undefined, isDismissable: true }; - const updateNotification = t.type !== 'blank' - ? notify[t.type || 'blank'](message, resultProps) - : notify(message, resultProps); - - onUndo(); - updateNotification() - } - - const handleDismiss = () => notify.dismiss(t.id); - - return ( - - {t.children} - {t.onUndo && ( - - )} - {t.isDismissable && ( - - )} - - ); -}; \ No newline at end of file diff --git a/src/js/components/Overlay/Backdrop.ts b/src/js/components/Overlay/Backdrop.ts deleted file mode 100644 index 5db1ea1c30..0000000000 --- a/src/js/components/Overlay/Backdrop.ts +++ /dev/null @@ -1,14 +0,0 @@ -import styled from 'styled-components'; - -export const Backdrop = styled.div` - position: fixed; - z-index: var(--zindex-modal); - top: 0; - left: 0; - bottom: 0; - right: 0; - background-color: ${props => props.hidden ? 'none' : 'rgba(0, 0, 0, 0.5)'}; - display: flex; - align-items: center; - justify-content: center; -`; \ No newline at end of file diff --git a/src/js/components/Overlay/Overlay.stories.tsx b/src/js/components/Overlay/Overlay.stories.tsx deleted file mode 100644 index 109df2da99..0000000000 --- a/src/js/components/Overlay/Overlay.stories.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import styled from 'styled-components'; -import { Create } from '@material-ui/icons'; -import { BADGE, Storybook } from '@/utils/storybook'; - -import { Overlay } from './Overlay'; -import { Menu } from '@/Menu'; -import { Button } from '@/Button'; - -export default { - title: 'Components/Overlay', - component: Overlay, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV, BADGE.IN_USE] - } -}; - -const MessageContent = styled.div` - display: flex; - place-items: center; - place-content: center; - flex-direction: column; - gap: 1rem; - padding: 2rem 1rem; - - svg { - font-size: 4rem; - margin: auto; - opacity: var(--opacity-high); - color: var(--link-color); - } - - span { - color: var(--body-text-color---opacity-med); - text-align: center; - display: block; - } -`; - -const Template = (args) => ; - -export const Basic = Template.bind({}); -Basic.args = { - children: 'Overlay', -}; - -export const Message = Template.bind({}); -Message.args = { - children: ( - - Write something insightful today - ), -}; - -export const AroundAMenu = Template.bind({}); -AroundAMenu.args = { - children: - - - - , -}; diff --git a/src/js/components/Overlay/Overlay.ts b/src/js/components/Overlay/Overlay.ts deleted file mode 100644 index 48ecb32103..0000000000 --- a/src/js/components/Overlay/Overlay.ts +++ /dev/null @@ -1,56 +0,0 @@ -import styled, { css, keyframes } from 'styled-components'; - -const overlayAppear = keyframes` - from { - opacity: 0; - transform: translateY(-10px); - } to { - opacity: 1; - transform: translateY(0); - } -`; - -/** - * A simple container with basic padding, background, shadow, etc. - */ -export const Overlay = styled.div` - display: inline-flex; - color: var(--body-text-color); - padding: 0.25rem; - min-width: 2em; - border-radius: calc(0.25rem + 0.25rem); // Button corner radius + container padding makes "concentric" container radius; - z-index: var(--zindex-dropdown); - min-height: 2em; - animation-fill-mode: both; - box-shadow: var(--depth-shadow-16), 0 0 0 1px rgb(0 0 0 / 0.05); - background: var(--background-plus-1); - position: relative; - - &:focus-visible, - &:focus { - box-shadow: var(--depth-shadow-16), 0 0 0 2px rgb(0 0 0 / 0.1); - outline: none; - } - - &.animate-in { - animation: ${overlayAppear} 0.125s; - } - - ${props => !!props.hasOutline && css` - .is-theme-dark & { - &:after { - content: ''; - inset: 0; - position: absolute; - box-shadow: inset 0 0 0 1px var(--body-text-color---opacity-lower); - z-index: 99999; - pointer-events: none; - border-radius: inherit; - } - } - `} -`; - -Overlay.defaultProps = { - hasOutline: true, -} diff --git a/src/js/components/Overlay/index.ts b/src/js/components/Overlay/index.ts deleted file mode 100644 index 90c6828ee5..0000000000 --- a/src/js/components/Overlay/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Overlay } from './Overlay'; -export { Overlay }; \ No newline at end of file diff --git a/src/js/components/Page/Page.tsx b/src/js/components/Page/Page.tsx index b60449f2ae..552c4381ec 100644 --- a/src/js/components/Page/Page.tsx +++ b/src/js/components/Page/Page.tsx @@ -32,7 +32,7 @@ export const PageContainer = ({ children, uid, type }) => {children} export const HeaderImage = ({ src }) => Template(Story, args)] -}; - -const Template = (Story, args) => ; - -export const Basic = () => ; -export const ProgressSpinner = () => ; -export const IndeterminateProgressSpinner = () => <> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -; diff --git a/src/js/components/Spinner/Spinner.tsx b/src/js/components/Spinner/Spinner.tsx deleted file mode 100644 index 3856d47b63..0000000000 --- a/src/js/components/Spinner/Spinner.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import styled, { keyframes } from "styled-components"; -import { classnames } from "@/utils/classnames"; -import React from "react"; - -export const spin = keyframes` - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -`; - -const appearAndDrop = keyframes` - 0% { - transform: translateY(-40%); - opacity: 0; - } - 100% { - transform: translateY(0); - opacity: 1; - } -`; - -const Wrap = styled.div` - width: ${(props) => props.size}; - height: ${(props) => props.size}; - display: flex; - flex-direction: column; - gap: 0.5rem; - align-self: center; - margin: auto; - text-align: center; - place-items: center; - animation: ${appearAndDrop} 0.5s ease; - place-content: center; - - &.placement-center { - position: absolute; - top: calc(50% - ${(props) => props.size} / 2); - left: calc(50% - ${(props) => props.size} / 2); - } -`; - -export const Progress = styled.div` - width: 3em; - height: 3em; - border-radius: 1000em; - border: 1.5px solid var(--background-minus-1); - border-top-color: var(--link-color); - animation: ${spin} 1s linear infinite; -`; - -const Message = styled.span` - animation: ${appearAndDrop} ${(props) => props.messageDelay}s 0.75s - ease-in-out; - font-size: 14px; - animation-fill-mode: both; -`; - -interface SpinnerProps { - message?: string | React.ReactNode; - placement?: "center" | null; - size?: string; - messageDelay?: number; -} - -export const Spinner = ({ - message, - placement, - size, - messageDelay, -}: SpinnerProps): JSX.Element => ( - - - {message && {message}} - -); - -Spinner.defaultProps = { - message: "Loading...", - placement: "center", - size: "10rem", - messageDelay: 2, -}; diff --git a/src/js/components/Spinner/components/Indeterminate.tsx b/src/js/components/Spinner/components/Indeterminate.tsx deleted file mode 100644 index d2f8d2f56e..0000000000 --- a/src/js/components/Spinner/components/Indeterminate.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import styled from 'styled-components'; -import { spin } from '../Spinner'; - -const Svg = styled.svg` - width: var(--size, 2em); - height: var(--size, 2em); - animation: ${spin} 3.33s linear infinite; -`; - -export const Indeterminate = (props) => - - diff --git a/src/js/components/Spinner/index.ts b/src/js/components/Spinner/index.ts deleted file mode 100644 index 0a1710f571..0000000000 --- a/src/js/components/Spinner/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Spinner } from './Spinner'; -export { Spinner }; diff --git a/src/js/components/StandaloneApp.stories.tsx b/src/js/components/StandaloneApp.stories.tsx deleted file mode 100644 index a44d036973..0000000000 --- a/src/js/components/StandaloneApp.stories.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import styled from 'styled-components'; -import { classnames } from '@/utils/classnames'; -import { Storybook } from '@/utils/storybook'; - -import { useAppState } from '@/utils/useAppState'; - -import { LeftSidebar } from '@/concept/LeftSidebar'; -import { RightSidebar } from '@/concept/RightSidebar'; -import { AppToolbar } from '@/AppToolbar'; -import { CommandBar } from '@/concept/CommandBar'; -import { AppLayout, MainContent } from '@/concept/App'; -import { Page } from '@/concept/Page'; -import { usePresenceProvider } from '@/concept/Block/hooks/usePresenceProvider'; - -import { mockPeople } from '@/Avatar/mockData'; -const mockPresence = mockPeople.map((p, index) => ({ ...p, uid: index.toString() })) - -import { - WithPresence -} from './concept/Block/Block.stories'; - -export default { - title: 'App/Standalone', - component: Window, - argTypes: { - connectionStatus: { - options: ['local', 'connecting', 'connected', 'reconnecting', 'offline'], - control: { type: 'radio' }, - defaultValue: 'local' - } - }, - parameters: { - layout: 'fullscreen' - }, - decorators: [(Story) => ] -}; - -const WindowWrapper = styled.div` - justify-self: stretch; - width: 100%; - border-radius: 5px; - box-shadow: 0 10px 12px rgb(0 0 0 / 0.1); - overflow: hidden; - position: relative; - background: var(--background-color); - - > * { - z-index: 1; - } - - &.os-windows { - border-radius: 4px; - } - - &.os-mac { - border-radius: 12px; - - &.is-electron { - &:before { - content: ''; - width: 12px; - height: 12px; - position: absolute; - border-radius: 100px; - left: 20px; - top: 19px; - background: #888; - z-index: 999999; - box-shadow: 20px 0 0 0 #888, 40px 0 0 0 #888; - } - - &.is-theme-dark { - &:after { - content: ''; - position: absolute; - inset: 0; - border-radius: inherit; - pointer-events: none; - z-index: 2; - box-shadow: inset 0 0 1px #fff, 0 0 1px #000; - } - } - } - } - - &.is-win-maximized, - &.is-win-fullscreen { - border-radius: 0; - height: 100vh; - width: 100vw; - margin: 0; - } - - &.is-storybook-docs { - height: 700px; - } -`; - -const Template = (args, context) => { - const { - currentUser, - setCurrentUser, - route, - currentPageMembers, - differentPageMembers, - activeDatabase, - setActiveDatabase, - inactiveDatabases, - isSynced, - isElectron, - setRoute, - hostAddress, - isThemeDark, - setIsThemeDark, - isWinFullscreen, - isWinFocused, - isWinMaximized, - isLeftSidebarOpen, - setIsLeftSidebarOpen, - isRightSidebarOpen, - setIsRightSidebarOpen, - setIsSettingsOpen, - isCommandBarOpen, - setIsCommandBarOpen, - isMergeDialogOpen, - setIsMergeDialogOpen, - isDatabaseDialogOpen, - } = useAppState(); - - const { PresenceProvider, clearPresence } = usePresenceProvider({ presentPeople: mockPresence }); - - return ( - - - setActiveDatabase(database)} - handlePressAddDatabase={() => console.log('pressed add database')} - handlePressRemoveDatabase={() => console.log('pressed remove database')} - handlePressImportDatabase={() => console.log('pressed import database')} - handlePressMoveDatabase={() => console.log('pressed move database')} - handlePressMember={(person) => console.log(person)} - handlePressCommandBar={() => setIsCommandBarOpen(!isCommandBarOpen)} - handlePressDailyNotes={() => setRoute('/daily-notes')} - handlePressAllPages={() => setRoute('/all-pages')} - handlePressGraph={() => setRoute('/graph')} - handlePressThemeToggle={() => setIsThemeDark(!isThemeDark)} - handlePressMerge={() => setIsMergeDialogOpen(true)} - handlePressSettings={() => setIsSettingsOpen(true)} - handlePressHistoryBack={() => console.log('pressed go back')} - handlePressHistoryForward={() => console.log('pressed go forward')} - handlePressLeftSidebarToggle={() => setIsLeftSidebarOpen(!isLeftSidebarOpen)} - handlePressRightSidebarToggle={() => setIsRightSidebarOpen(!isRightSidebarOpen)} - handlePressMinimize={() => console.log('pressed minimize')} - handlePressMaximizeRestore={() => console.log('pressed maximize/restore')} - handlePressClose={() => console.log('pressed close')} - handlePressHostAddress={(hostAddress) => console.log('pressed', hostAddress)} - handleUpdateProfile={(person) => setCurrentUser(person)} - /> - null} - shortcuts={[{ - uid: "4b89dde0-3ccf-481a-875b-d11adfda3f7e", - title: "Passer domesticus", - order: 1 - }, { - uid: "bd4a892f-c7e5-45d8-bab8-68a8ed9d224f", - title: "Spermophilus richardsonii", - order: 2 - }, { - uid: "b60fc12e-bf48-415c-a059-a7a4d5ef686e", - title: "Leprocaulinus vipera", - order: 3 - }, { - uid: "c58d62e5-0e1b-4f30-a156-af8467317c1c", - title: "Rangifer tarandus", - order: 4 - }, { - uid: "dd099e5d-1f6d-4be7-8bf0-9fc0310ba489", - title: "Nycticorax nycticorax", - order: 5 - }]} - version="1.0.0" - /> - - null} - handlePressUnlinkedReferencesToggle={() => null} - > - - - - - - - {/* */} - {isCommandBarOpen && ( setIsCommandBarOpen(false)} - />) - } - - ) -}; - -export const MacOs = Template.bind({}); -MacOs.args = { - os: 'mac', - isElectron: true, -}; - -export const Windows = Template.bind({}); -Windows.args = { - os: 'windows', - isElectron: true -}; - -export const Linux = Template.bind({}); -Linux.args = { - os: 'linux', - isElectron: true -}; diff --git a/src/js/components/Toggle/Toggle.stories.tsx b/src/js/components/Toggle/Toggle.stories.tsx deleted file mode 100644 index 97a82860f6..0000000000 --- a/src/js/components/Toggle/Toggle.stories.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Toggle } from './Toggle'; -import { BADGE, Storybook } from '@/utils/storybook'; - -export default { - title: 'Components/Toggle', - component: Toggle, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV, BADGE.IN_USE] - }, - decorators: [(Story) => ] -}; - -const Template = (args) => ; - -export const Default = Template.bind({}); -Default.args = { - defaultSelected: true -}; - -export const Wide = Template.bind({}); -Wide.args = { - toggleShape: { - width: 80, - height: 36, - inset: 1.5 - } -}; - -export const Labeled = Template.bind({}); -Labeled.args = { - checkedLabel: 'On', - unCheckedLabel: 'Off', - style: { fontSize: '2rem' }, - toggleShape: { - width: 120, - height: 50, - inset: 1.5 - } -}; diff --git a/src/js/components/Toggle/Toggle.tsx b/src/js/components/Toggle/Toggle.tsx deleted file mode 100644 index ac27f1616a..0000000000 --- a/src/js/components/Toggle/Toggle.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { useSwitch } from '@react-aria/switch' -import { useToggleState } from '@react-stately/toggle'; -import { HoverProps, useHover } from '@react-aria/interactions'; -import { useFocusRing } from '@react-aria/focus'; -import { usePress } from '@react-aria/interactions' -import { useVisuallyHidden } from '@react-aria/visually-hidden' -import { AriaSwitchProps } from '@react-types/switch'; -import { mergeProps } from '@react-aria/utils'; - -import { classnames } from '@/utils/classnames'; - -const Handle = styled.rect``; - -const Track = styled.rect``; - -const FocusRing = styled.rect``; - -const Svg = styled.svg` - height: 1em; - flex: 0 0 auto; - overflow: visible; - &, - & * { - transform-origin: center; - vector-effect: non-scaling-stroke; - transition: all 0.1s ease-in-out; - } -`; - -const ValueLabel = styled.text``; - -const Wrap = styled.label` - ${Track} { - fill: var(--body-text-color---opacity-low); - } - ${Handle} { - fill: var(--link-color---contrast); - } - &.is-selected { - ${Track} { - fill: var(--link-color); - } - ${Handle} { - fill: var(--link-color---contrast); - } - } - &.is-hovered { - ${Track} { - fill: var(--body-text-color---opacity-med); - } - ${Handle} { - fill: var(--link-color---contrast); - } - } - &.is-selected.is-hovered { - ${Track} { - fill: var(--link-color---opacity-high); - } - ${Handle} { - fill: var(--link-color---contrast); - } - } - &.is-pressed { - ${Track}, - ${Handle} { - transition-duration: 0s; - } - - ${Track} { - fill: var(--link-color); - } - ${Handle} { - fill: var(--link-color---contrast); - } - } -`; - -interface ToggleProps extends AriaSwitchProps, HoverProps { - toggleShape?: { width: number, height: number, inset: number }; - children?: React.ReactNode; - defaultValue?: boolean; - checkedLabel?: string; - unCheckedLabel?: string; - style: React.CSSProperties; - onChange?: (value: boolean) => void; -} - -export const Toggle = (props: ToggleProps) => { - const { - children, - toggleShape, - checkedLabel, - unCheckedLabel, - style - } = props; - - let state = useToggleState(props); - let ref = React.useRef(null); - let { inputProps } = useSwitch(props, state, ref); - let { hoverProps, isHovered } = useHover(props); - let { pressProps, isPressed } = usePress(props); - let { isFocusVisible, focusProps } = useFocusRing(); - let { visuallyHiddenProps } = useVisuallyHidden(); - - return ( - - - - - - {checkedLabel && - {checkedLabel} - } - {unCheckedLabel && {unCheckedLabel}} - - - {children} - - ) -} - -Toggle.defaultProps = { - toggleShape: { - width: 36, - height: 24, - inset: 1.5 - } -} - -Toggle.Wrap = Wrap; -Toggle.Svg = Svg; -Toggle.Handle = Handle; -Toggle.Track = Track; -Toggle.ValueLabel = ValueLabel; diff --git a/src/js/components/Toggle/index.ts b/src/js/components/Toggle/index.ts deleted file mode 100644 index f12465ea72..0000000000 --- a/src/js/components/Toggle/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Toggle } from './Toggle'; -export { Toggle }; diff --git a/src/js/components/utils/classnames.ts b/src/js/components/utils/classnames.ts deleted file mode 100644 index 109918b7f0..0000000000 --- a/src/js/components/utils/classnames.ts +++ /dev/null @@ -1 +0,0 @@ -export const classnames = (...classes) => classes.filter(Boolean).join(' '); \ No newline at end of file diff --git a/src/js/components/utils/config.ts b/src/js/components/utils/config.ts deleted file mode 100644 index 6455f30b7d..0000000000 --- a/src/js/components/utils/config.ts +++ /dev/null @@ -1,4 +0,0 @@ - -export const preferredDateFormat = { month: 'long', day: 'numeric' }; - -export const DOMRoot = document.querySelector("body"); diff --git a/src/js/components/utils/data/People.ts b/src/js/components/utils/data/People.ts deleted file mode 100644 index 06316e165b..0000000000 --- a/src/js/components/utils/data/People.ts +++ /dev/null @@ -1,98 +0,0 @@ -export const people = - [{ - username: "oorgen0", - personId: "5058615e-b5ce-4e48-9a70-1bb48079883f", - color: "#accb85" - }, { - username: "pcanepe1", - personId: "a22896b5-0cc0-40de-ae64-7105106beb6a", - color: "#12b47e" - }, { - username: "jthorrold2", - personId: "54f83c31-ac3b-412c-b02a-794db3cbff1d", - color: "#c542ed" - }, { - username: "afick3", - personId: "2bb8342d-e276-4333-8bc8-01201adf7778", - color: "#7920ef" - }, { - username: "nhannah4", - personId: "3c48194e-6506-402f-a17b-e979b3ae6026", - color: "#980e37" - }, { - username: "dmcentegart5", - personId: "648994a7-4970-4418-85f5-6710872e4dd2", - color: "#3d53cb" - }, { - username: "tclimar6", - personId: "62201231-bcdd-4b91-9d7e-d3869bfa8c5f", - color: "#594977" - }, { - username: "gchivrall7", - personId: "fd37b6e2-1b9d-4bbd-898c-fc4981835a59", - color: "#4fff47" - }, { - username: "dthomel8", - personId: "f452b384-79e3-4850-b077-770155cbf5ee", - color: "#8e9c1a" - }, { - username: "blinfoot9", - personId: "c547ffaf-63cb-4c45-b8b4-517c46c8eaa5", - color: "#696cf2" - }, { - username: "phardsona", - personId: "390cc8be-0b09-41e5-afa5-341dc69f03c4", - color: "#b33a7c" - }, { - username: "cdowneb", - personId: "dd4a68be-1a92-4afe-856c-7dc4ec4b58b4", - color: "#0f5dfe" - }, { - username: "ahortopc", - personId: "41a06c67-eb68-465c-8190-93a2c9a20875", - color: "#e8487d" - }, { - username: "osuthereld", - personId: "63d40d9a-1615-44c7-aa3b-9a910cc1aabb", - color: "#4f0d1a" - }, { - username: "mgrimblebye", - personId: "e0357779-edf2-490e-9a43-c4918d204e3b", - color: "#77b002" - }, { - username: "ccoochf", - personId: "3d2efbf6-3f43-4fa8-9136-b9d1fb7b7615", - color: "#803b68" - }, { - username: "anasseyg", - personId: "184ffca6-8acb-41cb-ae0e-9683dc234cc7", - color: "#3250c9" - }, { - username: "slasselleh", - personId: "a590cf82-2d5b-49a6-a625-cb2d98022a3c", - color: "#257179" - }, { - username: "ilerouxi", - personId: "aaccec70-7b66-40fe-8186-cbf5660282e7", - color: "#096908" - }, { - username: "fdransfieldj", - personId: "769e3b69-7270-43fc-b3fd-0c5401a352c8", - color: "#e75898" - }, { - username: "dsteinhamk", - personId: "ab64c0e7-4d2d-415d-8b14-6996d363bf10", - color: "#dee1fd" - }, { - username: "glouisetl", - personId: "2886b735-2104-4715-a717-e7041462d507", - color: "#b52850" - }, { - username: "jprozesckym", - personId: "ee321686-ad80-4796-b640-008a3fcb88e8", - color: "#228c57" - }, { - username: "pdrucen", - personId: "beb6085e-1437-438a-a1d6-933a0f9fa870", - color: "#497828" - }]; diff --git a/src/js/components/utils/data/PeoplePresence.ts b/src/js/components/utils/data/PeoplePresence.ts deleted file mode 100644 index a2a93463da..0000000000 --- a/src/js/components/utils/data/PeoplePresence.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { people } from './people'; - -export const peoplePresence = people.map((p, index) => ({ ...p, uid: index.toString() })) \ No newline at end of file diff --git a/src/js/components/utils/getOs.ts b/src/js/components/utils/getOs.ts deleted file mode 100644 index d74eecb283..0000000000 --- a/src/js/components/utils/getOs.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const getOs = (window) => { - if (window.navigator.appVersion.includes('Windows')) { - return 'windows' - } else if (window.navigator.appVersion.includes('Mac')) { - return 'mac' - } else if (window.navigator.appVersion.includes('Linux')) { - return 'linux' - } -} \ No newline at end of file diff --git a/src/js/components/utils/interfaces.ts b/src/js/components/utils/interfaces.ts deleted file mode 100644 index c398aa6a77..0000000000 --- a/src/js/components/utils/interfaces.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * The ID of a unique Athens block - */ -type UID = string | number; - -/** - * A person interacting with Athens in a multiplayer context - */ -type Person = { - personId: string; - username: string; - color: string; // CSS color -} - -/** - * OS the name of supported OSs - */ -type OS = 'mac' | 'windows' | 'linux'; - -/** - * The state of a session's connection to the Athens host - */ -type ConnectionStatus = 'local' | 'connecting' | 'connected' | 'reconnecting' | 'offline'; - -type HostAddress = string; - -/** - * A knowledge graph - */ -type Database = { - id: string; - name: string; - isRemote: boolean; - icon?: string; // Emoji - color?: string; // CSS color -} - -type Synced = boolean; - - -/** - * A Person associated with a specific Athens block in a multiplayer context -*/ -type PersonPresence = Person & { - uid: UID; -} - -/** - * A block -*/ -type Block = { - /** - * The UID of this block - */ - uid: UID; - /** - * Children - */ - children?: any; - /** - * Whether this block's children should be shown - */ - isOpen: boolean; - /** - * The raw content of the block - */ - rawContent: string; - /** - * The rendered content of the block - */ - renderedContent?: any; - /** - * Whether the block is part of a user selection - */ - isSelected?: boolean; - /** - * Whether this block is locked - */ - isLocked?: boolean; - /** - * Whether this block is editable - */ - isEditable?: boolean; - /** - * Whether this block represents a checked checkbox - */ - isChecked?: boolean; - /** - * A user attached to this block - */ - presentUser?: PersonPresence; -} - -type BlockGraph = { - tree: any[], - blocks: any, -}; diff --git a/src/js/components/utils/storybook.ts b/src/js/components/utils/storybook.ts deleted file mode 100644 index 9cd265f654..0000000000 --- a/src/js/components/utils/storybook.ts +++ /dev/null @@ -1,79 +0,0 @@ -import styled from 'styled-components'; - -// .storybook/constants.js -export enum BADGE { - BETA = 'beta', - STABLE = 'stable', - CONCEPT = 'concept', - DEV = 'dev', - IN_USE = 'in use', -} - -export const badges = { - [BADGE.IN_USE]: { - color: '#fff', - contrast: '#E1230C', - title: 'In Use' - }, - [BADGE.DEV]: { - color: '#fff', - contrast: '#E1230C', - title: 'Dev' - }, - [BADGE.BETA]: { - color: '#fff', - contrast: '#0084FF', - title: 'Beta' - }, - [BADGE.STABLE]: { - color: '#fff', - contrast: '#00C820', - title: 'Stable' - }, - [BADGE.CONCEPT]: { - color: '#fff', - contrast: '#FF6B00', - title: 'Concept' - }, -}; - -export const Storybook = () => null; - -/** - * Provides contextual classnames, colors, and typographic - * defaults which all components expect. - * - * Not used in the application, but useful for testing. - */ -const App = styled.div` - background-color: var(--background-color); - color: var(--body-text-color); - position: relative; - z-index: 0; - - .docs-story & { - margin: -30px -20px; - } -`; - -const Wrapper = styled.div` - padding: 2rem; -`; - -const Desktop = styled(Wrapper)` - padding: 2rem; - background: rebeccapurple; - - .is-storybook-canvas & { - min-height: 100vh; - display: flex; - - #app-layout { - height: 100%; - } - } -`; - -Storybook.App = App; -Storybook.Desktop = Desktop; -Storybook.Wrapper = Wrapper; diff --git a/src/js/components/utils/useAppState.ts b/src/js/components/utils/useAppState.ts deleted file mode 100644 index 905fcb335b..0000000000 --- a/src/js/components/utils/useAppState.ts +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react'; -import { mockDatabases as databaseMenuData } from '@/concept/DatabaseMenu/mockData'; -import * as presenceData from '@/PresenceDetails/mockData'; - -const mockData = { - connectionStatus: 'connected', - currentUser: { - personId: '1', - username: 'John Doe', - color: '#007e51', - }, - hostAddress: '192.169.0.1', - activeDatabase: databaseMenuData[0], - inactiveDatabases: databaseMenuData.slice(1), - currentPageMembers: presenceData.currentPageMembers, - differentPageMembers: presenceData.differentPageMembers, -} - -export const useAppState = () => { - - // Session - const [currentUser, setCurrentUser] = React.useState(mockData.currentUser); - const [hostAddress, setHostAddress] = React.useState(mockData.hostAddress); - const [currentPageMembers, setCurrentPageMembers] = React.useState(mockData.currentPageMembers); - const [differentPageMembers, setDifferentPageMembers] = React.useState(mockData.differentPageMembers); - - // Database - const [activeDatabase, setActiveDatabase] = React.useState(mockData.activeDatabase); - const [inactiveDatabases, setInactiveDatabases] = React.useState(mockData.inactiveDatabases); - const [isSynced, setIsSynced] = React.useState(null); - const [connectionStatus, setConnectionStatus] = React.useState(mockData.connectionStatus as ConnectionStatus); - - // Preferences - const [isThemeDark, setIsThemeDark] = React.useState(false); - - // App properties - const [route, setRoute] = React.useState(''); - const [isOnline, setIsOnline] = React.useState(false); - - // Window properties - const [isWinFullscreen, setIsWinFullscreen] = React.useState(false); - const [isWinFocused, setIsWinFocused] = React.useState(true); - const [isWinMaximized, setIsWinMaximized] = React.useState(false); - const [isElectron, setIsElectron] = React.useState(true); - - // Layout components - const [isLeftSidebarOpen, setIsLeftSidebarOpen] = React.useState(false); - const [isRightSidebarOpen, setIsRightSidebarOpen] = React.useState(false); - const [isCommandBarOpen, setIsCommandBarOpen] = React.useState(false); - - // Dialogs and Workflows - const [isMergeDialogOpen, setIsMergeDialogOpen] = React.useState(false); - const [isDatabaseDialogOpen, setIsDatabaseDialogOpen] = React.useState(false); - const [isSettingsOpen, setIsSettingsOpen] = React.useState(false); - - return { - currentUser, - setCurrentUser, - isOnline, - setIsOnline, - route, - currentPageMembers, - setCurrentPageMembers, - differentPageMembers, - setDifferentPageMembers, - activeDatabase, - setActiveDatabase, - inactiveDatabases, - isSettingsOpen, - setIsSettingsOpen, - setInactiveDatabases, - isSynced, - setIsSynced, - isElectron, - setIsElectron, - setRoute, - hostAddress, - setHostAddress, - isThemeDark, - setIsThemeDark, - isWinFullscreen, - setIsWinFullscreen, - isWinFocused, - setIsWinFocused, - isWinMaximized, - setIsWinMaximized, - isLeftSidebarOpen, - setIsLeftSidebarOpen, - isRightSidebarOpen, - setIsRightSidebarOpen, - isCommandBarOpen, - setIsCommandBarOpen, - isMergeDialogOpen, - setIsMergeDialogOpen, - isDatabaseDialogOpen, - setIsDatabaseDialogOpen, - connectionStatus, - setConnectionStatus - } -} \ No newline at end of file diff --git a/src/js/components/utils/useFocusRingEl.tsx b/src/js/components/utils/useFocusRingEl.tsx deleted file mode 100644 index 6c2b1538b9..0000000000 --- a/src/js/components/utils/useFocusRingEl.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import styled from "styled-components"; -import { useFocusRing } from "@react-aria/focus"; -import { DOMRoot } from "@/utils/config"; - -const focusRingRectStyle = (ref): any => { - const position = ref?.current?.getBoundingClientRect(); - const style = getComputedStyle(ref?.current); - const borderTopLeftRadius = style.borderTopLeftRadius; - const borderTopRightRadius = style.borderTopRightRadius; - const borderBottomRightRadius = style.borderBottomRightRadius; - const borderBottomLeftRadius = style.borderBottomLeftRadius; - let inset = style.getPropertyValue("--focus-ring-inset"); - if (inset === "") { - inset = "-3px"; - } - - return { - "--inset": inset, - "--left": position.left + "px", - "--top": position.top + "px", - "--width": position.width + "px", - "--height": position.height + "px", - "--border-top-left-radius": borderTopLeftRadius, - "--border-top-right-radius": borderTopRightRadius, - "--border-bottom-right-radius": borderBottomRightRadius, - "--border-bottom-left-radius": borderBottomLeftRadius, - }; -}; - -const FocusRingEl = styled.div>` - position: absolute; - inset: var(--inset); - border: 2px solid var(--link-color); - box-shadow: inset 0 0 0 1px var(--background-color); - top: calc(var(--top) + var(--inset)); - left: calc(var(--left) + var(--inset)); - width: calc(var(--width) - var(--inset) * 2); - height: calc(var(--height) - var(--inset) * 2); - z-index: 99999; - pointer-events: none; - border-top-left-radius: calc(var(--border-top-left-radius) - var(--inset)); - border-top-right-radius: calc(var(--border-top-right-radius) - var(--inset)); - border-bottom-left-radius: calc( - var(--border-bottom-left-radius) - var(--inset) - ); - border-bottom-right-radius: calc( - var(--border-bottom-right-radius) - var(--inset) - ); -`; - -export const useFocusRingEl = (ref) => { - const { isFocusVisible, focusProps } = useFocusRing(ref); - - const FocusRing = isFocusVisible ? ( - ReactDOM.createPortal( - , - DOMRoot, - ) - ) : ( - <> - ); - - return { - isFocusVisible, - focusProps, - FocusRing, - }; -}; From 486e44ac6ebe33768317f54baaf830ba475669be Mon Sep 17 00:00:00 2001 From: Stuart Hanberg Date: Thu, 31 Mar 2022 23:19:26 -0400 Subject: [PATCH 45/79] rfct: remove styled-components --- package.json | 1 - src/cljs/athens/views.cljs | 67 +-- src/cljs/athens/views/left_sidebar.cljs | 1 - src/cljs/athens/views/pages/core.cljs | 25 +- src/cljs/athens/views/pages/node_page.cljs | 14 +- src/js/components/AppToolbar/AppToolbar.tsx | 39 +- .../AppToolbar/components/WindowButtons.tsx | 253 +++++------ .../components/Confirmation/Confirmation.tsx | 35 ++ src/js/components/Page/Page.tsx | 5 +- .../ProfileSettingsDialog.stories.tsx | 67 --- src/js/components/concept/App/AppLayout.ts | 19 - src/js/components/concept/App/MainContent.ts | 31 -- src/js/components/concept/App/index.ts | 3 - .../concept/Badge/Badge.stories.tsx | 76 ---- src/js/components/concept/Badge/Badge.tsx | 65 --- src/js/components/concept/Badge/index.ts | 2 - .../concept/Block/Block.stories.tsx | 134 ------ src/js/components/concept/Block/Block.tsx | 214 --------- .../concept/Block/components/Body.ts | 12 - .../concept/Block/components/Container.ts | 93 ---- .../concept/Block/components/Content.tsx | 253 ----------- .../concept/Block/components/Refs.tsx | 22 - .../concept/Block/hooks/useBlockState.tsx | 6 - .../concept/Block/hooks/useChecklist.tsx | 27 -- .../concept/Block/hooks/usePresence.tsx | 19 - .../Block/hooks/usePresenceProvider.tsx | 44 -- .../concept/Block/hooks/useSelection.tsx | 15 - .../concept/Block/hooks/useToggle.tsx | 14 - src/js/components/concept/Block/index.ts | 2 - src/js/components/concept/Block/mockData.tsx | 59 --- .../concept/Block/utils/modifyBlocks.ts | 21 - .../concept/Block/utils/renderBlocks.ts | 92 ---- .../Block/utils/toggleBlockProperty.ts | 15 - .../concept/Checkbox/Checkbox.stories.tsx | 46 -- .../components/concept/Checkbox/Checkbox.tsx | 183 -------- src/js/components/concept/Checkbox/index.ts | 2 - .../concept/DailyNotes/DailyNotes.stories.tsx | 28 -- .../concept/DailyNotes/DailyNotes.tsx | 51 --- .../concept/DailyNotes/Next/DailyNotes.tsx | 108 ----- .../DailyNotes/SidebarCalendar/DailyNotes.tsx | 108 ----- src/js/components/concept/DailyNotes/index.ts | 2 - .../DatabaseIcon/DatabaseIcon.stories.tsx | 64 --- .../concept/DatabaseIcon/DatabaseIcon.tsx | 61 --- .../components/concept/DatabaseIcon/index.ts | 2 - .../DatabaseMenu/DatabaseMenu.stories.tsx | 35 -- .../concept/DatabaseMenu/DatabaseMenu.tsx | 196 -------- .../components/DatabaseMenuItem.tsx | 70 --- .../components/concept/DatabaseMenu/index.ts | 2 - .../concept/DatabaseMenu/mockData.ts | 196 -------- .../concept/Embed/Embed.stories.tsx | 43 -- src/js/components/concept/Embed/Embed.tsx | 63 --- src/js/components/concept/Embed/index.ts | 2 - .../LeftSidebar/LeftSidebar.stories.tsx | 139 ------ .../concept/LeftSidebar/LeftSidebar.tsx | 46 -- .../concept/LeftSidebar/components/Logo.tsx | 17 - .../LeftSidebar/components/Shortcut.tsx | 36 -- .../LeftSidebar/components/ShortcutsList.tsx | 23 - .../LeftSidebar/components/Sidebar.tsx | 65 --- .../LeftSidebar/components/Version.tsx | 20 - .../components/concept/LeftSidebar/index.ts | 2 - .../concept/Meter/Meter.stories.tsx | 15 - src/js/components/concept/Meter/Meter.tsx | 85 ---- src/js/components/concept/Meter/index.ts | 2 - .../components/concept/Page/Page.stories.tsx | 92 ---- src/js/components/concept/Page/Page.tsx | 218 --------- .../concept/Page/components/EmptyMessage.tsx | 7 - .../Page/components/References/References.tsx | 165 ------- .../References/components/Reference.tsx | 53 --- .../Page/components/References/index.ts | 2 - src/js/components/concept/Page/index.ts | 2 - .../concept/Preview/Preview.stories.tsx | 48 -- src/js/components/concept/Preview/Preview.tsx | 79 ---- src/js/components/concept/Preview/index.ts | 2 - src/js/components/concept/Preview/mockData.ts | 0 .../concept/Settings/Settings.stories.tsx | 35 -- .../components/concept/Settings/Settings.tsx | 139 ------ .../components/OpenCollectiveSettings.tsx | 82 ---- .../concept/Settings/components/Setting.ts | 63 --- src/js/components/concept/Settings/index.ts | 2 - .../concept/Welcome/Welcome.stories.tsx | 58 --- src/js/components/concept/Welcome/Welcome.tsx | 270 ----------- .../Welcome/components/AddDatabase.tsx | 423 ------------------ .../Welcome/components/DatabasesList.tsx | 199 -------- .../concept/Welcome/components/Item.tsx | 219 --------- .../Welcome/components/JoinDatabase.tsx | 97 ---- .../Welcome/components/SkeletonItem.tsx | 95 ---- src/js/components/concept/Welcome/index.ts | 2 - src/js/components/concept/Welcome/mockData.ts | 195 -------- src/js/components/utils/interfaces.ts | 97 ++++ src/js/components/utils/storybook.tsx | 82 ++++ src/js/components/utils/useAppState.ts | 100 +++++ yarn.lock | 18 +- 92 files changed, 526 insertions(+), 5775 deletions(-) create mode 100644 src/js/components/Confirmation/Confirmation.tsx delete mode 100644 src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.stories.tsx delete mode 100644 src/js/components/concept/App/AppLayout.ts delete mode 100644 src/js/components/concept/App/MainContent.ts delete mode 100644 src/js/components/concept/App/index.ts delete mode 100644 src/js/components/concept/Badge/Badge.stories.tsx delete mode 100644 src/js/components/concept/Badge/Badge.tsx delete mode 100644 src/js/components/concept/Badge/index.ts delete mode 100644 src/js/components/concept/Block/Block.stories.tsx delete mode 100644 src/js/components/concept/Block/Block.tsx delete mode 100644 src/js/components/concept/Block/components/Body.ts delete mode 100644 src/js/components/concept/Block/components/Container.ts delete mode 100644 src/js/components/concept/Block/components/Content.tsx delete mode 100644 src/js/components/concept/Block/components/Refs.tsx delete mode 100644 src/js/components/concept/Block/hooks/useBlockState.tsx delete mode 100644 src/js/components/concept/Block/hooks/useChecklist.tsx delete mode 100644 src/js/components/concept/Block/hooks/usePresence.tsx delete mode 100644 src/js/components/concept/Block/hooks/usePresenceProvider.tsx delete mode 100644 src/js/components/concept/Block/hooks/useSelection.tsx delete mode 100644 src/js/components/concept/Block/hooks/useToggle.tsx delete mode 100644 src/js/components/concept/Block/index.ts delete mode 100644 src/js/components/concept/Block/mockData.tsx delete mode 100644 src/js/components/concept/Block/utils/modifyBlocks.ts delete mode 100644 src/js/components/concept/Block/utils/renderBlocks.ts delete mode 100644 src/js/components/concept/Block/utils/toggleBlockProperty.ts delete mode 100644 src/js/components/concept/Checkbox/Checkbox.stories.tsx delete mode 100644 src/js/components/concept/Checkbox/Checkbox.tsx delete mode 100644 src/js/components/concept/Checkbox/index.ts delete mode 100644 src/js/components/concept/DailyNotes/DailyNotes.stories.tsx delete mode 100644 src/js/components/concept/DailyNotes/DailyNotes.tsx delete mode 100644 src/js/components/concept/DailyNotes/Next/DailyNotes.tsx delete mode 100644 src/js/components/concept/DailyNotes/SidebarCalendar/DailyNotes.tsx delete mode 100644 src/js/components/concept/DailyNotes/index.ts delete mode 100644 src/js/components/concept/DatabaseIcon/DatabaseIcon.stories.tsx delete mode 100644 src/js/components/concept/DatabaseIcon/DatabaseIcon.tsx delete mode 100644 src/js/components/concept/DatabaseIcon/index.ts delete mode 100644 src/js/components/concept/DatabaseMenu/DatabaseMenu.stories.tsx delete mode 100644 src/js/components/concept/DatabaseMenu/DatabaseMenu.tsx delete mode 100644 src/js/components/concept/DatabaseMenu/components/DatabaseMenuItem.tsx delete mode 100644 src/js/components/concept/DatabaseMenu/index.ts delete mode 100644 src/js/components/concept/DatabaseMenu/mockData.ts delete mode 100644 src/js/components/concept/Embed/Embed.stories.tsx delete mode 100644 src/js/components/concept/Embed/Embed.tsx delete mode 100644 src/js/components/concept/Embed/index.ts delete mode 100644 src/js/components/concept/LeftSidebar/LeftSidebar.stories.tsx delete mode 100644 src/js/components/concept/LeftSidebar/LeftSidebar.tsx delete mode 100644 src/js/components/concept/LeftSidebar/components/Logo.tsx delete mode 100644 src/js/components/concept/LeftSidebar/components/Shortcut.tsx delete mode 100644 src/js/components/concept/LeftSidebar/components/ShortcutsList.tsx delete mode 100644 src/js/components/concept/LeftSidebar/components/Sidebar.tsx delete mode 100644 src/js/components/concept/LeftSidebar/components/Version.tsx delete mode 100644 src/js/components/concept/LeftSidebar/index.ts delete mode 100644 src/js/components/concept/Meter/Meter.stories.tsx delete mode 100644 src/js/components/concept/Meter/Meter.tsx delete mode 100644 src/js/components/concept/Meter/index.ts delete mode 100644 src/js/components/concept/Page/Page.stories.tsx delete mode 100644 src/js/components/concept/Page/Page.tsx delete mode 100644 src/js/components/concept/Page/components/EmptyMessage.tsx delete mode 100644 src/js/components/concept/Page/components/References/References.tsx delete mode 100644 src/js/components/concept/Page/components/References/components/Reference.tsx delete mode 100644 src/js/components/concept/Page/components/References/index.ts delete mode 100644 src/js/components/concept/Page/index.ts delete mode 100644 src/js/components/concept/Preview/Preview.stories.tsx delete mode 100644 src/js/components/concept/Preview/Preview.tsx delete mode 100644 src/js/components/concept/Preview/index.ts delete mode 100644 src/js/components/concept/Preview/mockData.ts delete mode 100644 src/js/components/concept/Settings/Settings.stories.tsx delete mode 100644 src/js/components/concept/Settings/Settings.tsx delete mode 100644 src/js/components/concept/Settings/components/OpenCollectiveSettings.tsx delete mode 100644 src/js/components/concept/Settings/components/Setting.ts delete mode 100644 src/js/components/concept/Settings/index.ts delete mode 100644 src/js/components/concept/Welcome/Welcome.stories.tsx delete mode 100644 src/js/components/concept/Welcome/Welcome.tsx delete mode 100644 src/js/components/concept/Welcome/components/AddDatabase.tsx delete mode 100644 src/js/components/concept/Welcome/components/DatabasesList.tsx delete mode 100644 src/js/components/concept/Welcome/components/Item.tsx delete mode 100644 src/js/components/concept/Welcome/components/JoinDatabase.tsx delete mode 100644 src/js/components/concept/Welcome/components/SkeletonItem.tsx delete mode 100644 src/js/components/concept/Welcome/index.ts delete mode 100644 src/js/components/concept/Welcome/mockData.ts create mode 100644 src/js/components/utils/interfaces.ts create mode 100644 src/js/components/utils/storybook.tsx create mode 100644 src/js/components/utils/useAppState.ts diff --git a/package.json b/package.json index f9dc6d21b7..3ca5edecb9 100644 --- a/package.json +++ b/package.json @@ -147,7 +147,6 @@ "react-highlight.js": "1.0.7", "react-hot-toast": "^2.1.1", "react-intersection-observer": "^8.32.1", - "styled-components": "^5.3.0", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/src/cljs/athens/views.cljs b/src/cljs/athens/views.cljs index 74dc9c9424..a8172244c2 100644 --- a/src/cljs/athens/views.cljs +++ b/src/cljs/athens/views.cljs @@ -38,39 +38,42 @@ (zoom)) [:> ChakraProvider {:theme theme, :bg "background.basement"} - [:> OverlayProvider - [help-popup] - [alert] - [athena-component] - (cond - (and @loading @modal) [db-modal/window] + [help-popup] + [alert] + [athena-component] + (cond + (and @loading @modal) [db-modal/window] - @loading - [:> Center {:height "100vh"} - [:> Flex {:width 28 - :flexDirection "column" - :gap 2 - :color "foreground.secondary" - :borderRadius "lg" - :placeItems "center" - :placeContent "center" - :height 28} - [:> Spinner {:size "xl"}]]] + @loading + [:> Center {:height "100vh"} + [:> Flex {:width 28 + :flexDirection "column" + :gap 2 + :color "foreground.secondary" + :borderRadius "lg" + :placeItems "center" + :placeContent "center" + :height 28} + [:> Spinner {:size "xl"}]]] - :else [:<> - (when @modal [db-modal/window]) - [:> Grid - {:gridTemplateColumns "auto 1fr auto" - :gridTemplateRows "auto 1fr auto" - :grid-template-areas - "'app-header app-header app-header' + :else [:<> + (when @modal [db-modal/window]) + [:> Grid + {:gridTemplateColumns "auto 1fr auto" + :gridTemplateRows "auto 1fr auto" + :grid-template-areas + "'app-header app-header app-header' 'left-sidebar main-content secondary-content' 'devtool devtool devtool'" - :height "100vh" - :overflow "hidden" - :sx {"WebkitAppRegion" "drag"}} - [app-toolbar/app-toolbar] - [left-sidebar/left-sidebar] - [pages/view] - [right-sidebar/right-sidebar] - [devtool-component]]])]]]))) + :height "100vh" + :overflow "hidden" + :sx {"WebkitAppRegion" "drag" + "--app-toolbar-height" "3.25rem" + ".os-mac &" {"--app-header-height" "52px"} + ".os-windows &" {"--toolbar-height" "44px"} + ".os-linux &" {"--toolbar-height" "44px"}}} + [app-toolbar/app-toolbar] + [left-sidebar/left-sidebar] + [pages/view] + [right-sidebar/right-sidebar] + [devtool-component]]])]]))) diff --git a/src/cljs/athens/views/left_sidebar.cljs b/src/cljs/athens/views/left_sidebar.cljs index 8f79c7d16b..029f7f7e4c 100644 --- a/src/cljs/athens/views/left_sidebar.cljs +++ b/src/cljs/athens/views/left_sidebar.cljs @@ -94,7 +94,6 @@ (when @open? [:> (.-div motion) {:style {:display "flex" - ;; :paddingTop "7.5rem" :flex-direction "column" :height "100%" :alignItems "stretch" diff --git a/src/cljs/athens/views/pages/core.cljs b/src/cljs/athens/views/pages/core.cljs index 34a047f6c0..8db4f6845e 100644 --- a/src/cljs/athens/views/pages/core.cljs +++ b/src/cljs/athens/views/pages/core.cljs @@ -21,20 +21,29 @@ (toast (clj->js {:status "info" :title "Reconnecting to server..."}))) [:> Box {:flex "1 1 100%" - :position "relative" :gridArea "main-content" :alignItems "flex-start" :justifyContent "stretch" :display "flex" :overflowY "overlay" - :sx {:maskImage "linear-gradient(to bottom, - transparent, - transparent 3rem, - black 5rem, - black calc(100vh - 5rem), - #000000f0 calc(100vh - 4rem), - #00000088 100vh)" + :sx { + :maskImage "linear-gradient(to bottom, + transparent, + #000000cc 1rem, + black 1.5rem, + black calc(100vh - 5rem), + #000000f0 calc(100vh - 4rem), + #00000088 100vh)" + ".os-mac &" { + :maskImage "linear-gradient(to bottom, + transparent var(--app-header-height), + black calc(var(--app-header-height) + 2rem), + black 5rem, + black calc(100vh - 5rem), + #000000f0 calc(100vh - 4rem), + #00000088 100vh)" + } "&:before" {:content "''" :position "fixed" :zIndex "-1" diff --git a/src/cljs/athens/views/pages/node_page.cljs b/src/cljs/athens/views/pages/node_page.cljs index d27fea074e..8819c06594 100644 --- a/src/cljs/athens/views/pages/node_page.cljs +++ b/src/cljs/athens/views/pages/node_page.cljs @@ -1,7 +1,8 @@ (ns athens.views.pages.node-page (:require ["/components/Block/components/Anchor" :refer [Anchor]] - ["/components/Dialog/Dialog" :refer [Dialog]] + ;; ["/components/Dialog/Dialog" :refer [Dialog]] + ["/components/Confirmation/Confirmation" :refer [Confirmation]] ["/components/Page/Page" :refer [PageHeader PageBody PageFooter EditableTitleContainer]] ["@chakra-ui/react" :refer [Text Box Button Portal IconButton AccordionIcon AccordionItem AccordionPanel MenuDivider MenuButton Menu MenuList MenuItem Accordion AccordionButton Breadcrumb BreadcrumbItem BreadcrumbLink VStack]] ["@material-ui/icons/Bookmark" :default Bookmark] @@ -426,12 +427,11 @@ [:<> - (when alert-show - [:> Dialog {:isOpen true - :title message - :onConfirm confirm-fn - :onDismiss cancel-fn}]) - + [:> Confirmation {:isOpen alert-show + :title message + :onConfirm confirm-fn + :onClose cancel-fn}] + ;; Header [:> PageHeader diff --git a/src/js/components/AppToolbar/AppToolbar.tsx b/src/js/components/AppToolbar/AppToolbar.tsx index 2f902fff9e..e27c3fc7f8 100644 --- a/src/js/components/AppToolbar/AppToolbar.tsx +++ b/src/js/components/AppToolbar/AppToolbar.tsx @@ -75,6 +75,7 @@ const ToolbarIconButton = React.forwardRef((props: ToolbarIconButtonProps, ref) }); const AppToolbarWrapper = ({ children, ...props }) => { presenceDetails, ...rest } = props; - - const { toggleColorMode } = useColorMode() + const { colorMode, toggleColorMode } = useColorMode(); const [ canShowFullSecondaryMenu ] = useMediaQuery('(min-width: 900px)'); + // If the database color mode doesn't match + // the chakra color mode, update the chakra color mode + React.useEffect(() => { + if (isThemeDark && colorMode !== 'dark') { + toggleColorMode() + } else if (!isThemeDark && colorMode !== 'light') { + toggleColorMode() + } + }, [ isThemeDark, toggleColorMode ]) + const secondaryTools = [ { label: "Help", @@ -276,10 +301,7 @@ export const AppToolbar = (props: AppToolbarProps): React.ReactElement => { }, { label: "Toggle theme", - onClick: () => { - toggleColorMode() - handlePressThemeToggle() - }, + onClick: handlePressThemeToggle, icon: }, { @@ -375,7 +397,6 @@ export const AppToolbar = (props: AppToolbarProps): React.ReactElement => { {isElectron && (os === 'windows' || os === 'linux') && ( {children}; export interface WindowButtonsProps { - - handlePressMinimize(): void; + handlePressMinimize(): void, } export const WindowButtons = ({ - os, isWinFocused, isWinFullscreen, isWinMaximized, @@ -144,14 +136,7 @@ export const WindowButtons = ({ handlePressMaximizeRestore, handlePressClose }) => { - return ( + return ( {/* Minimize button */} + + + + + + ); +}; \ No newline at end of file diff --git a/src/js/components/Page/Page.tsx b/src/js/components/Page/Page.tsx index 552c4381ec..5df48a2a94 100644 --- a/src/js/components/Page/Page.tsx +++ b/src/js/components/Page/Page.tsx @@ -112,7 +112,7 @@ export const DailyNotesPage = ({ isReal, children }) => {children} -export const EditableTitleContainer = ({ children }) => + }} + {...props}> {children} \ No newline at end of file diff --git a/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.stories.tsx b/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.stories.tsx deleted file mode 100644 index 5608aab36c..0000000000 --- a/src/js/components/ProfileSettingsDialog/ProfileSettingsDialog.stories.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react'; - -import { useOverlayTriggerState } from "@react-stately/overlays"; - -import { BADGE, Storybook } from '@/utils/storybook'; -import { ProfileSettingsDialog } from './ProfileSettingsDialog'; - -import { Avatar } from '../Avatar'; -import { Button } from '@/Button'; - -export default { - title: 'Components/ProfileSettingsDialog', - component: ProfileSettingsDialog, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV, BADGE.IN_USE] - } -}; - -const testPerson = { personId: '123', username: 'John Doe', color: '#0071ed' }; - -const Template = (args, context) => { - let profileSettingsState = useOverlayTriggerState({ - defaultOpen: args.defaultOpen, - onOpenChange: (open) => { - console.log('ProfileSettingsDialog open state changed to: ', open); - }, - }); - const [person, setPerson] = React.useState(testPerson); - - const handleUpdatePerson = React.useCallback((person) => { - setPerson(person); - profileSettingsState.close(); - }, []); - - return ( - <> -
- - -
- - - - ) -}; - -export const Default = Template.bind({}); -Default.args = { - defaultOpen: true -} diff --git a/src/js/components/concept/App/AppLayout.ts b/src/js/components/concept/App/AppLayout.ts deleted file mode 100644 index 1ef3504c98..0000000000 --- a/src/js/components/concept/App/AppLayout.ts +++ /dev/null @@ -1,19 +0,0 @@ -import styled from 'styled-components'; - -/** - * Provides grid for high-level app layout - */ -export const AppLayout = styled.div.attrs({ id: 'app-layout' })` - --app-upper-spacing: 2.5rem; - display: grid; - grid-template-areas: 'app-header app-header app-header' - 'left-sidebar main-content secondary-content' - 'devtool devtool devtool'; - grid-template-columns: auto 1fr auto; - grid-template-rows: auto 1fr auto; - height: 100vh; - - .os-mac & { - --app-upper-spacing: calc(2.5rem + 48px); - } -`; \ No newline at end of file diff --git a/src/js/components/concept/App/MainContent.ts b/src/js/components/concept/App/MainContent.ts deleted file mode 100644 index b6c9c8da0e..0000000000 --- a/src/js/components/concept/App/MainContent.ts +++ /dev/null @@ -1,31 +0,0 @@ -import styled from 'styled-components'; - -export const MainContent = styled.div` - flex: 1 1 100%; - margin-left: auto; - margin-right: auto; - grid-area: main-content; - align-items: flex-start; - justify-content: stretch; - padding-top: var(--app-upper-spacing); - display: flex; - overflow-y: auto; - - @supports (overflow-y: overlay) { - overflow-y: overlay; - } - - &::-webkit-scrollbar { - background: var(--background-minus-1); - width: 0.5rem; - height: 0.5rem; - } - - &::-webkit-scrollbar-corner { - background: var(--background-minus-1); - } - - &::-webkit-scrollbar-thumb { - background: var(--background-minus-2); - } -`; \ No newline at end of file diff --git a/src/js/components/concept/App/index.ts b/src/js/components/concept/App/index.ts deleted file mode 100644 index d22a199262..0000000000 --- a/src/js/components/concept/App/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { MainContent } from './MainContent'; -import { AppLayout } from './AppLayout'; -export { AppLayout, MainContent }; \ No newline at end of file diff --git a/src/js/components/concept/Badge/Badge.stories.tsx b/src/js/components/concept/Badge/Badge.stories.tsx deleted file mode 100644 index 1a85167157..0000000000 --- a/src/js/components/concept/Badge/Badge.stories.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import styled from 'styled-components'; -import { Badge } from './Badge'; -import { BADGE, Storybook } from '@/utils/storybook'; - -import { Home } from '@material-ui/icons'; - -export default { - title: 'Concepts/Badge', - component: Badge, - argTypes: {}, - parameters: { - layout: 'centered', - badges: [BADGE.DEV] - }, - decorators: [(Story) => ] -}; - -const Wrapper = styled.div` - display: flex; - gap: 2rem; - font-size: 2em; -`; - -const MockObject = styled.div` - border-radius: 0.25rem; - background: var(--body-text-color---opacity-low); - width: 2em; - height: 2em; -`; - -const Template = (args) => ; - -export const Default = Template.bind({}); -Default.args = { - children: , -}; - -export const Content = Template.bind({}); -Content.args = { - children: , - badgeContent: '7' -}; - -const StyledIcon = styled(Home)` - background: var(--background-plus-2); - padding: 0.125em; - border-radius: 100em; - font-size: 2.5rem !important; -`; - -export const Position = () => - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/js/components/concept/Badge/Badge.tsx b/src/js/components/concept/Badge/Badge.tsx deleted file mode 100644 index a97b720c7c..0000000000 --- a/src/js/components/concept/Badge/Badge.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React, { ReactNode } from 'react'; -import styled from 'styled-components'; - -const BadgeEl = styled.b` - position: absolute; - border-radius: 100em; - background: var(--badge-background-color, var(--link-color)); - font-size: var(--font-size--text-xs); - color: var(--badge-text-color, #fff); - padding: 0.125em 0.35em; - line-height: 1; - - &:empty { - padding: 0; - width: var(--size, 0.5rem); - height: var(--size, 0.5rem); - } - - &.placement-top-right { - top: 0; - right: 0; - transform: translate(50%, -50%); - } - &.placement-top-left { - top: 0; - left: 0; - transform: translate(-50%, -50%); - } - &.placement-bottom-left { - bottom: 0; - left: 0; - transform: translate(-50%, 50%); - } - &.placement-bottom-right { - bottom: 0; - right: 0; - transform: translate(50%, 50%); - } -`; - -const BadgeWrap = styled.span` - position: relative; - display: inline-flex; -`; - -interface BadgeProps extends React.HTMLAttributes { - badgeContent?: ReactNode, - /** Where the badge should appear relative to the content */ - placement?: 'top-right' | 'top-left' | 'bottom-left' | 'bottom-right', -} - -/** - * Wrap the content with a badge - */ -export const Badge = ({ - badgeContent, - placement = "top-right", - children, - ...props -}: BadgeProps) => - {children} - - {badgeContent} - - diff --git a/src/js/components/concept/Badge/index.ts b/src/js/components/concept/Badge/index.ts deleted file mode 100644 index 0450f88303..0000000000 --- a/src/js/components/concept/Badge/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { Badge } from './Badge'; -export { Badge } \ No newline at end of file diff --git a/src/js/components/concept/Block/Block.stories.tsx b/src/js/components/concept/Block/Block.stories.tsx deleted file mode 100644 index f9fd9dde88..0000000000 --- a/src/js/components/concept/Block/Block.stories.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { mockPeople } from '@/Avatar/mockData'; - -import { Block } from './Block'; -import { BADGE, Storybook } from '@/utils/storybook'; -import { Meter } from '@/concept/Meter'; -import { blockTree } from './mockData'; -import { renderBlocks } from './utils/renderBlocks'; -import { useToggle } from './hooks/useToggle'; -import { usePresence } from './hooks/usePresence'; -import { useChecklist } from './hooks/useChecklist'; -import { useSelection } from './hooks/useSelection'; -import { useBlockState } from './hooks/useBlockState'; -import { usePresenceProvider } from './hooks/usePresenceProvider'; - -const mockPresence = mockPeople.map((p, index) => ({ ...p, uid: index.toString() })) - -export default { - title: 'Concepts/Block', - blockComponent: Block, - argTypes: {}, - decorators: [(Story) => ], - parameters: { - badges: [BADGE.DEV] - } -}; - -const Template = (args) => ; - -export const Basic = Template.bind({}); -Basic.args = { - ...blockTree.blocks["1"], -}; - -export const Editing = Template.bind({}); -Editing.args = { - ...blockTree.blocks["1"], - isEditing: true, -}; - -export const References = Template.bind({}); -References.args = { - ...blockTree.blocks["1"], - refsCount: 12 -}; - -export const Selected = Template.bind({}); -Selected.args = { - ...blockTree.blocks["1"], - isSelected: true, -}; - -export const WithToggle = () => { - const { blockGraph: withState, setBlockState } = useBlockState(blockTree); - const { blockGraph } = useToggle(withState, setBlockState); - - const blocks = renderBlocks({ - blockGraph: blockGraph, - setBlockState: setBlockState, - blockComponent: - }); - - return blocks; -} - - -export const WithPresence = () => { - const { blockGraph: withState, setBlockState: withStateState } = useBlockState(blockTree); - const { blockGraph, setBlockState } = usePresence(withState, withStateState); - - const blocks = renderBlocks({ - blockGraph: blockGraph, - setBlockState: setBlockState, - blockComponent: - }); - - return blocks; -} - -WithPresence.decorators = [(Story) => { - const { PresenceProvider, clearPresence } = usePresenceProvider({ presentPeople: mockPresence }); - - return - - - - - -}]; - -export const WithChecklist = () => { - const { blockGraph: withState, setBlockState } = useBlockState(blockTree); - const { blockGraph: withToggle } = useToggle(withState, setBlockState); - const { blockGraph, checked, total } = useChecklist(withToggle, setBlockState); - - const blocks = renderBlocks({ - blockGraph: blockGraph, - setBlockState: setBlockState, - blockComponent: - }); - - return <> - -
- {blocks} - ; -} - -export const WithSelection = () => { - const { blockGraph: withState, setBlockState } = useBlockState(blockTree); - const { blockGraph: withToggle } = useToggle(withState, setBlockState); - const { blockGraph } = useSelection(withToggle, setBlockState); - - const blocks = renderBlocks({ - blockGraph: blockGraph, - setBlockState: setBlockState, - blockComponent: - }); - - return blocks; -} - -export const MultipleSelected = () => { - const { blockGraph: withState, setBlockState } = useBlockState(blockTree); - const { blockGraph: withToggle } = useToggle(withState, setBlockState); - const { blockGraph } = useSelection(withToggle, setBlockState, true); - - const blocks = renderBlocks({ - blockGraph: blockGraph, - setBlockState: setBlockState, - blockComponent: - }); - - return blocks; -} diff --git a/src/js/components/concept/Block/Block.tsx b/src/js/components/concept/Block/Block.tsx deleted file mode 100644 index e8844106bf..0000000000 --- a/src/js/components/concept/Block/Block.tsx +++ /dev/null @@ -1,214 +0,0 @@ -import React from "react"; -import styled from "styled-components"; -import { Popper } from "@material-ui/core"; - -import { DOMRoot } from "@/utils/config"; -import { classnames } from "@/utils/classnames"; - -import { Avatar } from "@/Avatar"; -import { Anchor } from "@/Block/components/Anchor"; -import { Toggle } from "@/Block/components/Toggle"; -import { Body } from "./components/Body"; -import { Content, ContentProps } from "./components/Content"; -import { Refs } from "./components/Refs"; -import { Container } from "./components/Container"; - -export interface BlockProps extends Block, ContentProps { - /** - * Whether this block is in editing mode - */ - isDragging?: boolean; - /** - * Whether this block is being dragged - */ - isEditing?: boolean; - /** - * Number of references to this block - */ - refsCount?: number; - /** - * Whether to display the avatar of a present user - */ - showPresentUser?: boolean; - /** - * - */ - linkedRef?: string; - /** - * When toggle is pressed - */ - handlePressToggle?: (uid) => void; - /** - * When anchor is pressed - */ - handlePressAnchor?: () => void; - /** - * When mouse is over block - */ - handleMouseEnterBlock?: () => void; - /** - * When mouse leaves block - */ - handleMouseLeaveBlock?: () => void; - /** - * When raw content of a block is modified. - * Returns the new value of the raw content. - */ - handleContentChange?: (e: any) => void; - /** - * When the content is clicked or tapped - */ - handlePressContainer?: () => void; - /** - * When a dragged item is over this block - */ - handleDragOver?: () => void; - /** - * When a dragged item is no longer over this block - */ - handleDragLeave?: () => void; - /** - * When a dragged item dropped on this block - */ - handleDrop?: () => void; -} - -export const Block = ({ - children, - rawContent, - renderedContent, - presentUser, - showPresentUser = true, - isOpen = true, - isSelected, - isEditable, - isEditing, - isLocked, - isDragging, - linkedRef, - refsCount, - uid, - contentProps, - textareaProps, - handleContentChange, - handleMouseEnterBlock, - handleMouseLeaveBlock, - handlePressToggle, - handlePressAnchor, - handlePressContainer, - handleDragOver, - handleDragLeave, - handleDrop, -}: BlockProps) => { - const [showEditableDom, setRenderEditableDom] = React.useState( - false - ); - const [ - avatarAnchorEl, - setAvatarAnchorEl, - ] = React.useState(null); - - return ( - <> - { - e.stopPropagation(); - handlePressContainer && handlePressContainer(e); - }} - onDragOver={handleDragOver} - onDragLeave={handleDragLeave} - onDrop={handleDrop} - className={classnames( - children && "show-tree-indicator", - isOpen ? "is-open" : "is-closed", - linkedRef && "is-linked-ref", - isLocked && "is-locked", - isSelected && "is-selected", - presentUser && showPresentUser && "is-presence", - isSelected && isDragging && "is-dragging", - isEditing && "is-editing" - )} - > - {/* Drop area indicator before */} - { - handleMouseEnterBlock; - isEditable && setRenderEditableDom(true); - }} - onMouseLeave={() => { - handleMouseLeaveBlock; - isEditable && setRenderEditableDom(false); - }} - > - {children && !isLocked && ( - - )} - - {/* Tooltip el */} - - {refsCount >= 1 && } - - {/* inline search el */} - {/* slash menu el */} - {isOpen && children} - {/* Drop area indicator child */} - {/* Drop area indicator after */} - - - {showPresentUser && presentUser && ( - <> - - - - - )} - - ); -}; - -Block.Anchor = Anchor; -Block.Container = Container; -Block.Toggle = Toggle; -Block.Body = Body; -Block.Content = Content; -Block.ListContainer = styled.div` - display: flex; - flex-direction: column; -`; diff --git a/src/js/components/concept/Block/components/Body.ts b/src/js/components/concept/Block/components/Body.ts deleted file mode 100644 index d9c3bc5e5f..0000000000 --- a/src/js/components/concept/Block/components/Body.ts +++ /dev/null @@ -1,12 +0,0 @@ -import styled from 'styled-components'; - -export const Body = styled.div` - display: grid; - grid-template-areas: 'above above above above' - 'toggle bullet content refs' - 'below below below below'; - grid-template-columns: 1em 1em 1fr auto; - grid-template-rows: 0 1fr 0; - border-radius: 0.5rem; - position: relative; -`; diff --git a/src/js/components/concept/Block/components/Container.ts b/src/js/components/concept/Block/components/Container.ts deleted file mode 100644 index f35c757fd3..0000000000 --- a/src/js/components/concept/Block/components/Container.ts +++ /dev/null @@ -1,93 +0,0 @@ -import styled from 'styled-components'; - -export const Container = styled.div` - display: flex; - line-height: var(--line-height, 1.75em); - position: relative; - border-radius: 0.125rem; - justify-content: flex-start; - flex-direction: column; - flex: 1 1 100%; - color: inherit; - - &.show-tree-indicator:before { - content: ''; - position: absolute; - width: 1px; - left: calc(1.375em + 1px); - top: 2em; - bottom: 0; - transform: translateX(50%); - transition: background-color 0.2s ease-in-out; - background: var(--user-color, var(--border-color)); - } - - &.is-presence.show-tree-indicator:before { - opacity: var(--opacity-low); - transform: translateX(50%) scaleX(2); - } - - &:after { - content: ''; - position: absolute; - top: 0.75px; - right: 0; - bottom: 0.75px; - left: 0; - opacity: 0; - pointer-events: none; - border-radius: 0.25rem; - transition: opacity 0.075s ease; - background: var(--link-color---opacity-lower); - } - - &.is-selected:after { - opacity: 1; - } - - .is-selected &.is-selected { - &:after { - opacity: 0; - } - } - - .user-avatar { - position: absolute; - transition: transform 0.3s ease; - left: 4px; - top: 4px; - } - - .block-edit-toggle { - position: absolute; - appearance: none; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: none; - border: none; - cursor: text; - display: block; - z-index: 1; - } - - .block-content { - grid-area: content; - min-height: 1.5em; - - &:hover + .user-avatar { - transform: translateX(-2em); - } - } - - &.is-linked-ref { - background-color: var(--background-plus-2); - } - - /* Inset child blocks */ - & & { - margin-left: var(--block-child-inset-margin, 2em); - grid-area: body; - } -`; diff --git a/src/js/components/concept/Block/components/Content.tsx b/src/js/components/concept/Block/components/Content.tsx deleted file mode 100644 index cc261125a5..0000000000 --- a/src/js/components/concept/Block/components/Content.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; - -const ContentWrap = styled.div` - grid-area: content; - display: grid; - grid-template-areas: "main"; - place-items: stretch; - place-content: stretch; - position: relative; - overflow: visible; - z-index: 2; - flex-grow: 1; - word-break: break-word; - - .rendered-content, - textarea { - grid-area: main; - cursor: text; - font-size: inherit; - font-family: inherit; - color: inherit; - } - - textarea { - color: inherit; - font-size: inherit; - position: relative; - display: block; - -webkit-appearance: none; - resize: none; - transform: translate3d(0,0,0); - outline: none; - background: transparent; - caret-color: var(--link-color); - min-height: 100%; - padding: 0; - margin: 0; - border: 0; - opacity: 0; - } - - &.is-editing, - &.show-editable-dom { - textarea { - z-index: 3; - line-height: inherit; - opacity: 0; - } - } - - &.is-editing { - textarea { - opacity: 1; - } - - .rendered-content { - opacity: 0; - } - } - - &:not(.is-editing):hover textarea { - line-height: inherit; - } - - .is-locked > .block-body > & { - opacity: 0.5 - }; - - span.text-run { - pointer-events: none; - - > a { - position: relative; - z-index: 2; - pointer-events: auto; - } - - } - - span { - grid-area: main; - - > span { - > a { - position: relative; - z-index: 2; - } - } - } - - abbr { - grid-area: main; - z-index: 4; - - > span { - > a { - position: relative; - z-index: 2; - } - } - } - - code, pre { - font-family: 'IBM Plex Mono'; - } - - .media-16-9 { - height: 0; - width: calc(100% - 0.25rem); - z-index: 1; - transform-origin: right center; - transition: all 0.2s ease; - padding-bottom: calc(9 / 16 * 100%); - margin-block: 0.25rem; - margin-inline-end: 0.25rem; - position: relative; - } - - iframe { - border: 0; - box-shadow: inset 0 0 0 0.125rem var(background-minus-1); - position: absolute; - height: 100%; - width: 100%; - cursor: default; - top: 0; - right: 0; - left: 0; - bottom: 0; - border-radius: 0.25rem; - } - - img { - border-radius: 0.25rem; - max-width: calc(100% - 0.25rem); - } - - h1, h2, h3, h4, h5, h6 { - margin: 0; - color: var(--body-text-color---opacity-higher); - font-weight: 500; - } - - h1 { - padding: 0; - margin-block-start: "-0.1em"; - } - - h2, h3 { - padding: 0; - } - - h4 { - padding: 0.25em 0; - } - - h5 { - padding: 1em 0; - } - - h6 { - text-transform: uppercase; - letter-spacing: 0.06em; - padding: 1em 0; - } - - p { - margin: 0; - padding-bottom: 1em; - } - - blockquote { - margin-block: 0.125rem; - margin-inline: 0.5em; - padding-block: calc(0.5em - 0.125rem - 0.125rem); - padding-inline: 1.5em; - border-radius: 0.25em; - background: var(--background-minus-1); - color: var(--body-text-color---opacity-high); - - p { - padding-bottom: 1em; - - &:last-child { - padding-bottom: 0; - } - } - } - - mark.content-visibility.highlight { - padding: 0 0.2em; - border-radius: 0.125rem; - background-color: var(--text-highlight-color); - } - -`; - -export interface ContentProps { - /** The raw content of the block */ - rawContent: string; - /** The rendered content of the block */ - renderedContent?: RenderedContent; - /** Whether the block is in editing mode */ - isEditable?: boolean; - /** Whether the block is in editing mode */ - isEditing?: boolean; - /** Whether the block has child blocks */ - isLocked?: boolean; - /** Whether the block should render its editable components or just the static content */ - showEditableDom?: boolean; - /** When raw content of a block is modified. Returns the new value of the raw content. */ - handleContentChange?: (e: any) => void; - /** When the content is clicked or tapped */ - handlePressContent?: () => void; - /** Props on the content container */ - contentProps: React.HTMLAttributes; - /** Props on the editable textarea */ - textareaProps: React.TextareaHTMLAttributes; -} - -export const Content = ({ - rawContent, - renderedContent, - isLocked, - isEditable, - isEditing, - showEditableDom, - handleContentChange, - contentProps, - textareaProps, -}: ContentProps) => ( - - {(isEditing || showEditableDom) && (