0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-09 16:30:37 -05:00

Add clipboard management.

This commit is contained in:
Andrey Antukh 2016-04-02 13:00:41 +03:00
parent 4519d6e508
commit b5155eebcf
7 changed files with 125 additions and 50 deletions

View file

@ -18,12 +18,11 @@
[uxbox.shapes :as sh]
[uxbox.data.pages :as udp]
[uxbox.data.shapes :as uds]
[uxbox.util.datetime :as dt]
[uxbox.util.geom.point :as gpt]
[uxbox.util.data :refer (index-of)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Events (explicit)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Events (concrete)
(defn initialize
"Initialize the workspace state."
@ -93,9 +92,7 @@
(->> (into #{} xf (vals (:shapes-by-id state)))
(assoc-in state [:workspace :selected]))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Events (for selected)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Events (implicit) (for selected)
(defn deselect-all
"Mark a shape selected for drawing in the canvas."
@ -207,3 +204,41 @@
(->> (get-in state [:workspace :selected])
(map #(uds/update-stroke-attrs % opts)))))))
;; --- Copy to Clipboard
(defrecord CopyToClipboard []
rs/UpdateEvent
(-apply-update [_ state]
(let [selected (get-in state [:workspace :selected])
item {:id (random-uuid)
:created-at (dt/now)
:items selected}
clipboard (-> (:clipboard state)
(conj item))]
(assoc state :clipboard
(if (> (count clipboard) 5)
(pop clipboard)
clipboard)))))
(defn copy-to-clipboard
"Copy selected shapes to clipboard."
[]
(CopyToClipboard.))
;; --- Paste from Clipboard
(defrecord PasteFromClipboard [id]
rs/UpdateEvent
(-apply-update [_ state]
(let [page (get-in state [:workspace :page])
selected (if (nil? id)
(first (:clipboard state))
(->> (:clipboard state)
(filter #(= id (:id %)))
(first)))]
(stsh/duplicate-shapes state (:items selected) page))))
(defn paste-from-clipboard
"Copy selected shapes to clipboard."
([] (PasteFromClipboard. nil))
([id] (PasteFromClipboard. id)))

View file

@ -18,6 +18,7 @@
:project-filter ""}
:route nil
:auth (:uxbox/auth local-storage)
:clipboard #queue []
:profile nil
:workspace nil
:shapes-by-id {}

View file

@ -3,9 +3,7 @@
(:require [uxbox.shapes :as sh]
[uxbox.util.data :refer (index-of)]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shape Creation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Shape Creation
(defn assoc-shape-to-page
[state shape page]
@ -48,30 +46,30 @@
(reduce #(duplicate-shape %1 %2 page group) state shapes))))
(defn duplicate-shapes
[state shapes]
(letfn [(all-toplevel? [coll]
(every? #(nil? (:group %)) coll))
(all-same-group? [coll]
(let [group (:group (first coll))]
(every? #(= group (:group %)) coll)))]
(let [shapes (mapv #(get-in state [:shapes-by-id %]) shapes)]
(cond
(all-toplevel? shapes)
(let [page (:page (first shapes))]
(duplicate-shapes' state shapes page))
([state shapes]
(duplicate-shapes state shapes nil))
([state shapes page]
(letfn [(all-toplevel? [coll]
(every? #(nil? (:group %)) coll))
(all-same-group? [coll]
(let [group (:group (first coll))]
(every? #(= group (:group %)) coll)))]
(let [shapes (mapv #(get-in state [:shapes-by-id %]) shapes)]
(cond
(all-toplevel? shapes)
(let [page (or page (:page (first shapes)))]
(duplicate-shapes' state shapes page))
(all-same-group? shapes)
(let [page (:page (first shapes))
group (:group (first shapes))]
(duplicate-shapes' state shapes page group))
(all-same-group? shapes)
(let [page (or page (:page (first shapes)))
group (:group (first shapes))]
(duplicate-shapes' state shapes page group))
:else
(let [page (:page (first shapes))]
(duplicate-shapes' state shapes page))))))
:else
(let [page (or page (:page (first shapes)))]
(duplicate-shapes' state shapes page)))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Delete Shapes
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Delete Shapes
(defn dissoc-from-index
"A function that dissoc shape from the indexed
@ -127,9 +125,7 @@
(dissoc-from-index $ shape)
(clear-empty-groups $ shape)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Shape Movements
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Shape Movements
(defn- drop-at-index
[index coll v]
@ -193,3 +189,26 @@
:before (drop-before state tid sid)
:after (drop-after state tid sid)
(throw (ex-info "Invalid data" {})))))
;; --- Shape Packing
;; (defn- deep-scan-shape-ids
;; [state acc id]
;; (let [shape (get-in state [:shapes-by-id id])]
;; (if (= (:type shape) :builtin/group)
;; (reduce (partial deep-scan-shape-ids state)
;; (conj acc id)
;; (:items shape))
;; (conj acc id))))
;; (defn pack-shape
;; [state id]
;; (let [ids (deep-scan-shape-ids state #{} id)
;; index (reduce (fn [acc id]
;; (let [shape (get-in state [:shapes-by-id id])]
;; (assoc acc id shape)))
;; {} ids)]
;; {:type :builtin/packed-shape
;; :index index
;; :id id}))

View file

@ -7,33 +7,51 @@
(ns uxbox.ui.workspace.clipboard
(:require [sablono.core :as html :refer-macros [html]]
[rum.core :as rum]
[lentes.core :as l]
[uxbox.rstore :as rs]
[uxbox.state :as st]
[uxbox.ui.icons :as i]
[uxbox.ui.mixins :as mx]
[uxbox.ui.lightbox :as lightbox]
[uxbox.data.workspace :as udw]
[uxbox.util.dom :as dom]
[uxbox.ui.lightbox :as lightbox]))
[uxbox.util.datetime :as dt]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Component
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Lenses
(def ^:const ^:private clipboard-l
(-> (l/key :clipboard)
(l/focus-atom st/state)))
;; --- Clipboard Dialog Component
(defn- on-paste
[item]
(rs/emit! (udw/paste-from-clipboard (:id item)))
(lightbox/close!))
(defn- clipboard-dialog-render
[own]
(html
[:div.lightbox-body.clipboard
[:div.clipboard-list
(for [i (range 5)]
[:div.clipboard-item {:key i}
[:span.clipboard-icon i/box]
[:span (str "shape " i)]])]
[:a.close {:href "#"
:on-click #(do (dom/prevent-default %)
(lightbox/close!))} i/close]]))
(let [clipboard (rum/react clipboard-l)]
(html
[:div.lightbox-body.clipboard
[:div.clipboard-list
(for [item clipboard]
[:div.clipboard-item
{:key (str (:id item))
:on-click (partial on-paste item)}
[:span.clipboard-icon i/box]
[:span (str "Copied (" (dt/timeago (:created-at item)) ")")]])]
[:a.close {:href "#"
:on-click #(do (dom/prevent-default %)
(lightbox/close!))} i/close]])))
(def clipboard-dialog
(mx/component
{:render clipboard-dialog-render
:name "clipboard-dialog"
:mixins []}))
:mixins [mx/static rum/reactive]}))
(defmethod lightbox/render-lightbox :clipboard
[_]

View file

@ -10,6 +10,7 @@
(:require [goog.events :as events]
[beicon.core :as rx]
[uxbox.rstore :as rs]
[uxbox.ui.lightbox :as lightbox]
[uxbox.data.workspace :as dw])
(:import goog.events.EventType
goog.events.KeyCodes
@ -33,6 +34,9 @@
:ctrl+shift+l #(rs/emit! (dw/toggle-flag :layers))
:ctrl+r #(rs/emit! (dw/toggle-flag :ruler))
:ctrl+d #(rs/emit! (dw/duplicate-selected))
:ctrl+c #(rs/emit! (dw/copy-to-clipboard))
:ctrl+v #(rs/emit! (dw/paste-from-clipboard))
:ctrl+shift+v #(lightbox/open! :clipboard)
:esc #(rs/emit! (dw/deselect-all))
:backspace #(rs/emit! (dw/delete-selected))
:delete #(rs/emit! (dw/delete-selected))

View file

@ -69,7 +69,6 @@
(on-load-more [event]
(dom/prevent-default event)
(println "kaka")
(let [since (:min-version history)
params {:since since}]
(rs/emit! (udh/fetch-page-history (:id page) params))))]

View file

@ -101,7 +101,6 @@
:builtin/text i/text
:builtin/group i/folder))
(defn- get-hover-position
[event group?]
(let [target (.-currentTarget event)