Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Chore (UI): Resizable component #11049

Draft
wants to merge 7 commits into
base: feat/db
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions deps/shui/src/logseq/shui/resizable/core.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(ns logseq.shui.resizable.core
(:require [logseq.shui.util :as util]))

(def resizable-panel-group (util/lsui-wrap "ResizablePanelGroup"))
(def resizable-panel (util/lsui-wrap "ResizablePanel"))
(def resizable-handle (util/lsui-wrap "ResizableHandle"))
9 changes: 7 additions & 2 deletions deps/shui/src/logseq/shui/ui.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
[logseq.shui.select.core :as select-core]
[logseq.shui.dialog.core :as dialog-core]
[logseq.shui.popup.core :as popup-core]
[logseq.shui.form.core :as form-core]))
[logseq.shui.form.core :as form-core]
[logseq.shui.resizable.core :as resizable]))

(def button (util/lsui-wrap "Button" {:static? false}))
(def link (util/lsui-wrap "Link"))
Expand Down Expand Up @@ -111,4 +112,8 @@
(def dialog-close-all! dialog-core/close-all!)
(def popup-show! popup-core/show!)
(def popup-hide! popup-core/hide!)
(def popup-hide-all! popup-core/hide-all!)
(def popup-hide-all! popup-core/hide-all!)

(def resizable-panel-group resizable/resizable-panel-group)
(def resizable-panel resizable/resizable-panel)
(def resizable-handle resizable/resizable-handle)
43 changes: 43 additions & 0 deletions packages/ui/@/components/ui/resizable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { GripVertical } from "lucide-react"
import * as ResizablePrimitive from "react-resizable-panels"

import { cn } from "@/lib/utils"

const ResizablePanelGroup = ({
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
<ResizablePrimitive.PanelGroup
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
className
)}
{...props}
/>
)

const ResizablePanel = ResizablePrimitive.Panel

const ResizableHandle = ({
withHandle,
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
withHandle?: boolean
}) => (
<ResizablePrimitive.PanelResizeHandle
className={cn(
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
<div className="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
)

export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"react-day-picker": "^8.9.1",
"react-dom": "^18",
"react-hook-form": "^7.48.2",
"react-resizable-panels": "^2.0.11",
"tailwind-merge": "^2.0.0",
"tailwindcss-animate": "^1.0.7",
"yup": "^1.3.2",
Expand Down
4 changes: 3 additions & 1 deletion packages/ui/src/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import { Link } from '@/components/ui/link'
import { Separator } from '@/components/ui/separator'
import { Toggle } from '@/components/ui/toggle'
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@/components/ui/resizable'

declare global {
var LSUI: any
Expand Down Expand Up @@ -180,7 +181,8 @@ const shadui = {
AlertDialogCancel,
Tooltip, TooltipTrigger, TooltipArrow,
TooltipContent, TooltipProvider,
Toggle, ToggleGroup, ToggleGroupItem
Toggle, ToggleGroup, ToggleGroupItem,
ResizablePanelGroup, ResizablePanel, ResizableHandle
}

function setupGlobals() {
Expand Down
5 changes: 5 additions & 0 deletions packages/ui/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8197,6 +8197,11 @@ [email protected]:
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"

react-resizable-panels@^2.0.11:
version "2.0.11"
resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-2.0.11.tgz#7f7e116d5fb7e1a03c436a69be9f567fe0ecd531"
integrity sha512-tA3OvGFEK/U9rKuEg6TpXcr+i+cN5X8B4UIvs7jqr5lby629pDTGvqRjo1EJLhBpRZfkg0Zz1INJlSYigaS99g==

react-style-singleton@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
Expand Down
72 changes: 40 additions & 32 deletions src/main/frontend/components/container.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -906,38 +906,46 @@
(when (= (.-key e) "Enter")
(ui/focus-element (ui/main-node))))}
(t :accessibility/skip-to-main-content)]
[:div.#app-container
[:div#left-container
{:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
(header/header {:open-fn open-fn
:light? light?
:current-repo current-repo
:logged? logged?
:page? page?
:route-match route-match
:default-home default-home
:new-block-mode new-block-mode})
(when (util/electron?)
(find-in-page/search))

(main {:route-match route-match
:margin-less-pages? margin-less-pages?
:logged? logged?
:home? home?
:route-name route-name
:indexeddb-support? indexeddb-support?
:light? light?
:db-restoring? db-restoring?
:main-content main-content
:show-action-bar? show-action-bar?
:show-recording-bar? show-recording-bar?})]

(when window-controls?
(window-controls/container))

(right-sidebar/sidebar)

[:div#app-single-container]]
(shui/resizable-panel-group
{:id "app-container"
:direction "horizontal"
:autoSaveId "app-container-group"}
(shui/resizable-panel
{:id "left-container"
:order 1
:minSize 50
:class (if (state/sub :ui/sidebar-open?) "overflow-hidden" "w-full")}
[:<>
(header/header {:open-fn open-fn
:light? light?
:current-repo current-repo
:logged? logged?
:page? page?
:route-match route-match
:default-home default-home
:new-block-mode new-block-mode})
(when (util/electron?)
(find-in-page/search))

(main {:route-match route-match
:margin-less-pages? margin-less-pages?
:logged? logged?
:home? home?
:route-name route-name
:indexeddb-support? indexeddb-support?
:light? light?
:db-restoring? db-restoring?
:main-content main-content
:show-action-bar? show-action-bar?
:show-recording-bar? show-recording-bar?})])

(when window-controls?
(window-controls/container))

(when sidebar-open?
(right-sidebar/sidebar))

[:div#app-single-container])

(ui/notification)
(ui/modal)
Expand Down
53 changes: 27 additions & 26 deletions src/main/frontend/components/container.css
Original file line number Diff line number Diff line change
Expand Up @@ -587,39 +587,40 @@
}
}

.cp__right-sidebar {
z-index: var(--ls-z-index-level-1);
transition: width 0.3s;
position: relative;
user-select: none;

.resizer {
@apply absolute top-0 bottom-0;

touch-action: none;
left: 1px;
width: 3px;
user-select: none;
cursor: col-resize !important;
.resizer-handle {
@apply relative;

transition: background-color 300ms;
transition-delay: 300ms;
z-index: 1000;
&:after {
content: "";
display: block;
z-index: 1;
position: absolute;
transition: background-color .3s;
}

&:hover,
&:focus,
&:active {
@apply bg-primary/90;
}
&[data-panel-group-direction="vertical"]:after {
width: 100%;
top: -2px;
height: 5px;
}

&.closed {
width: 0 !important;
&[data-panel-group-direction="horizontal"]:after {
width: 5px;
left: -2px;
height: 100%;
}

&.open {
max-width: 60vw;
&[data-resize-handle-state="drag"] {
&:after {
@apply bg-primary/90
}
}
}

.cp__right-sidebar {
z-index: var(--ls-z-index-level-1);
position: relative;
user-select: none;

&-scollable {
min-height: 100%;
Expand Down
106 changes: 11 additions & 95 deletions src/main/frontend/components/right_sidebar.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -334,93 +334,6 @@
(let [match (:route-match @state/state)]
(get-page match)))

(rum/defc sidebar-resizer
[sidebar-open? sidebar-id handler-position]
(let [el-ref (rum/use-ref nil)
min-px-width 320 ; Custom window controls width
min-ratio 0.1
max-ratio 0.7
keyboard-step 5
add-resizing-class #(.. js/document.documentElement -classList (add "is-resizing-buf"))
remove-resizing-class (fn []
(.. js/document.documentElement -classList (remove "is-resizing-buf"))
(reset! ui-handler/*right-sidebar-resized-at (js/Date.now)))
set-width! (fn [ratio]
(when el-ref
(let [value (* ratio 100)
width (str value "%")]
(.setAttribute (rum/deref el-ref) "aria-valuenow" value)
(ui-handler/persist-right-sidebar-width! width))))]
(rum/use-effect!
(fn []
(when-let [el (and (fn? js/window.interact) (rum/deref el-ref))]
(-> (js/interact el)
(.draggable
(bean/->js
{:listeners
{:move
(fn [^js/MouseEvent e]
(let [width js/document.documentElement.clientWidth
min-ratio (max min-ratio (/ min-px-width width))
sidebar-el (js/document.getElementById sidebar-id)
offset (.-pageX e)
ratio (.toFixed (/ offset width) 6)
ratio (if (= handler-position :west) (- 1 ratio) ratio)
cursor-class (str "cursor-" (first (name handler-position)) "-resize")]
(if (= (.getAttribute el "data-expanded") "true")
(cond
(< ratio (/ min-ratio 2))
(state/hide-right-sidebar!)

(< ratio min-ratio)
(.. js/document.documentElement -classList (add cursor-class))

(and (< ratio max-ratio) sidebar-el)
(when sidebar-el
(#(.. js/document.documentElement -classList (remove cursor-class))
(set-width! ratio)))
:else
#(.. js/document.documentElement -classList (remove cursor-class)))
(when (> ratio (/ min-ratio 2)) (state/open-right-sidebar!)))))}}))
(.styleCursor false)
(.on "dragstart" add-resizing-class)
(.on "dragend" remove-resizing-class)
(.on "keydown" (fn [e]
(when-let [sidebar-el (js/document.getElementById sidebar-id)]
(let [width js/document.documentElement.clientWidth
min-ratio (max min-ratio (/ min-px-width width))
keyboard-step (case (.-code e)
"ArrowLeft" (- keyboard-step)
"ArrowRight" keyboard-step
0)
offset (+ (.-x (.getBoundingClientRect sidebar-el)) keyboard-step)
ratio (.toFixed (/ offset width) 6)
ratio (if (= handler-position :west) (- 1 ratio) ratio)]
(when (and (> ratio min-ratio) (< ratio max-ratio) (not (zero? keyboard-step)))
(do (add-resizing-class)
(set-width! ratio)))))))
(.on "keyup" remove-resizing-class)))
#())
[])

(rum/use-effect!
(fn []
;; sidebar animation duration
(js/setTimeout
#(reset! ui-handler/*right-sidebar-resized-at (js/Date.now)) 300))
[sidebar-open?])

[:.resizer
{:ref el-ref
:role "separator"
:aria-orientation "vertical"
:aria-label (t :right-side-bar/separator)
:aria-valuemin (* min-ratio 100)
:aria-valuemax (* max-ratio 100)
:aria-valuenow 50
:tabIndex "0"
:data-expanded sidebar-open?}]))

(rum/defcs sidebar-inner <
(rum/local false ::anim-finished?)
{:will-mount (fn [state]
Expand Down Expand Up @@ -481,12 +394,15 @@
blocks (if (empty? blocks)
[[(state/get-current-repo) "contents" :contents nil]]
blocks)
sidebar-open? (state/sub :ui/sidebar-open?)
width (state/sub :ui/sidebar-width)
repo (state/sub :git/current-repo)]
[:div#right-sidebar.cp__right-sidebar.h-screen
{:class (if sidebar-open? "open" "closed")
:style {:width width}}
(sidebar-resizer sidebar-open? "right-sidebar" :west)
(when sidebar-open?
(sidebar-inner repo t blocks))]))
[:<>
(shui/resizable-handle
{:class "resizer-handle"
:id "right-sidebar-handle"})
(shui/resizable-panel
{:id "right-sidebar"
:class "cp__right-sidebar h-screen"
:order 2
:minSize 10
:defaultSize 40}
(sidebar-inner repo t blocks))]))