mirror of
https://github.com/penpot/penpot.git
synced 2025-03-12 07:41:43 -05:00
🎉 Add page ordering (with d&d).
This commit is contained in:
parent
11f54f51ea
commit
04d364225c
7 changed files with 91 additions and 51 deletions
|
@ -11,6 +11,7 @@
|
|||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[promesa.core :as p]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.common.pages :as cp]
|
||||
[uxbox.common.exceptions :as ex]
|
||||
[uxbox.common.spec :as us]
|
||||
|
@ -106,6 +107,33 @@
|
|||
|
||||
|
||||
|
||||
;; --- Mutation: Sort Pages
|
||||
|
||||
(s/def ::page-ids (s/every ::us/uuid :kind vector?))
|
||||
(s/def ::reorder-pages
|
||||
(s/keys :req-un [::profile-id ::file-id ::page-ids]))
|
||||
|
||||
(declare update-page-ordering)
|
||||
|
||||
(sm/defmutation ::reorder-pages
|
||||
[{:keys [profile-id file-id page-ids]}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(p/run! #(update-page-ordering conn file-id %)
|
||||
(d/enumerate page-ids))
|
||||
nil))
|
||||
|
||||
(def ^:private sql:update-page-ordering
|
||||
"update page
|
||||
set ordering = $1
|
||||
where id = $2 and file_id = $3")
|
||||
|
||||
(defn- update-page-ordering
|
||||
[conn file-id [ordering page-id]]
|
||||
(-> (db/query-one conn [sql:update-page-ordering ordering page-id file-id])
|
||||
(p/then su/constantly-nil)))
|
||||
|
||||
|
||||
|
||||
;; --- Mutation: Generate Share Token
|
||||
|
||||
(declare assign-page-share-token)
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
and (fp_r.is_admin = true or
|
||||
fp_r.is_owner = true or
|
||||
fp_r.can_edit = true)
|
||||
window pages_w as (partition by f.id order by pg.created_at
|
||||
window pages_w as (partition by f.id order by pg.ordering
|
||||
range between unbounded preceding
|
||||
and unbounded following)
|
||||
order by f.modified_at desc")
|
||||
|
@ -182,7 +182,7 @@
|
|||
where f.id = $1
|
||||
and f.deleted_at is null
|
||||
and pg.deleted_at is null
|
||||
window pages_w as (partition by f.id order by pg.created_at
|
||||
window pages_w as (partition by f.id order by pg.ordering
|
||||
range between unbounded preceding
|
||||
and unbounded following)")
|
||||
|
||||
|
@ -229,22 +229,6 @@
|
|||
(check-edition-permissions! conn profile-id id)
|
||||
(retrieve-file conn id)))
|
||||
|
||||
;; --- Query: Project Files
|
||||
|
||||
;; (declare retrieve-project-files)
|
||||
|
||||
;; (s/def ::project-files
|
||||
;; (s/keys :req-un [::profile-id]
|
||||
;; :opt-un [::project-id]))
|
||||
|
||||
;; (sq/defquery ::project-files
|
||||
;; [{:keys [project-id] :as params}]
|
||||
;; (retrieve-project-files db/pool params))
|
||||
|
||||
;; (defn retrieve-project-files
|
||||
;; [conn {:keys [profile-id project-id]}]
|
||||
;; (-> (db/query conn [sql:project-files profile-id project-id])
|
||||
;; (p/then' (partial mapv decode-row))))
|
||||
|
||||
;; --- Helpers
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
and (fp_r.is_admin = true or
|
||||
fp_r.is_owner = true or
|
||||
fp_r.can_edit = true)
|
||||
window pages_w as (partition by f.id order by pg.created_at
|
||||
window pages_w as (partition by f.id order by pg.ordering
|
||||
range between unbounded preceding
|
||||
and unbounded following)
|
||||
order by f.modified_at desc
|
||||
|
|
|
@ -1326,6 +1326,28 @@
|
|||
[]
|
||||
{:commit-local? true}))))))
|
||||
|
||||
;; --- Change Page Order (D&D Ordering)
|
||||
|
||||
(defn relocate-page
|
||||
[id index]
|
||||
(ptk/reify ::relocate-pages
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [pages (get-in state [:workspace-file :pages])
|
||||
[before after] (split-at index pages)
|
||||
p? (partial = id)
|
||||
pages' (d/concat []
|
||||
(remove p? before)
|
||||
[id]
|
||||
(remove p? after))]
|
||||
(assoc-in state [:workspace-file :pages] pages')))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [file (:workspace-file state)]
|
||||
(->> (rp/mutation! :reorder-pages {:page-ids (:pages file)
|
||||
:file-id (:id file)})
|
||||
(rx/ignore))))))
|
||||
|
||||
;; --- Shape / Selection Alignment and Distribution
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
(ns uxbox.main.ui.dashboard.grid
|
||||
(:refer-clojure :exclude [sort-by])
|
||||
(:require
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]
|
||||
|
@ -11,7 +10,6 @@
|
|||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
||||
[uxbox.main.ui.components.context-menu :refer [context-menu]]
|
||||
[uxbox.util.data :refer [classnames]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :as i18n :refer [t tr]]
|
||||
[uxbox.util.router :as rt]
|
||||
|
@ -75,7 +73,7 @@
|
|||
:default-value (:name file)}]
|
||||
[:h3 (:name file)])
|
||||
[:& grid-item-metadata {:modified-at (:modified-at file)}]]
|
||||
[:div.project-th-actions {:class (classnames
|
||||
[:div.project-th-actions {:class (dom/classnames
|
||||
:force-display (:menu-open @local))}
|
||||
;; [:div.project-th-icon.pages
|
||||
;; i/page
|
||||
|
|
|
@ -162,7 +162,6 @@
|
|||
]
|
||||
[:li {:on-context-menu on-context-menu
|
||||
:ref dref
|
||||
:data-index index
|
||||
:class (dom/classnames
|
||||
:dnd-over-top (= (:over dprops) :top)
|
||||
:dnd-over-bot (= (:over dprops) :bot)
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.store :as st]
|
||||
|
@ -17,7 +18,7 @@
|
|||
[uxbox.main.ui.confirm :refer [confirm-dialog]]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.ui.modal :as modal]
|
||||
[uxbox.util.data :refer [classnames enumerate]]
|
||||
[uxbox.main.ui.hooks :as hooks]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.i18n :as i18n :refer [t]]
|
||||
[uxbox.util.router :as rt]))
|
||||
|
@ -27,6 +28,7 @@
|
|||
(mf/defc page-item
|
||||
[{:keys [page index deletable? selected?] :as props}]
|
||||
(let [local (mf/use-state {})
|
||||
|
||||
on-double-click
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
|
@ -54,22 +56,27 @@
|
|||
(dom/stop-propagation %)
|
||||
(modal/show! confirm-dialog {:on-accept delete-fn}))
|
||||
|
||||
on-drop #(do (prn "TODO"))
|
||||
on-hover #(st/emit! (dw/change-page-order {:id (:id page)
|
||||
:index index}))
|
||||
|
||||
navigate-fn #(st/emit! (dw/go-to-page (:id page)))
|
||||
;; [dprops ref] (use-sortable {:type "page-item"
|
||||
;; :data {:id (:id page)
|
||||
;; :index index}
|
||||
;; :on-hover on-hover
|
||||
;; :on-drop on-drop})
|
||||
]
|
||||
[:li {:class (classnames :selected selected?)}
|
||||
[:div.element-list-body {:class (classnames
|
||||
:selected selected?
|
||||
;; :dragging (:dragging? dprops)
|
||||
)
|
||||
|
||||
on-drop
|
||||
(fn [side {:keys [id name] :as data}]
|
||||
(let [index (if (= :bot side) (inc index) index)]
|
||||
(st/emit! (dw/relocate-page id index))))
|
||||
|
||||
[dprops dref] (hooks/use-sortable
|
||||
:type "page"
|
||||
:on-drop on-drop
|
||||
:data {:id (:id page)
|
||||
:index index
|
||||
:name (:name page)})]
|
||||
|
||||
[:li {:class (dom/classnames
|
||||
:selected selected?
|
||||
:dnd-over-top (= (:over dprops) :top)
|
||||
:dnd-over-bot (= (:over dprops) :bot))
|
||||
:ref dref}
|
||||
[:div.element-list-body {:class (dom/classnames
|
||||
:selected selected?)
|
||||
:on-click navigate-fn
|
||||
:on-double-click on-double-click}
|
||||
[:div.page-icon i/file-html]
|
||||
|
@ -89,16 +96,17 @@
|
|||
|
||||
;; --- Page Item Wrapper
|
||||
|
||||
(defn- make-page-ref
|
||||
(defn- make-page-iref
|
||||
[id]
|
||||
#(-> (l/in [:workspace-pages id])
|
||||
(l/derived st/state)))
|
||||
#(l/derived (fn [state]
|
||||
(let [page (get-in state [:workspace-pages id])]
|
||||
(select-keys page [:id :name :ordering])))
|
||||
st/state =))
|
||||
|
||||
(mf/defc page-item-wrapper
|
||||
[{:keys [page-id index deletable? selected?] :as props}]
|
||||
(let [page-iref (mf/use-memo
|
||||
(mf/deps page-id)
|
||||
(make-page-ref page-id))
|
||||
(let [page-iref (mf/use-memo (mf/deps page-id)
|
||||
(make-page-iref page-id))
|
||||
page (mf/deref page-iref)]
|
||||
[:& page-item {:page page
|
||||
:index index
|
||||
|
@ -109,15 +117,16 @@
|
|||
|
||||
(mf/defc pages-list
|
||||
[{:keys [file current-page] :as props}]
|
||||
(let [pages (enumerate (:pages file))
|
||||
(let [pages (d/enumerate (:pages file))
|
||||
deletable? (> (count pages) 1)]
|
||||
[:ul.element-list
|
||||
(for [[index page-id] pages]
|
||||
[:& page-item-wrapper {:page-id page-id
|
||||
:index index
|
||||
:deletable? deletable?
|
||||
:selected? (= page-id (:id current-page))
|
||||
:key page-id}])]))
|
||||
[:& page-item-wrapper
|
||||
{:page-id page-id
|
||||
:index index
|
||||
:deletable? deletable?
|
||||
:selected? (= page-id (:id current-page))
|
||||
:key page-id}])]))
|
||||
|
||||
;; --- Sitemap Toolbox
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue