feat(ui): enhance left sidebar (#2899)

* feat(ui): enhance left sidebar

Co-authored-by: Tienson Qin <tiensonqin@gmail.com>
This commit is contained in:
Charlie
2021-10-01 21:27:31 +08:00
committed by GitHub
parent 575e7f976b
commit 7f9a04d2c1
40 changed files with 885 additions and 457 deletions

View File

@@ -4,10 +4,12 @@
--ls-page-text-size: 1em;
--ls-page-title-size: 36px;
--ls-font-family: 'Inter';
--ls-main-content-max-width: 740px;
--ls-main-content-max-width: 820px;
--ls-main-content-max-width-wide: 100%;
--ls-border-radius-low: 4px;
--ls-border-radius-medium: 8px;
--ls-left-sidebar-width: 240px;
--ls-left-sidebar-nav-btn-size: 38px;
}
@media (prefers-color-scheme: dark) {

4
resources/css/tabler-icons.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" name="viewport">
<link type="text/css" rel="stylesheet" href="./css/tabler-icons.min.css">
<link href="./css/style.css" rel="stylesheet" type="text/css">
<link href="./img/logo.png" rel="shortcut icon" type="image/png">
<link href="./img/logo.png" rel="shortcut icon" sizes="192x192">

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3,8 +3,8 @@
<head>
<meta charset="utf-8">
<meta content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" name="viewport">
<link rel="stylesheet" type="text/css" href="./css/tabler-icons.min.css">
<link href="./css/style.css" rel="stylesheet" type="text/css">
<link rel="stylesheet" href="https://unpkg.com/@tabler/icons@latest/iconfont/tabler-icons.min.css">
<link href="./img/logo.png" rel="shortcut icon" type="image/png">
<link href="./img/logo.png" rel="shortcut icon" sizes="192x192">
<link href="./img/logo.png" rel="apple-touch-icon">

View File

@@ -113,7 +113,7 @@
(defn- new-version-downloaded-cb
[_ & args]
(.info logger "[update-downloaded]" args)
(when-let [web-contents (and @*win (. @*win -webContents))]
(when-let [web-contents (and @*win (. ^js @*win -webContents))]
(.send web-contents "auto-updater-downloaded" (bean/->js args))))
(defn init-auto-updater

View File

@@ -34,6 +34,7 @@
[frontend.components.plugins :as plugins]
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.block :as block-handler]
[frontend.handler.page :as page-handler]
[frontend.handler.dnd :as dnd]
[frontend.handler.editor :as editor-handler]
[frontend.handler.repeated :as repeated]
@@ -373,6 +374,9 @@
:on-mouse-down
(fn [e]
(util/stop e)
(when redirect-page-name
(page-handler/add-page-to-recent! (state/get-current-repo) redirect-page-name)
(js/setTimeout #(model/refresh-recent-pages) 300))
(let [create-first-block! (fn []
(when-not (editor-handler/add-default-title-property-if-needed! redirect-page-name)
(editor-handler/insert-first-page-block-if-not-exists! redirect-page-name)))]
@@ -389,7 +393,9 @@
(create-first-block!)
(route-handler/redirect! {:to :page
:path-params {:name redirect-page-name}}))))
(when (and contents-page? (state/get-left-sidebar-open?))
(when (and contents-page?
(util/mobile?)
(state/get-left-sidebar-open?))
(ui-handler/close-left-sidebar!)))}
(if (and (coll? children) (seq children))

View File

@@ -35,6 +35,9 @@
(.readAsText reader file)))
(notification/show! "Please choose a JSON file."
:error))))}]
[:hr]
[:div.mt-4
(case roam-importing?
true (ui/loading "Loading")

View File

@@ -2,6 +2,7 @@
(:require [frontend.components.export :as export]
[frontend.components.plugins :as plugins]
[frontend.components.repo :as repo]
[frontend.components.page :as page]
[frontend.components.right-sidebar :as sidebar]
[frontend.components.search :as search]
[frontend.components.svg :as svg]
@@ -22,20 +23,14 @@
[rum.core :as rum]
[frontend.mobile.util :as mobile-util]))
(rum/defc home-btn < rum/reactive
[{:keys [white? electron-mac?]}]
[:a.cp__header-logo
{:class (when electron-mac? "button")
:href (rfe/href :home)
(rum/defc home-button
[]
[:a.button
{:href (rfe/href :home)
:on-click (fn []
(util/scroll-to-top)
(state/set-journals-length! 2))}
(if electron-mac?
svg/home
(if-let [logo (and config/publishing?
(get-in (state/get-config) [:project :logo]))]
[:img.cp__header-logo-img {:src logo}]
(svg/logo (not white?))))])
(ui/icon "home" {:style {:fontSize 20}})])
(rum/defc login
[logged?]
@@ -62,54 +57,38 @@
(rum/defc left-menu-button < rum/reactive
[{:keys [on-click]}]
[:button#left-menu.cp__header-left-menu
{:on-click on-click}
[:svg.h-6.w-6
{:viewBox "0 0 24 24", :fill "none", :stroke "currentColor"}
[:path
{:d "M4 6h16M4 12h16M4 18h7"
:stroke-width "2"
:stroke-linejoin "round"
:stroke-linecap "round"}]]])
(let [left-sidebar-open? (state/sub :ui/left-sidebar-open?)]
(ui/tippy
{:html [:div.text-sm.font-medium
"Shortcut: "
[:code (util/->platform-shortcut "t l")]]
:delay 2000
:hideDelay 1
:position "right"
:interactive true
:arrow true}
[:a#left-menu.cp__header-left-menu.button
{:on-click on-click
:style {:margin-left 10}}
(ui/icon "menu-2" {:style {:fontSize 20}})])))
(rum/defc dropdown-menu < rum/reactive
[{:keys [me current-repo t default-home]}]
(let [projects (state/sub [:me :projects])
developer-mode? (state/sub [:ui/developer-mode?])
logged? (state/logged?)]
logged? (state/logged?)
page-menu (page/page-menu t)
page-menu-and-hr (when (seq page-menu)
(concat page-menu [{:hr true}]))]
(ui/dropdown-with-links
(fn [{:keys [toggle-fn]}]
[:a.cp__right-menu-button.button
[:a.button
{:on-click toggle-fn}
(svg/horizontal-dots nil)])
(ui/icon "dots" {:style {:fontSize 20}})])
(->>
[(when current-repo
{:title (t :cards-view)
:options {:on-click #(state/pub-event! [:modal/show-cards])}})
(when current-repo
{:title (t :graph-view)
:options {:href (rfe/href :graph)}
:icon svg/graph-sm})
(when current-repo
{:title (t :all-pages)
:options {:href (rfe/href :all-pages)}
:icon svg/pages-sm})
(when (and current-repo (not config/publishing?))
{:title (t :all-files)
:options {:href (rfe/href :all-files)}
:icon svg/folder-sm})
(when (and default-home current-repo)
{:title (t :all-journals)
:options {:href (rfe/href :all-journals)}
:icon svg/calendar-sm})
{:hr true}
(when-not (state/publishing-enable-editing?)
[(when-not (state/publishing-enable-editing?)
{:title (t :settings)
:options {:on-click state/open-settings!}
:icon svg/settings-sm})
@@ -123,7 +102,7 @@
:options {:on-click #(plugins/open-select-theme!)}})
(when current-repo
{:title (t :export)
{:title (t :export-graph)
:options {:on-click #(state/set-modal! export/export)}
:icon nil})
@@ -142,6 +121,7 @@
{:title (t :sign-out)
:options {:on-click user-handler/sign-out!}
:icon svg/logout-sm})]
(concat page-menu-and-hr)
(remove nil?))
;; {:links-footer (when (and (util/electron?) (not logged?))
;; [:div.px-2.py-2 (login logged?)])}
@@ -202,12 +182,10 @@
(js/window.apis.toggleMaxOrMinActiveWindow))))}
(left-menu-button {:on-click (fn []
(open-fn)
(state/set-left-sidebar-open! true))})
(state/set-left-sidebar-open!
(not (:ui/left-sidebar-open? @state/state))))})
(home-btn {:white? white? :electron-mac? electron-mac?})
(when electron-mac? (back-and-forward true))
(when current-repo
(ui/tippy
{:html [:div.text-sm.font-medium
@@ -215,21 +193,26 @@
;; TODO: Pull from config so it displays custom shortcut, not just the default
[:code (util/->platform-shortcut "Ctrl + k")]]
:interactive true
:delay [2000, 0]
:arrow true}
[:a.button#search-button
{:on-click #(state/pub-event! [:go/search])}
svg/search]))
(when electron-not-mac? (back-and-forward))
(ui/icon "search" {:style {:fontSize 20}})]))
[:div.flex-1.flex] ;; Spacer in the middle ------------------------------
(when (and
(not (mobile-util/is-native-platform?))
(not (util/electron?)))
(login logged?))
(when plugin-handler/lsp-enabled?
(plugins/hook-ui-items :toolbar))
[:a (when refreshing?
[:div {:class "animate-spin-reverse"}
svg/refresh])]
(when (not= (state/get-current-route) :home)
(home-button))
(when electron-mac? (back-and-forward electron-mac?))
(new-block-mode)
@@ -237,17 +220,8 @@
[:div {:class "animate-spin-reverse"}
svg/refresh])
(when (and
(not (mobile-util/is-native-platform?))
(not (util/electron?)))
(login logged?))
(repo/sync-status current-repo)
(when-not (util/mobile?)
[:div.repos
(repo/repos-dropdown nil nil)])
(when show-open-folder?
[:a.text-sm.font-medium.button
{:on-click #(page-handler/ls-dir-files! shortcut/refresh!)}
@@ -261,17 +235,12 @@
[:a.text-sm.font-medium.button {:href (rfe/href :graph)}
(t :graph)])
;; Go to Keyboard Shortcuts page
[:a.button
{:title "Keyboard shortcuts"
:on-click (fn [] (route-handler/redirect! {:to :shortcut-setting}))}
(svg/icon-cmd 20)]
(dropdown-menu {:me me
:t t
:current-repo current-repo
:default-home default-home})
(when (not (state/sub :ui/sidebar-open?)) (sidebar/toggle))
(when (not (state/sub :ui/sidebar-open?))
(sidebar/toggle))
(updater-tips-new-version t)])))

View File

@@ -13,7 +13,6 @@
left: 0;
right: 0;
user-select: none;
transition: width 0.3s;
line-height: 1;
.it svg {
@@ -80,10 +79,6 @@
.is-electron.is-mac .cp__header {
padding-left: 78px;
-moz-transition: padding-left .3s ease-in;
-o-transition: padding-left .3s ease-in;
-webkit-transition: padding-left .3s ease-in;
transition: padding-left .3s ease-in;
}
.cp__header .navigation svg {
@@ -98,19 +93,6 @@
-webkit-app-region: no-drag;
}
.cp__header-left-menu {
@apply px-4 mr-4;
border-right: 1px solid var(--ls-secondary-background-color);
color: var(--ls-link-text-color);
display: block;
height: 100%;
}
.cp__header-left-menu:focus {
@apply outline-none;
background: var(--ls-menu-hover-color);
}
.cp__header-logo {
@apply p-2;
}
@@ -133,10 +115,6 @@
@apply shadow-none;
}
.cp__header-left-menu {
display: none;
}
.cp__header-logo {
display: block;
}
@@ -147,13 +125,11 @@
}
#repo-name {
vertical-align: middle;
display: inline;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 7ch;
color: var(--ls-icon-color, #045591);
height: 14px;
}

View File

@@ -0,0 +1,38 @@
(ns frontend.components.modals
(:require [frontend.db.model :as db-model]
[frontend.handler.page :as page-handler]
[frontend.handler.route :as route-handler]
[frontend.ui :as ui]
[clojure.string :as string]
[rum.core :as rum]
[frontend.state :as state]
[frontend.mixins :as mixins]
[frontend.context.i18n :as i18n]
[goog.dom :as gdom]))
(rum/defcs new-page-modal <
(mixins/event-mixin
(fn [state]
(mixins/on-enter
state
:node (gdom/getElement "input-new-page-title")
:on-enter (fn [^js e]
(let [^js target (.-target e)
value (.-value target)]
(when-let [title (and (not (string/blank? (string/trim value))) value)]
(if (db-model/page-empty? (state/get-current-repo) title)
(page-handler/create! title {:redirect? true})
(route-handler/redirect! {:to :page
:path-params {:name title}}))))))))
[state]
(rum/with-context
[[t] i18n/*tongue-context*]
[:div
[:h2.text-xl.pb-4 (t :new-page)]
[:input#input-new-page-title.form-input
{:autoFocus true
:placeholder "page title"}]
[:p.py-2.flex (ui/button (t :submit))]]))
(defn show-new-page-modal! []
(state/set-modal! new-page-modal))

View File

@@ -48,9 +48,7 @@
(when page-name
(if block?
(db/get-block-and-children repo block-id)
(do
(page-handler/add-page-to-recent! repo page-original-name)
(db/get-page-blocks repo page-name)))))
(db/get-page-blocks repo page-name))))
(defn- open-first-block!
[state]
@@ -270,87 +268,97 @@
{:default-collapsed? false})]])))
(defn page-menu
[repo t page page-name page-original-name title journal? public? developer-mode?]
(let [contents? (= (string/lower-case (str page-name)) "contents")
links (fn [] (->>
[(when-not contents?
{:title (t :page/add-to-favorites)
:options {:on-click (fn [] (page-handler/handle-add-page-to-contents! page-original-name))}})
[t]
(when-let [page-name (and (state/get-current-page)
(string/lower-case (state/get-current-page)))]
(let [repo (state/sub :git/current-repo)
page (and page-name (db/entity repo [:block/name page-name]))
page-original-name (:block/original-name page)
journal? (db/journal-page? page-name)
block? (and page (util/uuid-string? page-name))
contents? (= (string/lower-case (str page-name)) "contents")
{:keys [title] :as properties} (:block/properties page)
title (or title page-original-name page-name)
public? (true? (:public properties))
favorites (:favorites (state/sub-graph-config))
favorited? (contains? (set (map string/lower-case favorites))
(string/lower-case page-name))
developer-mode? (state/sub [:ui/developer-mode?])]
(when (and page (not block?))
(->>
[{:title (if favorited?
(t :page/unfavorite)
(t :page/add-to-favorites))
:options {:on-click
(fn []
(if favorited?
(page-handler/unfavorite-page! page-original-name)
(page-handler/favorite-page! page-original-name)))}}
{:title "Go to presentation mode"
:options {:on-click (fn []
(state/sidebar-add-block!
repo
(:db/id page)
:page-presentation
{:page page}))}}
(when (and (not contents?)
(not journal?))
{:title (t :page/rename)
:options {:on-click #(state/set-modal! (rename-page-dialog title page-name))}})
{:title (t :page/presentation-mode)
:options {:on-click (fn []
(state/sidebar-add-block!
repo
(:db/id page)
:page-presentation
{:page page}))}}
(when (and (not contents?)
(not journal?))
{:title (t :page/rename)
:options {:on-click #(state/set-modal! (rename-page-dialog title page-name))}})
(when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))]
[{:title (t :page/open-in-finder)
:options {:on-click #(js/window.apis.showItemInFolder file-path)}}
{:title (t :page/open-with-default-app)
:options {:on-click #(js/window.apis.openPath file-path)}}])
(when-let [file-path (and (util/electron?) (page-handler/get-page-file-path))]
[{:title (t :page/open-in-finder)
:options {:on-click #(js/window.apis.showItemInFolder file-path)}}
{:title (t :page/open-with-default-app)
:options {:on-click #(js/window.apis.openPath file-path)}}])
(when-not contents?
{:title (t :page/delete)
:options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
(when-not contents?
{:title (t :page/delete)
:options {:on-click #(state/set-modal! (delete-page-dialog page-name))}})
(when (state/get-current-page)
{:title (t :export)
:options {:on-click #(state/set-modal!
(fn []
(export/export-blocks [(:block/uuid page)])))}})
(when (util/electron?)
{:title (t (if public? :page/make-private :page/make-public))
:options {:on-click
(when (state/get-current-page)
{:title (t :export-page)
:options {:on-click #(state/set-modal!
(fn []
(page-handler/update-public-attribute!
page-name
(if public? false true))
(state/close-modal!))}})
(export/export-blocks [(:block/uuid page)])))}})
(when (util/electron?)
{:title (t :page/version-history)
:options {:on-click
(fn []
(shell/get-file-latest-git-log page 100))}})
(when (util/electron?)
{:title (t (if public? :page/make-private :page/make-public))
:options {:on-click
(fn []
(page-handler/update-public-attribute!
page-name
(if public? false true))
(state/close-modal!))}})
(when plugin-handler/lsp-enabled?
(for [[_ {:keys [key label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
{:title label
:options {:on-click #(commands/exec-plugin-simple-command!
pid (assoc cmd :page (state/get-current-page)) action)}}))
(when (util/electron?)
{:title (t :page/version-history)
:options {:on-click
(fn []
(shell/get-file-latest-git-log page 100))}})
(when developer-mode?
{:title "(Dev) Show page data"
:options {:on-click (fn []
(let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))]
(println page-data)
(notification/show!
[:div
[:pre.code page-data]
[:br]
(ui/button "Copy to clipboard"
:on-click #(.writeText js/navigator.clipboard page-data))]
:success
false)))}})]
(flatten)
(remove nil?)))]
(ui/dropdown-with-links
(fn [{:keys [toggle-fn]}]
[:a.cp__vertical-menu-button
{:title "More options"
:on-click toggle-fn}
(svg/vertical-dots nil)])
links
{:modal-class (util/hiccup->class
"origin-top-right.absolute.right-0.top-10.mt-2.rounded-md.shadow-lg.whitespace-nowrap.dropdown-overflow-auto.page-drop-options")
:z-index 1})))
(when plugin-handler/lsp-enabled?
(for [[_ {:keys [key label] :as cmd} action pid] (state/get-plugins-commands-with-type :page-menu-item)]
{:title label
:options {:on-click #(commands/exec-plugin-simple-command!
pid (assoc cmd :page (state/get-current-page)) action)}}))
(when developer-mode?
{:title "(Dev) Show page data"
:options {:on-click (fn []
(let [page-data (with-out-str (pprint/pprint (db/pull (:db/id page))))]
(println page-data)
(notification/show!
[:div
[:pre.code page-data]
[:br]
(ui/button "Copy to clipboard"
:on-click #(.writeText js/navigator.clipboard page-data))]
:success
false)))}})]
(flatten)
(remove nil?))))))
;; A page is just a logical block
(rum/defcs page < rum/reactive
@@ -429,10 +437,7 @@
[:div.flex.flex-row
(when plugin-handler/lsp-enabled?
(plugins/hook-ui-slot :page-head-actions-slotted nil)
(plugins/hook-ui-items :pagebar))
(page-menu repo t page page-name page-original-name title
journal? public? developer-mode?)])])
(plugins/hook-ui-items :pagebar))])])
[:div
(when (and block? (not sidebar?))
(let [config {:id "block-parent"
@@ -750,6 +755,10 @@
(rum/with-context [[t] i18n/*tongue-context*]
[:div.flex-1
[:h1.title (t :all-pages)]
[:a.ml-1.opacity-70.hover:opacity-100 {:href (rfe/href :all-files)}
[:span
(ui/icon "files")
[:span.ml-1 (t :all-files)]]]
(when current-repo
(let [pages (->> (page-handler/get-all-pages current-repo)
(map (fn [page] (assoc page :block/backlinks (count (:block/_refs (db/entity (:db/id page)))))))

View File

@@ -189,9 +189,7 @@
(when (seq repos)
(ui/dropdown-with-links
(fn [{:keys [toggle-fn]}]
[:a#repo-switch.block.pr-2.whitespace-nowrap {:on-click toggle-fn
:class (when-not (util/mobile?)
"fade-link")}
[:a#repo-switch.block.pr-2.whitespace-nowrap {:on-click toggle-fn}
[:span
(let [repo-name (get-repo-name current-repo)
repo-name (if (or (util/electron?)
@@ -199,8 +197,8 @@
(last
(string/split repo-name #"/"))
repo-name)]
[:span#repo-name {:title repo-name} repo-name])
[:span.dropdown-caret.ml-1 {:style {:border-top-color "#6b7280"}}]]])
[:span#repo-name.font-medium {:title repo-name} repo-name])
[:span.dropdown-caret.ml-2 {:style {:border-top-color "#6b7280"}}]]])
(mapv
(fn [{:keys [id url]}]
{:title (get-repo-name url)
@@ -219,7 +217,7 @@
switch-repos)
(cond->
{:modal-class (util/hiccup->class
"origin-top-right.absolute.left-0.mt-2.w-48.rounded-md.shadow-lg")
"origin-top-right.absolute.left-0.mt-2.rounded-md.shadow-lg")
:links-footer [:div
(when (seq switch-repos) [:hr.my-4])
[:a {:class "block px-4 py-2 text-sm transition ease-in-out duration-150 cursor menu-link"

View File

@@ -22,8 +22,19 @@
(rum/defc toggle
[]
(when-not (util/mobile?)
[:a.button {:on-click state/toggle-sidebar-open?!}
(svg/menu)]))
(ui/tippy
{:html [:div.text-sm.font-medium
"Shortcut: "
[:code (util/->platform-shortcut "t r")]]
:delay 2000
:hideDelay 1
:position "left"
:interactive true
:arrow true}
[:a.button.fade-link.toggle
{:on-click state/toggle-sidebar-open?!}
(ui/icon "layout-sidebar-right" {:style {:fontSize "20px"}})])))
(rum/defc block-cp < rum/reactive
[repo idx block]
@@ -49,8 +60,7 @@
[repo idx db-id block-type block-data t]
(case block-type
:contents
[(or (state/get-favorites-name)
(t :right-side-bar/favorites))
[(t :right-side-bar/contents)
(contents)]
:help
@@ -215,8 +225,7 @@
[:div.ml-4.text-sm
[:a.cp__right-sidebar-settings-btn {:on-click (fn [e]
(state/sidebar-add-block! repo "contents" :contents nil))}
(or (state/get-favorites-name)
(t :right-side-bar/favorites))]]
(t :right-side-bar/contents)]]
[:div.ml-4.text-sm
[:a.cp__right-sidebar-settings-btn {:on-click (fn []

View File

@@ -14,3 +14,8 @@ html[data-theme=light] {
.sidebar-item-list {
padding-bottom: 150px;
}
html[data-theme='light'] a.toggle:hover {
color: var(--ls-primary-text-color);
}

View File

@@ -284,11 +284,10 @@
"Tip: " [:code (util/->platform-shortcut "Ctrl+Shift+p")] " to open the commands palette"]
:interactive true
:arrow true}
[:a.inline-block
{:style {:margin-top 1
:margin-left 12}
[:a.inline-block.fade-link
{:style {:margin-left 12}
:on-click #(state/toggle! :ui/command-palette-open?)}
(svg/icon-cmd 20)])])]
(ui/icon "command" {:style {:font-size 20}})])])]
(let [recent-search (mapv (fn [q] {:type :search :data q}) (db/get-key-value :recent/search))
pages (->> (db/get-key-value :recent/pages)
(remove nil?)

View File

@@ -584,18 +584,19 @@
[:aside.md:w-64
[:ul
(for [[label text icon] [[:general (t :settings-page/tab-general) (svg/adjustments 16)]
[:editor (t :settings-page/tab-editor) (svg/icon-editor 16)]
[:shortcuts (t :settings-page/tab-shortcuts) (svg/icon-cmd 18)]
[:git (t :settings-page/tab-version-control) svg/git]
[:advanced (t :settings-page/tab-advanced) (svg/icon-cli 16)]]]
(for [[label text icon] [[:general (t :settings-page/tab-general) (ui/icon "adjustments" {:style {:font-size 20}})]
[:editor (t :settings-page/tab-editor) (ui/icon "writing" {:style {:font-size 20}})]
[:shortcuts (t :settings-page/tab-shortcuts) (ui/icon "command" {:style {:font-size 20}})]
[:git (t :settings-page/tab-version-control) (ui/icon "history" {:style {:font-size 20}})]
[:advanced (t :settings-page/tab-advanced) (ui/icon "bulb" {:style {:font-size 20}})]]]
[:li
{:class (util/classnames [{:active (= label @*active)}])
:on-click #(reset! *active label)}
[:a.flex.items-center
[[:i.flex.items-center icon] [:strong text]]]])]]
icon
[:strong text]]])]]
[:article

View File

@@ -44,6 +44,7 @@
font-size: 14px;
font-weight: normal;
padding-left: 5px;
margin-top: 2px;
opacity: .9;
}
}

View File

@@ -9,19 +9,25 @@
[frontend.components.settings :as settings]
[frontend.components.theme :as theme]
[frontend.components.widgets :as widgets]
[frontend.components.modals :refer [show-new-page-modal!]]
[frontend.config :as config]
[frontend.context.i18n :as i18n]
[frontend.db :as db]
[frontend.db.model :as db-model]
[frontend.components.svg :as svg]
[frontend.db-mixins :as db-mixins]
[frontend.handler.editor :as editor-handler]
[frontend.handler.route :as route-handler]
[frontend.handler.page :as page-handler]
[frontend.mixins :as mixins]
[frontend.modules.shortcut.data-helper :as shortcut-dh]
[frontend.state :as state]
[frontend.ui :as ui]
[frontend.util :as util]
[reitit.frontend.easy :as rfe]
[goog.dom :as gdom]
[rum.core :as rum]))
[rum.core :as rum]
[frontend.extensions.srs :as srs]))
(defn nav-item
[title href svg-d active? close-modal-fn]
@@ -37,34 +43,155 @@
:stroke-linecap "round"}]]
title])
(rum/defc nav-content-item
[name {:keys [edit-fn class] :as opts} child]
[:div.nav-content-item.is-expand
{:class class}
[:div.hd.items-center.mb-2
{:on-click (fn [^js/MouseEvent e]
(let [^js target (.-target e)
^js parent (.closest target ".nav-content-item")]
(.toggle (.-classList parent) "is-expand")))}
[:a.font-medium.fade-link name]
[:span
[:a.more svg/arrow-down-v2]]]
[:div.bd child]])
;; TODO: enhance
(defn- pick-one-ast-page-ref
[block]
(when-let [title-ast (and block (:block/title block))]
(when-let [link-ref (and (= (ffirst title-ast) "Link")
(:url (second (first title-ast))))]
(when (= "Page_ref" (first link-ref))
(second link-ref)))))
(defn- delta-y
[e]
(let [rect (.. (.. e -target) getBoundingClientRect)]
(- (.. e -pageY) (.. rect -top))))
(defn- move-up?
[e]
(let [delta (delta-y e)]
(< delta 14)))
(rum/defcs favorite-item <
(rum/local nil ::up?)
(rum/local nil ::dragging-over)
[state t name]
(let [up? (get state ::up?)
dragging-over (get state ::dragging-over)
target (state/sub :favorites/dragging)]
[:li.favorite-item
{:key name
:class (if (and target @dragging-over (not= target @dragging-over))
"dragging-target"
"")
:draggable true
:on-drag-start (fn [event]
(state/set-state! :favorites/dragging name))
:on-drag-over (fn [e]
(util/stop e)
(reset! dragging-over name)
(when-not (= name (get @state/state :favorites/dragging))
(reset! up? (move-up? e))))
:on-drag-leave (fn [e]
(reset! dragging-over nil))
:on-drop (fn [e]
(page-handler/reorder-favorites! {:to name
:up? (move-up? e)})
(reset! up? nil)
(reset! dragging-over nil))}
[:a {:href (rfe/href :page {:name name})}
name]]))
(rum/defc favorites < rum/reactive
[t]
(nav-content-item
[:a.flex.items-center.text-sm.font-medium.rounded-md
(ui/icon "star mr-1" {:style {:font-size 18}})
[:span.flex-1.uppercase {:style {:padding-top 2}}
(t :left-side-bar/nav-favorites)]]
{:class "favorites"
:edit-fn
(fn [e]
(rfe/push-state :page {:name "Favorites"})
(util/stop e))}
(let [favorites (:favorites (state/sub-graph-config))]
(when (seq favorites)
[:ul.favorites
(for [name favorites]
(when-not (string/blank? name)
(favorite-item t name)))]))))
(rum/defc recent-pages
< rum/reactive db-mixins/query
[t]
(nav-content-item
[:a.flex.items-center.text-sm.font-medium.rounded-md
(ui/icon "history mr-1" {:style {:font-size 18}})
[:span.flex-1.uppercase {:style {:padding-top 2}}
(t :left-side-bar/nav-recent-pages)]]
{:class "recent"}
(let [pages (state/sub :editor/recent-pages)]
[:ul
(for [name pages]
[:li {:key name}
[:a {:href (rfe/href :page {:name name})} name]])])))
(rum/defc flashcards < rum/reactive
[]
(let [num (srs/get-srs-cards-total)]
[:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:on-click #(state/pub-event! [:modal/show-cards])}
(ui/icon "infinity mr-3" {:style {:font-size 20}})
[:span.flex-1 "Flashcards"]
(when (and num (not (zero? num)))
[:span.ml-3.inline-block.py-0.5.px-3.text-xs.font-medium.rounded-full num])]))
(rum/defc sidebar-nav < rum/reactive
[route-match close-modal-fn]
(let [white? (= "white" (state/sub :ui/theme))
active? (fn [route] (= route (get-in route-match [:data :name])))
page-active? (fn [page]
(= page (get-in route-match [:parameters :path :name])))
right-sidebar? (state/sub :ui/sidebar-open?)
left-sidebar? (state/sub :ui/left-sidebar-open?)]
(when left-sidebar?
[:nav.flex-1.left-sidebar-inner
(nav-item "Journals" "#/"
"M3 12l9-9 9 9M5 10v10a1 1 0 001 1h3a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1h3a1 1 0 001-1V10M9 21h6"
(active? :home)
close-modal-fn)
(nav-item "All Pages" "#/all-pages"
"M6 2h9a1 1 0 0 1 .7.3l4 4a1 1 0 0 1 .3.7v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4c0-1.1.9-2 2-2zm9 2.41V7h2.59L15 4.41zM18 9h-3a2 2 0 0 1-2-2V4H6v16h12V9zm-2 7a1 1 0 0 1-1 1H9a1 1 0 0 1 0-2h6a1 1 0 0 1 1 1zm0-4a1 1 0 0 1-1 1H9a1 1 0 0 1 0-2h6a1 1 0 0 1 1 1zm-5-4a1 1 0 0 1-1 1H9a1 1 0 1 1 0-2h1a1 1 0 0 1 1 1z"
(active? :all-pages)
close-modal-fn)
(when-not config/publishing?
(nav-item "All Files" "#/all-files"
"M3 7V17C3 18.1046 3.89543 19 5 19H19C20.1046 19 21 18.1046 21 17V9C21 7.89543 20.1046 7 19 7H13L11 5H5C3.89543 5 3 5.89543 3 7Z"
(active? :all-files)
close-modal-fn))
(when-not right-sidebar?
[:div.pl-4.pr-4 {:style {:height 1
:background-color (if white? "#f0f8ff" "#073642")
:margin 12}}])
(right-sidebar/contents)])))
(rum/with-context [[t] i18n/*tongue-context*]
(let [active? (fn [route] (= route (get-in route-match [:data :name])))
page-active? (fn [page]
(= page (get-in route-match [:parameters :path :name])))
left-sidebar? (state/sub :ui/left-sidebar-open?)
white? (= "white" (state/sub :ui/theme))]
(when left-sidebar?
[:div.left-sidebar-inner.flex-1.flex.flex-col.min-h-0
[:div.flex.flex-col.pt-5.pb-4.overflow-y-auto
(when-not (util/mobile?)
[:div.flex.items-center.flex-shrink-0.px-4.mb-5
[:a {:href (rfe/href :home)}
(svg/logo (not white?))]
[:div.repos.ml-2
(repo/repos-dropdown nil nil)]])
[:nav.flex-1.px-2.space-y-1 {:aria-label "Sidebar"}
[:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:href (rfe/href :all-journals)}
(ui/icon "calendar mr-3" {:style {:font-size 20}})
[:span.flex-1 "Journals"]]
(flashcards)
[:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:href (rfe/href :graph)}
(ui/icon "hierarchy mr-3" {:style {:font-size 20}})
[:span.flex-1 "Graph view"]]
[:a.item.group.flex.items-center.px-2.py-2.text-sm.font-medium.rounded-md {:href (rfe/href :all-pages)}
(ui/icon "files mr-3" {:style {:font-size 20}})
[:span.flex-1 "All pages"]]]
(favorites t)
(recent-pages t)]]))))
(rum/defc sidebar-mobile-sidebar < rum/reactive
[{:keys [open? close-fn route-match]}]
@@ -99,41 +226,47 @@
{:did-mount (fn [state]
(when-let [element (gdom/getElement "main-content")]
(dnd/subscribe!
element
:upload-files
{:drop (fn [e files]
(when-let [id (state/get-edit-input-id)]
(let [format (:block/format (state/get-edit-block))]
(editor-handler/upload-asset id files format editor-handler/*asset-uploading? true))))}))
element
:upload-files
{:drop (fn [e files]
(when-let [id (state/get-edit-input-id)]
(let [format (:block/format (state/get-edit-block))]
(editor-handler/upload-asset id files format editor-handler/*asset-uploading? true))))}))
state)}
[{:keys [route-match global-graph-pages? logged? home? route-name indexeddb-support? white? db-restoring? main-content]}]
(rum/with-context [[t] i18n/*tongue-context*]
[:div#main-content.cp__sidebar-main-layout.flex-1.flex
[:div#sidebar-nav-wrapper.flex-col.pt-4.hidden.sm:block
{:style {:flex (if (state/get-left-sidebar-open?)
"0 1 20%"
"0 0 0px")}}
(when (state/sub :ui/left-sidebar-open?)
(sidebar-nav route-match nil))]
[:div#main-content-container.w-full.flex.justify-center
{:style {:margin-top (if global-graph-pages? 0 "2rem")}}
[:div.cp__sidebar-main-content
{:data-is-global-graph-pages global-graph-pages?
:data-is-full-width (or global-graph-pages?
(contains? #{:all-files :all-pages :my-publishing} route-name))}
(cond
(not indexeddb-support?)
nil
db-restoring?
[:div.mt-20
[:div.ls-center
(ui/loading (t :loading))]]
(let [left-sidebar-open? (state/sub :ui/left-sidebar-open?)
mobile? (util/mobile?)]
(rum/with-context [[t] i18n/*tongue-context*]
[:div#main-content.cp__sidebar-main-layout.flex-1.flex
{:class (util/classnames [{:is-left-sidebar-open left-sidebar-open?}])}
:else
[:div.pb-24 {:class (if global-graph-pages? "" (util/hiccup->class "max-w-7xl.mx-auto"))
:style {:margin-bottom (if global-graph-pages? 0 120)}}
main-content])]]]))
;; desktop left sidebar layout
(when-not mobile?
[:div#sidebar-nav-wrapper.cp__sidebar-left-layout
{:class (util/classnames [{:is-open left-sidebar-open?}])}
;; sidebar contents
(sidebar-nav route-match nil)])
[:div#main-content-container.w-full.flex.justify-center
[:div.cp__sidebar-main-content
{:data-is-global-graph-pages global-graph-pages?
:data-is-full-width (or global-graph-pages?
(contains? #{:all-files :all-pages :my-publishing} route-name))}
(cond
(not indexeddb-support?)
nil
db-restoring?
[:div.mt-20
[:div.ls-center
(ui/loading (t :loading))]]
:else
[:div.pb-24 {:class (if global-graph-pages? "" (util/hiccup->class "max-w-7xl.mx-auto"))
:style {:margin-bottom (if global-graph-pages? 0 120)}}
main-content])]]])))
(rum/defc footer
[]
@@ -155,22 +288,22 @@
;; TODO: simplify logic
(rum/defc main-content < rum/reactive db-mixins/query
{:init (fn [state]
(when-not @sidebar-inited?
(let [current-repo (state/sub :git/current-repo)
default-home (get-default-home-if-valid)
sidebar (:sidebar default-home)
sidebar (if (string? sidebar) [sidebar] sidebar)]
(when-let [pages (->> (seq sidebar)
(remove string/blank?))]
(doseq [page pages]
(let [page (string/lower-case page)
[db-id block-type] (if (= page "contents")
["contents" :contents]
[page :page])]
(state/sidebar-add-block! current-repo db-id block-type nil)))
(reset! sidebar-inited? true))))
state)}
{:init (fn [state]
(when-not @sidebar-inited?
(let [current-repo (state/sub :git/current-repo)
default-home (get-default-home-if-valid)
sidebar (:sidebar default-home)
sidebar (if (string? sidebar) [sidebar] sidebar)]
(when-let [pages (->> (seq sidebar)
(remove string/blank?))]
(doseq [page pages]
(let [page (string/lower-case page)
[db-id block-type] (if (= page "contents")
["contents" :contents]
[page :page])]
(state/sidebar-add-block! current-repo db-id block-type nil)))
(reset! sidebar-inited? true))))
state)}
[]
(let [today (state/sub :today)
cloning? (state/sub :repo/cloning?)
@@ -184,60 +317,60 @@
preferred-format (state/sub [:me :preferred_format])
logged? (:name me)]
(rum/with-context [[t] i18n/*tongue-context*]
[:div
(cond
(and default-home
(= :home (state/get-current-route))
(not (state/route-has-p?))
(:page default-home))
(route-handler/redirect! {:to :page
:path-params {:name (:page default-home)}})
[:div
(cond
(and default-home
(= :home (state/get-current-route))
(not (state/route-has-p?))
(:page default-home))
(route-handler/redirect! {:to :page
:path-params {:name (:page default-home)}})
(and config/publishing?
(not default-home)
(empty? latest-journals))
(route-handler/redirect! {:to :all-pages})
(and config/publishing?
(not default-home)
(empty? latest-journals))
(route-handler/redirect! {:to :all-pages})
importing-to-db?
(ui/loading (t :parsing-files))
importing-to-db?
(ui/loading (t :parsing-files))
loading-files?
(ui/loading (t :loading-files))
loading-files?
(ui/loading (t :loading-files))
(and (not logged?) (seq latest-journals))
(journal/journals latest-journals)
(and (not logged?) (seq latest-journals))
(journal/journals latest-journals)
(and logged? (not preferred-format))
(widgets/choose-preferred-format)
(and logged? (not preferred-format))
(widgets/choose-preferred-format)
;; TODO: delay this
(and logged? (nil? (:email me)))
(settings/set-email)
(and logged? (nil? (:email me)))
(settings/set-email)
cloning?
(ui/loading (t :cloning))
cloning?
(ui/loading (t :cloning))
(seq latest-journals)
(journal/journals latest-journals)
(seq latest-journals)
(journal/journals latest-journals)
(and logged? (empty? (:repos me)))
(widgets/add-graph)
(and logged? (empty? (:repos me)))
(widgets/add-graph)
;; FIXME: why will this happen?
:else
[:div])])))
:else
[:div])])))
(rum/defc custom-context-menu < rum/reactive
[]
(when (state/sub :custom-context-menu/show?)
(when-let [links (state/sub :custom-context-menu/links)]
(ui/css-transition
{:class-names "fade"
:timeout {:enter 500
:exit 300}}
links
{:class-names "fade"
:timeout {:enter 500
:exit 300}}
links
;; (custom-context-menu-content)
))))
))))
(rum/defc new-block-mode < rum/reactive
[]
@@ -261,11 +394,11 @@
(when-not (state/sub :ui/sidebar-open?)
;; TODO: remove with-context usage
(rum/with-context [[t] i18n/*tongue-context*]
[:div.cp__sidebar-help-btn
{:title (t :help-shortcut-title)
:on-click (fn []
(state/sidebar-add-block! (state/get-current-repo) "help" :help nil))}
"?"])))
[:div.cp__sidebar-help-btn
{:title (t :help-shortcut-title)
:on-click (fn []
(state/sidebar-add-block! (state/get-current-repo) "help" :help nil))}
"?"])))
(rum/defc settings-modal < rum/reactive
[]
@@ -273,7 +406,7 @@
(if settings-open?
(do
(state/set-modal!
(fn [] [:div.settings-modal (settings/settings)]))
(fn [] [:div.settings-modal (settings/settings)]))
(util/lock-global-scroll settings-open?))
(state/set-modal! nil))
nil))
@@ -307,6 +440,7 @@
system-theme? (state/sub :ui/system-theme?)
white? (= "white" (state/sub :ui/theme))
sidebar-open? (state/sub :ui/sidebar-open?)
left-sidebar-open? (state/sub :ui/left-sidebar-open?)
route-name (get-in route-match [:data :name])
global-graph-pages? (= :graph route-name)
logged? (:name me)
@@ -329,47 +463,50 @@
(editor-handler/unhighlight-blocks!)
(util/fix-open-external-with-shift! e))}
[:div.theme-inner
(sidebar-mobile-sidebar
{:open? open?
:close-fn close-fn
:route-match route-match})
[:div.#app-container.h-screen.flex
[:div.flex-1.h-full.flex.flex-col#left-container.relative
{:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
(header/header {:open-fn open-fn
:white? white?
:current-repo current-repo
:logged? logged?
:page? page?
:route-match route-match
:me me
:default-home default-home
:new-block-mode new-block-mode})
[:div.theme-inner
{:class (util/classnames [{:ls-left-sidebar-open left-sidebar-open?}])}
[:div#main-container.scrollbar-spacing
(main {:route-match route-match
:global-graph-pages? global-graph-pages?
:logged? logged?
:home? home?
:route-name route-name
:indexeddb-support? indexeddb-support?
:white? white?
:db-restoring? db-restoring?
:main-content main-content})]
(sidebar-mobile-sidebar
{:open? open?
:close-fn close-fn
:route-match route-match})
(footer)]
(right-sidebar/sidebar)
[:div.#app-container.h-screen.flex
[:div.flex-1.h-full.flex.flex-col#left-container.relative
{:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
(header/header {:open-fn open-fn
:white? white?
:current-repo current-repo
:logged? logged?
:page? page?
:route-match route-match
:me me
:default-home default-home
:new-block-mode new-block-mode})
[:div#app-single-container]]
[:div#main-container.scrollbar-spacing
(main {:route-match route-match
:global-graph-pages? global-graph-pages?
:logged? logged?
:home? home?
:route-name route-name
:indexeddb-support? indexeddb-support?
:white? white?
:db-restoring? db-restoring?
:main-content main-content})]
(ui/notification)
(ui/modal)
(settings-modal)
(command-palette/command-palette-modal)
(custom-context-menu)
[:a#download.hidden]
(when
(and (not config/mobile?)
(not config/publishing?))
(help-button))]))))
(footer)]
(right-sidebar/sidebar)
[:div#app-single-container]]
(ui/notification)
(ui/modal)
(settings-modal)
(command-palette/command-palette-modal)
(custom-context-menu)
[:a#download.hidden]
(when
(and (not config/mobile?)
(not config/publishing?))
(help-button))]))))

View File

@@ -10,14 +10,41 @@
}
}
#app-container {
flex: 0 0 100%;
transition: all 200ms ease-in 0s;
.is-electron.is-mac .cp__sidebar-left-layout {
padding-top: 30px;
transition: all 0.25s;
-webkit-transition: all 0.25s;
}
#main-content-container {
.is-electron.is-mac.is-fullscreen .cp__sidebar-left-layout {
padding-top: 0;
}
.ls-left-sidebar-open {
.cp__header {
padding-left: 0 !important;
margin-left: var(--ls-left-sidebar-width);
}
}
#app-container {
flex: 0 0 100%;
transition: all 200ms ease-in 0s;
}
#main-container {
position: relative;
}
#main-content {
&.is-left-sidebar-open {
padding-left: var(--ls-left-sidebar-width);
}
&-container {
font-size: 1em;
padding: 1rem;
}
}
#left-sidebar {
@@ -49,15 +76,130 @@
color: var(--ls-active-primary-color);
}
.left-sidebar-inner {
padding-right: 15px;
}
nav > a {
color: var(--ls-icon-color);
}
}
.left-sidebar-inner {
height: 100%;
.dropdown-wrapper {
min-width: 180px;
}
.nav-content-item {
padding: 32px 0 0 0;
> .hd {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 5px;
user-select: none;
cursor: pointer;
padding: 0 18px;
> span {
> a {
opacity: .4;
padding-left: 12px;
display: none;
transition: none;
&:hover {
opacity: 1 !important;
}
&:last-child {
transform: translateY(-6px) translateX(2px) rotate(90deg);
}
}
}
&:hover {
> span {
> a {
display: block;
&:last-child {
display: block;
opacity: .6;
}
}
}
}
}
> .bd {
display: none;
ul {
list-style: none;
padding: 0;
margin: 0;
a {
width: 100%;
padding: 2px 20px;
display: flex;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: var(--ls-primary-text-color);
&:hover {
background-color: var(--ls-quaternary-background-color);
}
&:active {
opacity: .7;
}
}
}
}
&.is-expand {
> .hd > span > a {
&:last-child {
transform: translateY(2px);
}
}
> .bd {
display: block;
}
}
}
a.item:hover {
background-color: var(--ls-quaternary-background-color);
}
}
.white-theme .left-sidebar-inner a{
color: var(--ls-primary-text-color);
}
.cp__sidebar-left-layout {
@apply flex-col sm:block;
background-color: var(--ls-secondary-background-color);
width: var(--ls-left-sidebar-width);
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 9;
transition: transform .25s;
transform: translateX(-100%);
&.is-open {
transform: translateX(0);
}
}
.settings-modal {
margin: -15px;
}
@@ -148,19 +290,19 @@
}
&-topbar {
position: sticky;
position: -webkit-sticky;
top: 0;
left: 0;
right: 0;
background-color: var(--ls-secondary-background-color, #d8e1e8);
z-index: 999;
user-select: none;
-webkit-app-region: drag;
position: sticky;
position: -webkit-sticky;
top: 0;
left: 0;
right: 0;
background-color: var(--ls-secondary-background-color, #d8e1e8);
z-index: 999;
user-select: none;
-webkit-app-region: drag;
a, svg {
-webkit-app-region: no-drag;
}
a, svg {
-webkit-app-region: no-drag;
}
}
.page {
@@ -219,3 +361,7 @@
overflow-y: overlay;
}
}
.favorites li.dragging-target {
border-left: 5px solid green;
}

View File

@@ -399,7 +399,7 @@
(rum/defc logo
[dark?]
[:svg
{:fill (if dark? "currentColor" "#002B36"), :view-box "0 0 21 21", :height "21", :width "21"}
{:fill "currentColor", :view-box "0 0 21 21", :height "21", :width "21"}
[:ellipse
{:transform
"matrix(0.987073 0.160274 -0.239143 0.970984 11.7346 2.59206)"

View File

@@ -1357,3 +1357,8 @@
(filter :block/file)
(sort-by :block/updated-at >)
(take 200)))
(defn refresh-recent-pages
[]
(let [results (db-utils/get-key-value :recent/pages)]
(state/set-state! :editor/recent-pages results)))

View File

@@ -101,6 +101,10 @@
:right-side-bar/favorites "Favorites"
:right-side-bar/page-graph "Page graph"
:right-side-bar/block-ref "Block reference"
:left-side-bar/new-page "New page"
:left-side-bar/nav-favorites "Favorites"
:left-side-bar/nav-shortcuts "Shortcuts"
:left-side-bar/nav-recent-pages "Recent"
:git/set-access-token "Set GitHub personal access token"
:git/token-is-encrypted "The token will be encrypted and stored in the browser local storage"
:git/token-server "The server will never store it"
@@ -136,7 +140,7 @@
:project/setup "Setup a public project on Logseq"
:project/location "All published pages will be located under"
:project/sync-settings "Sync project settings"
:page/presentation-mode "Presentation mode (powered by Reveal.js)"
:page/presentation-mode "Presentation"
:page/edit-properties-placeholder "Properties"
:page/delete-success "Page {1} was deleted successfully!"
:page/delete-confirmation "Are you sure you want to delete this page and its file?"
@@ -156,6 +160,7 @@
:page/publish-as-slide "Publish this page as a slide on Logseq"
:page/unpublish "Un-publish this page on Logseq"
:page/add-to-favorites "Add to Favorites"
:page/unfavorite "Unfavorite page"
:page/show-journals "Show journals"
:page/show-name "Show page name"
:page/hide-name "Hide page name"
@@ -266,6 +271,8 @@
:cards-view "View cards"
:publishing "Publishing"
:export "Export"
:export-graph "Export graph"
:export-page "Export page"
:export-markdown "Export as standard Markdown (no block properties)"
:export-opml "Export as OPML"
:export-public-pages "Export public pages"
@@ -415,7 +422,7 @@
:project/setup "Einrichten eines öffentlichen Projekts auf Logseq"
:project/location "Alle veröffentlichten Seiten befinden sich unter"
:project/sync-settings "Projekteinstellungen synchronisieren"
:page/presentation-mode "Präsentationsmodus (angetrieben von Reveal.js)"
:page/presentation-mode "Präsentationsmodus"
:page/edit-properties-placeholder "Klicken Sie hier, um die Eigenschaften dieser Seite zu bearbeiten"
:page/delete-success "Die Seite {1} wurde erfolgreich gelöscht!"
:page/delete-confirmation "Diese Seite und die zugehörige Datei löschen?"
@@ -616,7 +623,7 @@
:project/setup "Paramétrer un projet public sur Logseq"
:project/location "Toutes les pages publiées seront joignables sous"
:project/sync-settings "Synchroniser les paramètres du projet"
:page/presentation-mode "Mode présentation (avec Reveal.js)"
:page/presentation-mode "Mode présentation"
:page/delete-success "Page {1} supprimée !"
:page/delete-confirmation "Etes-vous sûr de vouloir supprimer la page ?"
:page/rename-to "Renommer \"{1}\" en:"
@@ -820,6 +827,10 @@
:right-side-bar/favorites "收藏"
:right-side-bar/page-graph "页面图谱:"
:right-side-bar/block-ref "块引用"
:left-side-bar/new-page "新页面"
:left-side-bar/nav-favorites "收藏页面"
:left-side-bar/nav-shortcuts "快捷导航"
:left-side-bar/nav-recent-pages "最近使用"
:git/set-access-token "设定 GitHub 个人访问令牌"
:git/token-is-encrypted "令牌将被加密并存储在浏览器本地存储"
:git/token-server "服务器将永远不会存储它"
@@ -856,7 +867,7 @@
:project/location "一切发布的页面将会被放到 "
:project/sync-settings "同步项目设置"
:page/edit-properties-placeholder "点击这里编辑当前页面的属性 (标签,别名等)"
:page/presentation-mode "演讲模式 (由 Reveal.js 驱动)"
:page/presentation-mode "打开幻灯片"
:page/delete-success "页面 {1} 删除成功!"
:page/delete-confirmation "您确定要删除此页面和文件吗?"
:page/rename-to "重命名 \"{1}\" 至:"
@@ -875,6 +886,7 @@
:page/publish-as-slide "将本页作为幻灯片发布至 Logseq"
:page/unpublish "取消将本页发布至 Logseq"
:page/add-to-favorites "添加收藏"
:page/unfavorite "取消收藏"
:page/show-journals "显示日志"
:page/show-name "显示页面名"
:page/hide-name "隐藏页面名"
@@ -957,6 +969,8 @@
:new-graph "添加图谱"
:re-index "重新建立索引"
:sync-from-local-files "刷新(读取本地最新文件)"
:export-graph "导出图谱"
:export-page "导出当前页面"
:export-json "以 JSON 格式导出"
:export-roam-json "以 Roam JSON 格式导出"
:export-markdown "以 Markdown 格式导出"
@@ -1161,7 +1175,7 @@
:project/setup "在 Logseq 上發布新的項目"
:project/location "一切發布的頁面將會被放到 "
:project/sync-settings "同步項目設置"
:page/presentation-mode "演講模式 (由 Reveal.js 驅動)"
:page/presentation-mode "演講模式"
:page/delete-success "頁面 {1} 刪除成功!"
:page/delete-confirmation "您確定要刪除此頁面嗎?"
:page/rename-to "重命名 \"{1}\" 至:"
@@ -1397,7 +1411,7 @@
:project/setup "Stel 'n publieke projek op by Logseq"
:project/location "Alle gepubliseerde blaai sal voorkom onder"
:project/sync-settings "Sinkroniseer projek instellings"
:page/presentation-mode "Aanbiedings modus (gedryf deur Reveal.js)"
:page/presentation-mode "Aanbiedings modus"
:page/delete-success "Bladsy {1} is suksesvol uitgevee!"
:page/delete-confirmation "Is jy seker jy wil die bladsy uitvee?"
:page/rename-to "Hernoem \"{1}\" na:"
@@ -1618,7 +1632,7 @@
:project/setup "Configurar un proyecto público en Logseq"
:project/location "Todas las páginas publicadas se encontrarán en"
:project/sync-settings "Opciones de sincronización del proyecto"
:page/presentation-mode "Modo presentación (usando Reveal.js)"
:page/presentation-mode "Modo presentación"
:page/edit-properties-placeholder "Propiedades"
:page/delete-success "¡Página {1} eliminada con éxito!"
:page/delete-confirmation "¿Está seguro que desea eliminar esta página y su archivo?"
@@ -1905,7 +1919,7 @@
:project/setup "Sett opp et offentlig prosjekt på Logseq"
:project/location "Alle publiserte sider vil bli lokalisert under"
:project/sync-settings "Synkroniser prosjektinnstillinger"
:page/presentation-mode "Presentasjonsmodus (Drevet av Reveal.js)"
:page/presentation-mode "Presentasjonsmodus"
:page/edit-properties-placeholder "Egenskaper"
:page/delete-success "Side {1} ble vellykket slettet!"
:page/delete-confirmation "Er du sikker på at du vil slette denne siden og filen dens?"
@@ -2205,7 +2219,7 @@
:project/setup "Configurar um projeto público em Logseq"
:project/location "Todas as páginas publicadas ficarão localizadas em"
:project/sync-settings "Definições de sincronização do projeto"
:page/presentation-mode "Modo de apresentação (usando Reveal.js)"
:page/presentation-mode "Modo de apresentação"
:page/edit-properties-placeholder "Propriedades"
:page/delete-success "Página {1} apagada com sucesso!"
:page/delete-confirmation "Tem a certeza de que quer apagar esta página e o respetivo ficheiro?"

View File

@@ -1084,8 +1084,8 @@
(if (or (= status-doc :loading)
(nil? initial-hls))
[:div.flex.justify-center.items-center.h-screen.text-gray-500.text-md
"Downloading PDF file " url]
[:div.flex.justify-center.items-center.h-screen.text-gray-500.text-lg
svg/loading]
[(rum/with-key (pdf-viewer
url initial-hls

View File

@@ -678,6 +678,14 @@ body.is-pdf-active {
#head {
padding-left: 0;
}
#main-content.is-left-sidebar-open {
padding-left: unset;
}
.ls-left-sidebar-open .cp__header {
margin-left: unset;
}
}
/* overrides for pdf_viewer.css from PDF.JS web viewer */

View File

@@ -515,6 +515,16 @@
(component-macro/register cloze-macro-name cloze-macro-show)
(defn get-srs-cards-total
[]
(let [repo (state/get-current-repo)
query-string ""
*query-result (query repo query-string)]
(when *query-result
(let [blocks (rum/react *query-result)
{:keys [result]} (query-scheduled repo blocks (tl/local-now))]
(count result)))))
;;; register cards macro
(rum/defcs cards
< rum/reactive

View File

@@ -6,6 +6,7 @@
[frontend.components.diff :as diff]
[frontend.components.plugins :as plugin]
[frontend.components.encryption :as encryption]
[frontend.components.modals :as modals]
[frontend.components.git :as git-component]
[frontend.components.shell :as shell]
[frontend.components.search :as search]
@@ -53,6 +54,9 @@
(defmethod handle :repo/install-error [[_ repo-url title]]
(show-install-error! repo-url title))
(defmethod handle :modal/show-new-page-modal []
(modals/show-new-page-modal!))
(defmethod handle :modal/encryption-setup-dialog [[_ repo-url close-fn]]
(state/set-modal!
(encryption/encryption-setup-dialog repo-url close-fn)))

View File

@@ -19,6 +19,7 @@
[frontend.handler.route :as route-handler]
[frontend.handler.ui :as ui-handler]
[frontend.handler.web.nfs :as web-nfs]
[frontend.handler.config :as config-handler]
[frontend.modules.outliner.core :as outliner-core]
[frontend.modules.outliner.file :as outliner-file]
[frontend.modules.outliner.tree :as outliner-tree]
@@ -204,32 +205,6 @@
(p/catch (fn [err]
(js/console.error "error: " err)))))))
(defn delete!
[page-name ok-handler]
(when page-name
(when-let [repo (state/get-current-repo)]
(let [page-name (string/lower-case page-name)
blocks (db/get-page-blocks page-name)
tx-data (mapv
(fn [block]
[:db.fn/retractEntity [:block/uuid (:block/uuid block)]])
blocks)]
(db/transact! tx-data)
(delete-file! repo page-name)
;; if other page alias this pagename,
;; then just remove some attrs of this entity instead of retractEntity
(if (model/get-alias-source-page (state/get-current-repo) page-name)
(when-let [id (:db/id (db/entity [:block/name page-name]))]
(let [txs (mapv (fn [attribute]
[:db/retract id attribute])
db-schema/retract-page-attributes)]
(db/transact! txs)))
(db/transact! [[:db.fn/retractEntity [:block/name page-name]]]))
(ok-handler)))))
(defn- compute-new-file-path
[old-path new-page-name]
(let [result (string/split old-path "/")
@@ -344,6 +319,53 @@
(p/let [_ (rename-file-aux! repo old-path new-path)]
(println "Renamed " old-path " to " new-path)))))))
(defn favorite-page!
[page-name]
(when-not (string/blank? page-name)
(let [favorites (->
(cons
page-name
(or (:favorites (state/get-config)) []))
(distinct)
(vec))]
(config-handler/set-config! :favorites favorites))))
(defn unfavorite-page!
[page-name]
(when-not (string/blank? page-name)
(let [favorites (->> (:favorites (state/get-config))
(remove #(= (string/lower-case %) (string/lower-case page-name)))
(vec))]
(config-handler/set-config! :favorites favorites))))
(defn delete!
[page-name ok-handler]
(when page-name
(when-let [repo (state/get-current-repo)]
(let [page-name (string/lower-case page-name)
blocks (db/get-page-blocks page-name)
tx-data (mapv
(fn [block]
[:db.fn/retractEntity [:block/uuid (:block/uuid block)]])
blocks)]
(db/transact! tx-data)
(delete-file! repo page-name)
;; if other page alias this pagename,
;; then just remove some attrs of this entity instead of retractEntity
(if (model/get-alias-source-page (state/get-current-repo) page-name)
(when-let [id (:db/id (db/entity [:block/name page-name]))]
(let [txs (mapv (fn [attribute]
[:db/retract id attribute])
db-schema/retract-page-attributes)]
(db/transact! txs)))
(db/transact! [[:db.fn/retractEntity [:block/name page-name]]]))
(unfavorite-page! page-name)
(ok-handler)))))
(defn- rename-page-aux [old-name new-name]
(when-let [repo (state/get-current-repo)]
(when-let [page (db/pull [:block/name (string/lower-case old-name)])]
@@ -417,6 +439,9 @@
(repo-handler/push-if-auto-enabled! repo)
(p/let [_ (unfavorite-page! old-name)]
(favorite-page! new-name))
(ui-handler/re-render-root!))))
(defn rename!
@@ -438,14 +463,27 @@
:else
(rename-page-aux old-name new-name)))))
(defn handle-add-page-to-contents!
[page-name]
(let [content (str "[[" page-name "]]")]
(editor-handler/api-insert-new-block!
content
{:page "Contents"})
(notification/show! (util/format "Added to %s!" (state/get-favorites-name)) :success)
(editor-handler/clear-when-saved!)))
(defn- split-col-by-element
[col element]
(let [col (vec col)
idx (.indexOf col element)]
[(subvec col 0 (inc idx))
(subvec col (inc idx))]))
(defn reorder-favorites!
[{:keys [to up?]}]
(let [favorites (:favorites (state/get-config))
from (get @state/state :favorites/dragging)]
(when (and from to (not= from to))
(let [[prev next] (split-col-by-element favorites to)
[prev next] (mapv #(remove (fn [e] (= from e)) %) [prev next])
favorites (->>
(if up?
(concat (drop-last prev) [from (last prev)] next)
(concat prev [from] next))
(remove nil?)
(distinct))]
(config-handler/set-config! :favorites favorites)))))
(defn has-more-journals?
[]

View File

@@ -66,6 +66,24 @@
(when-not file-exists?
(file-handler/reset-file! repo-url path default-content)))))
(defn create-favorites-file
[repo-url]
(spec/validate :repos/url repo-url)
(let [repo-dir (config/get-repo-dir repo-url)
format (state/get-preferred-format)
path (str (state/get-pages-directory)
"/favorites."
(config/get-file-extension format))
file-path (str "/" path)
default-content (case (name format)
"org" (rc/inline "favorites.org")
"markdown" (rc/inline "favorites.md")
"")]
(p/let [_ (fs/mkdir-if-not-exists (str repo-dir "/" (state/get-pages-directory)))
file-exists? (fs/create-if-not-exists repo-url repo-dir file-path default-content)]
(when-not file-exists?
(file-handler/reset-file! repo-url path default-content)))))
(defn create-custom-theme
[repo-url]
(spec/validate :repos/url repo-url)
@@ -145,6 +163,7 @@
;; TODO: move to frontend.handler.file
(create-config-file-if-not-exists repo-url)
(create-contents-file repo-url)
(create-favorites-file repo-url)
(create-custom-theme repo-url)
(state/pub-event! [:page/create-today-journal repo-url])))))
@@ -554,6 +573,7 @@
(create-today-journal-if-not-exists repo {:content tutorial})))
(create-config-file-if-not-exists repo)
(create-contents-file repo)
(create-favorites-file repo)
(create-custom-theme repo)
(state/set-db-restoring! false)
(ui-handler/re-render-root!)))

View File

@@ -15,6 +15,11 @@
(when-let [elem (gdom/getElement "close-left-bar")]
(.click elem)))
(defn toggle-left-sidebar!
[]
(state/set-left-sidebar-open!
(not (@state/state :ui/left-sidebar-open?))))
(defn hide-right-sidebar
[]
(state/hide-right-sidebar!))

View File

@@ -43,11 +43,11 @@
^{:before m/prevent-default-behavior}
{:pdf/previous-page
{:desc "Previous page of current pdf doc"
:binding "ctrl+p"
:binding "alt+p"
:fn pdf-utils/prev-page}
:pdf/next-page
{:desc "Next page of current pdf doc"
:binding "ctrl+n"
:binding "alt+n"
:fn pdf-utils/next-page}}
:shortcut.handler/auto-complete
@@ -142,7 +142,7 @@
:fn editor-handler/strike-through-format!}
:editor/move-block-up
{:desc "Move block up"
:binding (if mac? "mod+shift+up" "alt+shift+up")
:binding (if mac? "mod+shift+up" "alt+shift+up")
:fn (editor-handler/move-up-down true)}
:editor/move-block-down
{:desc "Move block down"
@@ -185,13 +185,13 @@
:binding (if mac? false "alt+w")
:fn editor-handler/backward-kill-word}
:editor/replace-block-reference-at-point
{:desc "Replace block reference with its content at point"
{:desc "Replace block reference with its content at point"
:binding "mod+shift+r"
:fn editor-handler/replace-block-reference-with-content-at-point}
:fn editor-handler/replace-block-reference-with-content-at-point}
:editor/paste-text-in-one-block-at-point
{:desc "Paste text into one block at point"
{:desc "Paste text into one block at point"
:binding "mod+shift+v"
:fn editor-handler/paste-text-in-one-block-at-point}
:fn editor-handler/paste-text-in-one-block-at-point}
:editor/insert-youtube-timestamp
{:desc "Insert youtube timestamp"
:binding "mod+shift+y"
@@ -264,7 +264,11 @@
:editor/redo
{:desc "Redo"
:binding ["shift+mod+z" "mod+y"]
:fn history/redo!}}
:fn history/redo!}
:editor/new-page
{:desc "New page"
:binding "mod+n"
:fn #(state/pub-event! [:modal/show-new-page-modal])}}
:shortcut.handler/global-prevent-default
^{:before m/prevent-default-behavior}
@@ -327,12 +331,12 @@
;; always overrides the copy due to "mod+c mod+s"
{:misc/copy
{:binding "mod+c"
:fn (fn [] (js/document.execCommand "copy"))}
:fn (fn [] (js/document.execCommand "copy"))}
:command-palette/toggle
{:desc "Toggle command palette"
{:desc "Toggle command palette"
:binding "mod+shift+p"
:fn (fn [] (state/toggle! :ui/command-palette-open?))}}
:fn (fn [] (state/toggle! :ui/command-palette-open?))}}
:shortcut.handler/global-non-editing-only
^{:before m/enable-when-not-editing-mode!}
@@ -360,6 +364,10 @@
{:desc "Toggle right sidebar"
:binding "t r"
:fn ui-handler/toggle-right-sidebar!}
:ui/toggle-left-sidebar
{:desc "Toggle left sidebar"
:binding "t l"
:fn ui-handler/toggle-left-sidebar!}
:ui/toggle-help
{:desc "Toggle help"
:binding "shift+/"
@@ -378,11 +386,11 @@
:fn ui-handler/toggle-wide-mode!}
:ui/select-theme-color
{:desc "Select available theme colors"
:binding "t i"
:binding "t i"
:fn plugin-handler/show-themes-modal!}
:ui/goto-plugins
{:desc "Go to plugins dashboard"
:binding "t p"
:binding "t p"
:fn plugin-handler/goto-plugins-dashboard!}
:editor/toggle-open-blocks
{:desc "Toggle open blocks (collapse or expand all blocks)"

View File

@@ -61,7 +61,7 @@
:ui/fullscreen? false
:ui/settings-open? false
:ui/sidebar-open? false
:ui/left-sidebar-open? false
:ui/left-sidebar-open? (boolean (storage/get "ls-left-sidebar-open?"))
:ui/theme (or (storage/get :ui/theme) "dark")
:ui/system-theme? ((fnil identity (or util/mac? util/win32? false)) (storage/get :ui/system-theme?))
:ui/wide-mode? false
@@ -103,6 +103,8 @@
:editor/document-mode? document-mode?
:editor/args nil
:editor/on-paste? false
:editor/recent-pages nil
:db/last-transact-time {}
:db/last-persist-transact-ids {}
;; whether database is persisted
@@ -171,7 +173,9 @@
:debug/write-acks {}
:encryption/graph-parsing? false})))
:encryption/graph-parsing? false
:favorites/dragging nil})))
(defn sub
@@ -1117,6 +1121,7 @@
(defn set-left-sidebar-open!
[value]
(storage/set "ls-left-sidebar-open?" (boolean value))
(set-state! :ui/left-sidebar-open? value))
(defn set-developer-mode!

View File

@@ -99,13 +99,15 @@
(on-click-fn e))
(close-fn)))
child (if hr
[:hr.my-1]
nil
[:div
{:style {:display "flex" :flex-direction "row"}}
[:div {:style {:margin-right "8px"}} title]])]
(rum/with-key
(menu-link new-options child)
title)))
(if hr
[:hr.my-1]
(rum/with-key
(menu-link new-options child)
title))))
(when links-footer links-footer)])
opts))
@@ -710,6 +712,7 @@
:options {:theme (when (= (state/sub :ui/theme) "dark") "dark")}
:on-tweet-load-success #(reset! *loading? false)})]]))
(rum/defc icon
[class]
[:i {:class (str "ti ti-" class)}])
(defn icon
([class] (icon class nil))
([class opts]
[:i (merge {:class (str "ti ti-" class)} opts)]))

View File

@@ -14,6 +14,7 @@
[frontend.db.query-dsl :as query-dsl]
[frontend.db.utils :as db-utils]
[frontend.fs :as fs]
[frontend.handler :as handler]
[frontend.handler.dnd :as editor-dnd-handler]
[frontend.handler.editor :as editor-handler]
[frontend.handler.export :as export-handler]
@@ -22,6 +23,7 @@
[frontend.handler.plugin :as plugin-handler]
[frontend.modules.outliner.core :as outliner]
[frontend.modules.outliner.tree :as outliner-tree]
[electron.listener :as el]
[frontend.state :as state]
[frontend.util :as util]
[frontend.util.cursor :as cursor]
@@ -520,3 +522,8 @@
([content status] (let [hiccup? (and (string? content) (string/starts-with? (string/triml content) "[:"))
content (if hiccup? (parse-hiccup-ui content) content)]
(notification/show! content (keyword status)))))
(defn ^:export force_save_graph
[]
(p/let [_ (el/persist-dbs!)
_ (reset! handler/triggered? true)]))

View File

@@ -40,12 +40,12 @@
;; If not specified, Logseq default opens journals page on startup
;; value for `:page` is name of page
;; Possible options for `:sidebar` are
;; 1. `"Contents"` to open up `Favorites` in sidebar by default
;; 1. `"Contents"` to open up `Contents` in sidebar by default
;; 2. `page name` to open up some page in sidebar
;; 3. Or multiple pages in an array ["Contents" "Page A" "Page B"]
;; If `:sidebar` is not set, sidebar will be hidden
;; Example:
;; 1. Setup page "Changelog" as home page and "Favorites" in sidebar
;; 1. Setup page "Changelog" as home page and "Contents" in sidebar
;; :default-home {:page "Changelog", :sidebar "Contents"}
;; 2. Setup page "Jun 3rd, 2021" as home page without sidebar
;; :default-home {:page "Jun 3rd, 2021"}

1
templates/favorites.md Normal file
View File

@@ -0,0 +1 @@
-

1
templates/favorites.org Normal file
View File

@@ -0,0 +1 @@
*

View File

@@ -7862,11 +7862,6 @@ react-grid-layout@^0.16.6:
react-draggable "3.x"
react-resizable "1.x"
react-icon-base@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-icon-base/-/react-icon-base-2.1.0.tgz#a196e33fdf1e7aaa1fda3aefbb68bdad9e82a79d"
integrity sha1-oZbjP98eeqof2jrvu2i9rZ6Cp50=
react-icons@^2.2.7:
version "2.2.7"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-2.2.7.tgz#d7860826b258557510dac10680abea5ca23cf650"