enhance(mobile): fixed position of head-bar & mobile-bar (#3360)

enhance(mobile): fixed position of head-bar & mobile-bar
Co-authored-by: charlie <xyhp915@qq.com>
pull/3355/head^2
Tienson Qin 2021-12-07 13:40:47 +08:00 committed by GitHub
parent 74c2606300
commit d9452bd739
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 201 additions and 144 deletions

View File

@ -9,6 +9,8 @@
--ls-scrollbar-width: 6px;
--ls-border-radius-low: 4px;
--ls-border-radius-medium: 8px;
--ls-headbar-height: 3rem;
--ls-headbar-inner-top-padding: 0px;
--ls-left-sidebar-width: 240px;
--ls-left-sidebar-nav-btn-size: 38px;
}

View File

@ -8,6 +8,7 @@
[frontend.components.search :as search]
[frontend.components.svg :as svg]
[frontend.config :as config]
[frontend.handler.notification :as notification]
[frontend.db :as db]
[frontend.extensions.zotero :as zotero]
[frontend.handler.editor :as editor-handler :refer [get-state]]
@ -217,91 +218,99 @@
(rum/defc mobile-bar < rum/reactive
[parent-state parent-id]
[:div#mobile-editor-toolbar.bg-base-2.fix-ios-fixed-bottom
[:div.flex.justify-around.w-full
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/indent-outdent true))}
(ui/icon "arrow-bar-right"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/indent-outdent false))}
(ui/icon "arrow-bar-left"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
((editor-handler/move-up-down true)))}
(ui/icon "arrow-bar-to-up"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
((editor-handler/move-up-down false)))}
(ui/icon "arrow-bar-to-down"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert! parent-id "\n"
{:forward-pos 1})
;; TODO: should we add this focus step to `simple-insert!`?
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "arrow-back"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/cycle-todo!))}
(ui/icon "checkbox"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert!
parent-id "[[]]"
{:backward-pos 2
:check-fn (fn [_ _ new-pos]
(reset! commands/*slash-caret-pos new-pos)
(commands/handle-step [:editor/search-page]))})
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "brackets"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert!
parent-id "(())"
{:backward-pos 2
:check-fn (fn [_ _ new-pos]
(reset! commands/*slash-caret-pos new-pos)
(commands/handle-step [:editor/search-block]))})
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "parentheses"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert! parent-id "/" {})
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "command"
{:style {:fontSize ui/icon-size}})]]]])
(let [vw-state (state/sub :ui/visual-viewport-state)
vw-pending? (state/sub :ui/visual-viewport-pending?)]
[:div#mobile-editor-toolbar.bg-base-2
{:style {:bottom (if (and vw-state)
(- (.-clientHeight js/document.documentElement)
(:height vw-state)
(:offset-top vw-state))
0)}
:class (util/classnames [{:is-vw-pending (boolean vw-pending?)}])}
[:div.flex.justify-around.w-full
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/indent-outdent true))}
(ui/icon "arrow-bar-right"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/indent-outdent false))}
(ui/icon "arrow-bar-left"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
((editor-handler/move-up-down true)))}
(ui/icon "arrow-bar-to-up"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
((editor-handler/move-up-down false)))}
(ui/icon "arrow-bar-to-down"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert! parent-id "\n"
{:forward-pos 1})
;; TODO: should we add this focus step to `simple-insert!`?
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "arrow-back"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/cycle-todo!))}
(ui/icon "checkbox"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert!
parent-id "[[]]"
{:backward-pos 2
:check-fn (fn [_ _ new-pos]
(reset! commands/*slash-caret-pos new-pos)
(commands/handle-step [:editor/search-page]))})
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "brackets"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert!
parent-id "(())"
{:backward-pos 2
:check-fn (fn [_ _ new-pos]
(reset! commands/*slash-caret-pos new-pos)
(commands/handle-step [:editor/search-block]))})
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "parentheses"
{:style {:fontSize ui/icon-size}})]]
[:div
[:button.bottom-action
{:on-mouse-down (fn [e]
(util/stop e)
(commands/simple-insert! parent-id "/" {})
(when-let [input (gdom/getElement parent-id)]
(.focus input)))}
(ui/icon "command"
{:style {:fontSize ui/icon-size}})]]]]))
(rum/defcs input < rum/reactive
(rum/local {} ::input-value)

View File

@ -1,15 +1,15 @@
#mobile-editor-toolbar {
position: fixed;
bottom: 0;
width: 100%;
left: 0;
width: 100%;
justify-content: center;
height: 2.5rem;
display: flex;
align-items: center;
z-index: 9999;
transition: top 0.3s;
transition: none;
button {
padding: 10px;

View File

@ -161,6 +161,8 @@
(let [repos (->> (state/sub [:me :repos])
(remove #(= (:url %) config/local-repo)))
electron-mac? (and util/mac? (util/electron?))
vw-state (state/sub :ui/visual-viewport-state)
vw-pending? (state/sub :ui/visual-viewport-pending?)
show-open-folder? (and (or (nfs/supported?)
(mobile-util/is-native-platform?))
(empty? repos)
@ -168,15 +170,17 @@
refreshing? (state/sub :nfs/refreshing?)]
(rum/with-context [[t] i18n/*tongue-context*]
[:div.cp__header#head
{:class (cond electron-mac? "electron-mac"
(mobile-util/native-ios?) "native-ios"
(mobile-util/native-android?) "native-android")
{:class (util/classnames [{:electron-mac electron-mac?
:native-ios (mobile-util/native-ios?)
:native-android (mobile-util/native-android?)
:is-vw-pending (boolean vw-pending?)}])
:on-double-click (fn [^js e]
(when-let [target (.-target e)]
(when (and (util/electron?)
(or (.. target -classList (contains "cp__header"))))
(js/window.apis.toggleMaxOrMinActiveWindow))))
:style {:fontSize 50}}
:style {:fontSize 50
:transform (str "translateY(" (or (:offset-top vw-state) 0) "px)")}}
[:div.l.flex
(left-menu-button {:on-click (fn []
(open-fn)

View File

@ -1,8 +1,10 @@
.cp__header {
@apply shadow z-10 h-12;
@apply shadow z-10;
-webkit-app-region: drag;
padding-right: 0.5rem;
padding-top: var(--ls-headbar-inner-top-padding);
height: calc(var(--ls-headbar-height) + var(--ls-headbar-inner-top-padding));
display: flex;
align-items: center;
justify-content: space-between;
@ -170,3 +172,23 @@ a.button {
.is-mac.is-electron :is(.cp__header, .cp__right-sidebar-topbar) :is(button, .button, a) {
cursor: default !important;
}
html.is-native-ios,
html.is-ios.is-safari {
#main-container {
padding-top: 20px;
}
.cp__header {
position: fixed !important;
background-color: var(--ls-primary-background-color);
}
.is-vw-pending {
display: none !important;
}
}
html.is-native-ios {
--ls-headbar-inner-top-padding: 36px;
}

View File

@ -568,8 +568,9 @@
:close-fn close-fn
:route-match route-match})
[:div.#app-container.h-screen.flex {:style {:padding-top (ui/main-content-top-padding)}}
[:div.flex-1.h-full.flex.flex-col#left-container.relative
[:div.#app-container
{:style {:padding-top (ui/main-content-top-padding)}}
[:div#left-container
{:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
(header/header {:open-fn open-fn
:white? white?

View File

@ -1,8 +1,8 @@
@supports(padding: max(0px)) {
.post {
padding-left: max(12px, env(safe-area-inset-left));
padding-right: max(12px, env(safe-area-inset-right));
}
@supports (padding: max(0px)) {
.post {
padding-left: max(12px, env(safe-area-inset-left));
padding-right: max(12px, env(safe-area-inset-right));
}
}
#app-container {
@ -21,9 +21,14 @@
}
#app-container {
display: flex;
flex: 0 0 100%;
}
#left-container {
@apply flex flex-1 flex-col relative h-screen;
}
#main-container {
position: relative;
height: 100%;
@ -44,6 +49,12 @@ html.is-mobile {
#main-content.is-left-sidebar-open {
padding-left: 0;
}
.left-sidebar-inner {
> .wrap {
padding-top: 64px;
}
}
}
#left-sidebar {
@ -64,8 +75,8 @@ html.is-mobile {
#left-bar {
background-color: var(--ls-primary-background-color);
width: 70vw;
max-width: 300px;
width: 70vw;
max-width: 300px;
> .head-wrap {
background-color: var(--ls-search-background-color);
@ -100,10 +111,11 @@ html.is-mobile {
overflow: auto;
> .wrap {
padding-top: 24px;
@screen md {
padding-top: 60px;
}
padding-top: 24px;
@screen md {
padding-top: 55px;
}
}
.dropdown-wrapper {

View File

@ -62,12 +62,6 @@
#(when system-theme?
(ui/setup-system-theme-effect!))
[system-theme?])
(rum/use-effect!
#(when (mobile-util/native-ios?)
(ui/setup-patch-ios-fixed-bottom-position!))
[edit?])
[:div
{:class (str theme "-theme")
:on-click on-click}

View File

@ -17,7 +17,9 @@
(ui/inject-document-devices-envs!)
(ui/inject-dynamic-style-node!)
(plugin-handler/host-mounted!)
(let [teardown-fn (ui/setup-active-keystroke!)]
(let [teardown-fn (comp
(ui/setup-active-keystroke!)
(ui/setup-patch-ios-visual-viewport-state!))]
(assoc state ::teardown teardown-fn)))
:will-unmount (fn [state]
(let [teardown (::teardown state)]

View File

@ -82,6 +82,8 @@
:ui/shortcut-tooltip? (if (false? (storage/get :ui/shortcut-tooltip?))
false
true)
:ui/visual-viewport-pending? false
:ui/visual-viewport-state nil
:document/mode? document-mode?
@ -1578,3 +1580,11 @@
(defn get-last-key-code
[]
(:editor/last-key-code @state))
(defn set-visual-viewport-state
[input]
(set-state! :ui/visual-viewport-state input))
(defn get-visual-viewport-state
[]
(:ui/visual-viewport-state @state))

View File

@ -50,7 +50,6 @@
:else
0))
(defonce icon-size (if (mobile-util/is-native-platform?) 23 20))
(rum/defc ls-textarea
@ -305,35 +304,37 @@
(.appendChild js/document.head node))
style)))
(defn setup-patch-ios-fixed-bottom-position!
"fix a common issue about ios webpage viewport
when soft keyboard setup"
(defn setup-patch-ios-visual-viewport-state!
[]
(when (and
(util/ios?)
(not (nil? js/window.visualViewport)))
(let [viewport js/visualViewport
style (get-dynamic-style-node)
sheet (.-sheet style)
raf-pending? (atom false)
(when-let [^js vp (and (or (and (util/mobile?) (util/safari?))
(mobile-util/native-ios?))
js/window.visualViewport)]
(let [raf-pending? (atom false)
set-raf-pending! #(reset! raf-pending? %)
handler
on-viewport-changed
(fn []
(when-not @raf-pending?
(let [f (fn []
(set-raf-pending! false)
(let [vh (+ (.-offsetTop viewport) (.-height viewport))
rule (.. sheet -rules (item 0))
set-top #(set! (.. rule -style -top) (str % "px"))]
(set-top vh)))]
(set-raf-pending! true)
(js/window.requestAnimationFrame f))))]
(.insertRule sheet ".fix-ios-fixed-bottom {bottom:unset !important; transform: translateY(-100%); top: 100vh;}")
(.addEventListener viewport "resize" handler)
(.addEventListener viewport "scroll" handler)
(let [update-vw-state
(util/debounce 20
(fn []
(state/set-visual-viewport-state {:height (.-height vp)
:page-top (.-pageTop vp)
:offset-top (.-offsetTop vp)})
(state/set-state! :ui/visual-viewport-pending? false)))]
(when-not @raf-pending?
(let [f (fn []
(set-raf-pending! false)
(update-vw-state))]
(set-raf-pending! true)
(state/set-state! :ui/visual-viewport-pending? true)
(js/window.requestAnimationFrame f)))))]
(.addEventListener vp "resize" on-viewport-changed)
(.addEventListener vp "scroll" on-viewport-changed)
(fn []
(.removeEventListener viewport "resize" handler)
(.removeEventListener viewport "scroll" handler)))))
(.removeEventListener vp "resize" on-viewport-changed)
(.removeEventListener vp "scroll" on-viewport-changed)
(state/set-visual-viewport-state nil)))))
(defn setup-system-theme-effect!
[]
@ -471,14 +472,14 @@
(str/split #" |\+"))
sequence)]
[:span.keyboard-shortcut
(map-indexed (fn [i key]
[:code {:key i}
(map-indexed (fn [i key]
[:code {:key i}
;; Display "cmd" rather than "meta" to the user to describe the Mac
;; mod key, because that's what the Mac keyboards actually say.
(if (or (= :meta key) (= "meta" key))
(util/meta-key-name)
(name key))])
sequence)]))
(if (or (= :meta key) (= "meta" key))
(util/meta-key-name)
(name key))])
sequence)]))
(defn keyboard-shortcut-from-config [shortcut-name]
(let [default-binding (:binding (get shortcut-config/all-default-keyboard-shortcuts shortcut-name))