mirror of
https://github.com/penpot/penpot.git
synced 2025-05-26 05:36:11 +02:00
♻️ Refactor penpot library
This commit is contained in:
parent
8bdec66927
commit
0b7b6e2c23
18 changed files with 817 additions and 1034 deletions
30
CHANGES.md
30
CHANGES.md
|
@ -6,6 +6,36 @@
|
||||||
|
|
||||||
### :boom: Breaking changes & Deprecations
|
### :boom: Breaking changes & Deprecations
|
||||||
|
|
||||||
|
**Breaking changes on penpot library:**
|
||||||
|
|
||||||
|
- Change the signature of the `addPage` method: it now accepts an object (as a single argument) where you can pass `id`,
|
||||||
|
`name`, and `background` props (instead of the previous positional arguments)
|
||||||
|
- Rename the `file.createRect` method to `file.addRect`
|
||||||
|
- Rename the `file.createCircle` method to `file.addCircle`
|
||||||
|
- Rename the `file.createPath` method to `file.addPath`
|
||||||
|
- Rename the `file.createText` method to `file.addText`
|
||||||
|
- Rename `file.startComponent` to `file.addComponent` (to preserve the naming style)
|
||||||
|
- Rename `file.createComponentInstance` to `file.addComponentInstance` (to preserve the naming style)
|
||||||
|
- Rename `file.lookupShape` to `file.getShape`
|
||||||
|
- Rename `file.asMap` to `file.toMap`
|
||||||
|
- Remove `file.updateLibraryColor` (use `file.addLibraryColor` if you just need to replace a color)
|
||||||
|
- Remove `file.deleteLibraryColor` (this library is intended to build files)
|
||||||
|
- Remove `file.updateLibraryTypography` (use `file.addLibraryTypography` if you just need to replace a typography)
|
||||||
|
- Remove `file.deleteLibraryTypography` (this library is intended to build files)
|
||||||
|
- Remove `file.add/update/deleteLibraryMedia` (they are no longer supported by Penpot and have been replaced by components)
|
||||||
|
- Remove `file.deleteObject` (this library is intended to build files)
|
||||||
|
- Remove `file.updateObject` (this library is intended to build files)
|
||||||
|
- Remove `file.finishComponent` (it is no longer necessary; see below for more details on component creation changes)
|
||||||
|
- Change the `file.getCurrentPageId` function to a read-only `file.currentPageId` property
|
||||||
|
- Add `file.currentFrameId` read-only property
|
||||||
|
- Add `file.lastId` read-only property
|
||||||
|
|
||||||
|
There are also relevant semantic changes in how components should be created: this refactor removes
|
||||||
|
all notions of the old components (v1). Since v2, the shapes that are part of a component live on a
|
||||||
|
page. So, from now on, to create a component, you should first create a frame, then add shapes
|
||||||
|
and/or groups to that frame, and then create a component by declaring that frame as the component
|
||||||
|
root.
|
||||||
|
|
||||||
### :heart: Community contributions (Thank you!)
|
### :heart: Community contributions (Thank you!)
|
||||||
|
|
||||||
### :sparkles: New features
|
### :sparkles: New features
|
||||||
|
|
|
@ -55,8 +55,8 @@
|
||||||
:features features
|
:features features
|
||||||
:ignore-sync-until ignore-sync-until
|
:ignore-sync-until ignore-sync-until
|
||||||
:modified-at modified-at
|
:modified-at modified-at
|
||||||
:deleted-at deleted-at
|
:deleted-at deleted-at}
|
||||||
:create-page create-page
|
{:create-page create-page
|
||||||
:page-id page-id})
|
:page-id page-id})
|
||||||
file (-> (bfc/insert-file! cfg file)
|
file (-> (bfc/insert-file! cfg file)
|
||||||
(bfc/decode-row))]
|
(bfc/decode-row))]
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -732,20 +732,22 @@
|
||||||
|
|
||||||
(update-group [group objects]
|
(update-group [group objects]
|
||||||
(let [lookup (d/getf objects)
|
(let [lookup (d/getf objects)
|
||||||
children (->> group :shapes (map lookup))]
|
children (get group :shapes)]
|
||||||
(cond
|
(cond
|
||||||
;; If the group is empty we don't make any changes. Will be removed by a later process
|
;; If the group is empty we don't make any changes. Will be removed by a later process
|
||||||
(empty? children)
|
(empty? children)
|
||||||
group
|
group
|
||||||
|
|
||||||
(= :bool (:type group))
|
(= :bool (:type group))
|
||||||
(gsh/update-bool group children objects)
|
(gsh/update-bool group objects)
|
||||||
|
|
||||||
(:masked-group group)
|
(:masked-group group)
|
||||||
(set-mask-selrect group children)
|
(->> (map lookup children)
|
||||||
|
(set-mask-selrect group))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(gsh/update-group-selrect group children))))]
|
(->> (map lookup children)
|
||||||
|
(gsh/update-group-selrect group)))))]
|
||||||
|
|
||||||
(if page-id
|
(if page-id
|
||||||
(d/update-in-when data [:pages-index page-id :objects] reg-objects)
|
(d/update-in-when data [:pages-index page-id :objects] reg-objects)
|
||||||
|
|
|
@ -660,9 +660,13 @@
|
||||||
nil ;; so it does not need resize
|
nil ;; so it does not need resize
|
||||||
|
|
||||||
(= (:type parent) :bool)
|
(= (:type parent) :bool)
|
||||||
(gsh/update-bool parent children objects)
|
(gsh/update-bool parent objects)
|
||||||
|
|
||||||
(= (:type parent) :group)
|
(= (:type parent) :group)
|
||||||
|
;; FIXME: this functions should be
|
||||||
|
;; normalized in the same way as
|
||||||
|
;; update-bool in order to make all
|
||||||
|
;; this code consistent
|
||||||
(if (:masked-group parent)
|
(if (:masked-group parent)
|
||||||
(gsh/update-mask-selrect parent children)
|
(gsh/update-mask-selrect parent children)
|
||||||
(gsh/update-group-selrect parent children)))]
|
(gsh/update-group-selrect parent children)))]
|
||||||
|
|
|
@ -455,12 +455,12 @@
|
||||||
|
|
||||||
(defn update-bool
|
(defn update-bool
|
||||||
"Calculates the selrect+points for the boolean shape"
|
"Calculates the selrect+points for the boolean shape"
|
||||||
[shape _children objects]
|
[shape objects]
|
||||||
|
|
||||||
(let [content (path/calc-bool-content shape objects)
|
(let [content (path/calc-bool-content shape objects)
|
||||||
shape (assoc shape :content content)]
|
shape (assoc shape :content content)]
|
||||||
(path/update-geometry shape)))
|
(path/update-geometry shape)))
|
||||||
|
|
||||||
|
;; FIXME: revisit
|
||||||
(defn update-shapes-geometry
|
(defn update-shapes-geometry
|
||||||
[objects ids]
|
[objects ids]
|
||||||
(->> ids
|
(->> ids
|
||||||
|
@ -474,7 +474,7 @@
|
||||||
(update-mask-selrect shape children)
|
(update-mask-selrect shape children)
|
||||||
|
|
||||||
(cfh/bool-shape? shape)
|
(cfh/bool-shape? shape)
|
||||||
(update-bool shape children objects)
|
(update-bool shape objects)
|
||||||
|
|
||||||
(cfh/group-shape? shape)
|
(cfh/group-shape? shape)
|
||||||
(update-group-selrect shape children)
|
(update-group-selrect shape children)
|
||||||
|
|
|
@ -23,28 +23,32 @@
|
||||||
|
|
||||||
(defn sample-file
|
(defn sample-file
|
||||||
[label & {:keys [page-label name view-only?] :as params}]
|
[label & {:keys [page-label name view-only?] :as params}]
|
||||||
(binding [ffeat/*current* #{"components/v2"}]
|
(let [params
|
||||||
(let [params (cond-> params
|
(cond-> params
|
||||||
label
|
label
|
||||||
(assoc :id (thi/new-id! label))
|
(assoc :id (thi/new-id! label))
|
||||||
|
|
||||||
page-label
|
(nil? name)
|
||||||
(assoc :page-id (thi/new-id! page-label))
|
(assoc :name "Test file")
|
||||||
|
|
||||||
(nil? name)
|
:always
|
||||||
(assoc :name "Test file"))
|
(assoc :features ffeat/default-features))
|
||||||
|
|
||||||
file (-> (ctf/make-file (dissoc params :page-label))
|
opts
|
||||||
(assoc :features #{"components/v2"})
|
(cond-> {}
|
||||||
(assoc :permissions {:can-edit (not (true? view-only?))}))
|
page-label
|
||||||
|
(assoc :page-id (thi/new-id! page-label)))
|
||||||
|
|
||||||
page (-> file
|
file (-> (ctf/make-file params opts)
|
||||||
:data
|
(assoc :permissions {:can-edit (not (true? view-only?))}))
|
||||||
(ctpl/pages-seq)
|
|
||||||
(first))]
|
|
||||||
|
|
||||||
(with-meta file
|
page (-> file
|
||||||
{:current-page-id (:id page)}))))
|
:data
|
||||||
|
(ctpl/pages-seq)
|
||||||
|
(first))]
|
||||||
|
|
||||||
|
(with-meta file
|
||||||
|
{:current-page-id (:id page)})))
|
||||||
|
|
||||||
(defn validate-file!
|
(defn validate-file!
|
||||||
([file] (validate-file! file {}))
|
([file] (validate-file! file {}))
|
||||||
|
|
|
@ -137,33 +137,36 @@
|
||||||
(update :options assoc :components-v2 true)))))
|
(update :options assoc :components-v2 true)))))
|
||||||
|
|
||||||
(defn make-file
|
(defn make-file
|
||||||
[{:keys [id project-id name revn is-shared features
|
[{:keys [id project-id name revn is-shared features migrations
|
||||||
ignore-sync-until modified-at deleted-at
|
ignore-sync-until modified-at deleted-at]
|
||||||
create-page page-id]
|
:or {is-shared false revn 0}}
|
||||||
:or {is-shared false revn 0 create-page true}}]
|
|
||||||
|
& {:keys [create-page page-id]
|
||||||
|
:or {create-page true}}]
|
||||||
|
|
||||||
(let [id (or id (uuid/next))
|
(let [id (or id (uuid/next))
|
||||||
|
|
||||||
data (if create-page
|
data (if create-page
|
||||||
(if page-id
|
(if page-id
|
||||||
(make-file-data id page-id)
|
(make-file-data id page-id)
|
||||||
(make-file-data id))
|
(make-file-data id))
|
||||||
(make-file-data id nil))
|
(make-file-data id nil))
|
||||||
|
|
||||||
file {:id id
|
file (d/without-nils
|
||||||
:project-id project-id
|
{:id id
|
||||||
:name name
|
:project-id project-id
|
||||||
:revn revn
|
:name name
|
||||||
:vern 0
|
:revn revn
|
||||||
:is-shared is-shared
|
:vern 0
|
||||||
:version version
|
:is-shared is-shared
|
||||||
:data data
|
:version version
|
||||||
:features features
|
:data data
|
||||||
:ignore-sync-until ignore-sync-until
|
:features features
|
||||||
:modified-at modified-at
|
:migrations migrations
|
||||||
:deleted-at deleted-at}]
|
:ignore-sync-until ignore-sync-until
|
||||||
|
:modified-at modified-at
|
||||||
|
:deleted-at deleted-at})]
|
||||||
|
|
||||||
(d/without-nils file)))
|
(check-file file)))
|
||||||
|
|
||||||
;; Helpers
|
;; Helpers
|
||||||
|
|
||||||
|
|
|
@ -149,13 +149,16 @@
|
||||||
{:test {:init-fn frontend-tests.runner/init
|
{:test {:init-fn frontend-tests.runner/init
|
||||||
:prepend-js ";if (typeof globalThis.navigator?.userAgent === 'undefined') { globalThis.navigator = {userAgent: ''}; };"}}}
|
:prepend-js ";if (typeof globalThis.navigator?.userAgent === 'undefined') { globalThis.navigator = {userAgent: ''}; };"}}}
|
||||||
|
|
||||||
:lib-penpot
|
:library
|
||||||
{:target :esm
|
{:target :esm
|
||||||
:output-dir "resources/public/libs"
|
:runtime :custom
|
||||||
|
:output-dir "target/library"
|
||||||
|
:devtools {:autoload false}
|
||||||
|
|
||||||
:modules
|
:modules
|
||||||
{:penpot {:exports {:renderPage app.libs.render/render-page-export
|
{:penpot
|
||||||
:createFile app.libs.file-builder/create-file-export}}}
|
{:exports {BuilderError lib.file-builder/BuilderError
|
||||||
|
createFile lib.file-builder/create-file}}}
|
||||||
|
|
||||||
:compiler-options
|
:compiler-options
|
||||||
{:output-feature-set :es2020
|
{:output-feature-set :es2020
|
||||||
|
@ -165,6 +168,8 @@
|
||||||
:release
|
:release
|
||||||
{:compiler-options
|
{:compiler-options
|
||||||
{:fn-invoke-direct true
|
{:fn-invoke-direct true
|
||||||
|
:optimizations #shadow/env ["PENPOT_BUILD_OPTIMIZATIONS" :as :keyword :default :advanced]
|
||||||
|
:pretty-print false
|
||||||
:source-map true
|
:source-map true
|
||||||
:elide-asserts true
|
:elide-asserts true
|
||||||
:anon-fn-naming-policy :off
|
:anon-fn-naming-policy :off
|
||||||
|
|
|
@ -1,281 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) KALEIDOS INC
|
|
||||||
|
|
||||||
(ns app.libs.file-builder
|
|
||||||
(:require
|
|
||||||
[app.common.data :as d]
|
|
||||||
[app.common.features :as cfeat]
|
|
||||||
[app.common.files.builder :as fb]
|
|
||||||
[app.common.media :as cm]
|
|
||||||
[app.common.types.components-list :as ctkl]
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.util.json :as json]
|
|
||||||
[app.util.webapi :as wapi]
|
|
||||||
[app.util.zip :as uz]
|
|
||||||
[app.worker.export :as e]
|
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[cuerdas.core :as str]
|
|
||||||
[promesa.core :as p]))
|
|
||||||
|
|
||||||
(defn parse-data [data]
|
|
||||||
(as-> data $
|
|
||||||
(js->clj $ :keywordize-keys true)
|
|
||||||
;; Transforms camelCase to kebab-case
|
|
||||||
(d/deep-mapm
|
|
||||||
(fn [[key value]]
|
|
||||||
(let [value (if (= (type value) js/Symbol)
|
|
||||||
(keyword (js/Symbol.keyFor value))
|
|
||||||
value)
|
|
||||||
key (-> key d/name str/kebab keyword)]
|
|
||||||
[key value])) $)))
|
|
||||||
|
|
||||||
(defn data-uri->blob
|
|
||||||
[data-uri]
|
|
||||||
(let [[mtype b64-data] (str/split data-uri ";base64,")
|
|
||||||
mtype (subs mtype (inc (str/index-of mtype ":")))
|
|
||||||
decoded (.atob js/window b64-data)
|
|
||||||
size (.-length ^js decoded)
|
|
||||||
content (js/Uint8Array. size)]
|
|
||||||
|
|
||||||
(doseq [i (range 0 size)]
|
|
||||||
(aset content i (.charCodeAt decoded i)))
|
|
||||||
|
|
||||||
(wapi/create-blob content mtype)))
|
|
||||||
|
|
||||||
(defn parse-library-media
|
|
||||||
[[file-id media]]
|
|
||||||
(rx/merge
|
|
||||||
(let [markup
|
|
||||||
(->> (vals media)
|
|
||||||
(reduce e/collect-media {})
|
|
||||||
(json/encode))]
|
|
||||||
(rx/of (vector (str file-id "/media.json") markup)))
|
|
||||||
|
|
||||||
(->> (rx/from (vals media))
|
|
||||||
(rx/map #(assoc % :file-id file-id))
|
|
||||||
(rx/merge-map
|
|
||||||
(fn [media]
|
|
||||||
(let [file-path (str/concat file-id "/media/" (:id media) (cm/mtype->extension (:mtype media)))
|
|
||||||
blob (data-uri->blob (:uri media))]
|
|
||||||
(rx/of (vector file-path blob))))))))
|
|
||||||
|
|
||||||
(defn export-file
|
|
||||||
[file]
|
|
||||||
(let [file (assoc file
|
|
||||||
:name (:name file)
|
|
||||||
:file-name (:name file)
|
|
||||||
:is-shared false)
|
|
||||||
|
|
||||||
files-stream (->> (rx/of {(:id file) file})
|
|
||||||
(rx/share))
|
|
||||||
|
|
||||||
manifest-stream
|
|
||||||
(->> files-stream
|
|
||||||
(rx/map #(e/create-manifest (uuid/next) (:id file) :all % cfeat/default-features))
|
|
||||||
(rx/map (fn [a]
|
|
||||||
(vector "manifest.json" a))))
|
|
||||||
|
|
||||||
render-stream
|
|
||||||
(->> files-stream
|
|
||||||
(rx/merge-map vals)
|
|
||||||
(rx/merge-map e/process-pages)
|
|
||||||
(rx/observe-on :async)
|
|
||||||
(rx/merge-map e/get-page-data)
|
|
||||||
(rx/share))
|
|
||||||
|
|
||||||
colors-stream
|
|
||||||
(->> files-stream
|
|
||||||
(rx/merge-map vals)
|
|
||||||
(rx/map #(vector (:id %) (get-in % [:data :colors])))
|
|
||||||
(rx/filter #(d/not-empty? (second %)))
|
|
||||||
(rx/map e/parse-library-color))
|
|
||||||
|
|
||||||
typographies-stream
|
|
||||||
(->> files-stream
|
|
||||||
(rx/merge-map vals)
|
|
||||||
(rx/map #(vector (:id %) (get-in % [:data :typographies])))
|
|
||||||
(rx/filter #(d/not-empty? (second %)))
|
|
||||||
(rx/map e/parse-library-typographies))
|
|
||||||
|
|
||||||
media-stream
|
|
||||||
(->> files-stream
|
|
||||||
(rx/merge-map vals)
|
|
||||||
(rx/map #(vector (:id %) (get-in % [:data :media])))
|
|
||||||
(rx/filter #(d/not-empty? (second %)))
|
|
||||||
(rx/merge-map parse-library-media))
|
|
||||||
|
|
||||||
components-stream
|
|
||||||
(->> files-stream
|
|
||||||
(rx/merge-map vals)
|
|
||||||
(rx/filter #(d/not-empty? (ctkl/components-seq (:data %))))
|
|
||||||
(rx/merge-map e/parse-library-components))
|
|
||||||
|
|
||||||
pages-stream
|
|
||||||
(->> render-stream
|
|
||||||
(rx/map e/collect-page))]
|
|
||||||
|
|
||||||
(rx/merge
|
|
||||||
(->> render-stream
|
|
||||||
(rx/map #(hash-map
|
|
||||||
:type :progress
|
|
||||||
:file (:id file)
|
|
||||||
:data (str "Render " (:file-name %) " - " (:name %)))))
|
|
||||||
|
|
||||||
(->> (rx/merge
|
|
||||||
manifest-stream
|
|
||||||
pages-stream
|
|
||||||
components-stream
|
|
||||||
media-stream
|
|
||||||
colors-stream
|
|
||||||
typographies-stream)
|
|
||||||
(rx/reduce conj [])
|
|
||||||
(rx/with-latest-from files-stream)
|
|
||||||
(rx/merge-map (fn [[data _]]
|
|
||||||
(->> (uz/compress-files data)
|
|
||||||
(rx/map #(vector file %)))))))))
|
|
||||||
|
|
||||||
(deftype File [^:mutable file]
|
|
||||||
Object
|
|
||||||
|
|
||||||
(addPage [_ name]
|
|
||||||
(set! file (fb/add-page file {:name name}))
|
|
||||||
(str (:current-page-id file)))
|
|
||||||
|
|
||||||
(addPage [_ name options]
|
|
||||||
(set! file (fb/add-page file {:name name :options (parse-data options)}))
|
|
||||||
(str (:current-page-id file)))
|
|
||||||
|
|
||||||
(closePage [_]
|
|
||||||
(set! file (fb/close-page file)))
|
|
||||||
|
|
||||||
(addArtboard [_ data]
|
|
||||||
(set! file (fb/add-artboard file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(closeArtboard [_]
|
|
||||||
(set! file (fb/close-artboard file)))
|
|
||||||
|
|
||||||
(addGroup [_ data]
|
|
||||||
(set! file (fb/add-group file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(closeGroup [_]
|
|
||||||
(set! file (fb/close-group file)))
|
|
||||||
|
|
||||||
(addBool [_ data]
|
|
||||||
(set! file (fb/add-bool file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(closeBool [_]
|
|
||||||
(set! file (fb/close-bool file)))
|
|
||||||
|
|
||||||
(createRect [_ data]
|
|
||||||
(set! file (fb/create-rect file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(createCircle [_ data]
|
|
||||||
(set! file (fb/create-circle file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(createPath [_ data]
|
|
||||||
(set! file (fb/create-path file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(createText [_ data]
|
|
||||||
(set! file (fb/create-text file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(createImage [_ data]
|
|
||||||
(set! file (fb/create-image file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(createSVG [_ data]
|
|
||||||
(set! file (fb/create-svg-raw file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(closeSVG [_]
|
|
||||||
(set! file (fb/close-svg-raw file)))
|
|
||||||
|
|
||||||
(addLibraryColor [_ data]
|
|
||||||
(set! file (fb/add-library-color file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(updateLibraryColor [_ data]
|
|
||||||
(set! file (fb/update-library-color file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(deleteLibraryColor [_ data]
|
|
||||||
(set! file (fb/delete-library-color file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(addLibraryMedia [_ data]
|
|
||||||
(set! file (fb/add-library-media file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(deleteLibraryMedia [_ data]
|
|
||||||
(set! file (fb/delete-library-media file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(addLibraryTypography [_ data]
|
|
||||||
(set! file (fb/add-library-typography file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(deleteLibraryTypography [_ data]
|
|
||||||
(set! file (fb/delete-library-typography file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(startComponent [_ data]
|
|
||||||
(set! file (fb/start-component file (parse-data data)))
|
|
||||||
(str (:current-component-id file)))
|
|
||||||
|
|
||||||
(finishComponent [_]
|
|
||||||
(set! file (fb/finish-component file)))
|
|
||||||
|
|
||||||
(createComponentInstance [_ data]
|
|
||||||
(set! file (fb/create-component-instance file (parse-data data)))
|
|
||||||
(str (:last-id file)))
|
|
||||||
|
|
||||||
(lookupShape [_ shape-id]
|
|
||||||
(clj->js (fb/lookup-shape file (uuid/parse shape-id))))
|
|
||||||
|
|
||||||
(updateObject [_ id new-obj]
|
|
||||||
(let [old-obj (fb/lookup-shape file (uuid/parse id))
|
|
||||||
new-obj (d/deep-merge old-obj (parse-data new-obj))]
|
|
||||||
(set! file (fb/update-object file old-obj new-obj))))
|
|
||||||
|
|
||||||
(deleteObject [_ id]
|
|
||||||
(set! file (fb/delete-object file (uuid/parse id))))
|
|
||||||
|
|
||||||
(getId [_]
|
|
||||||
(:id file))
|
|
||||||
|
|
||||||
(getCurrentPageId [_]
|
|
||||||
(:current-page-id file))
|
|
||||||
|
|
||||||
(asMap [_]
|
|
||||||
(clj->js file))
|
|
||||||
|
|
||||||
(newId [_]
|
|
||||||
(uuid/next))
|
|
||||||
|
|
||||||
(export [_]
|
|
||||||
(p/create
|
|
||||||
(fn [resolve reject]
|
|
||||||
(->> (export-file file)
|
|
||||||
(rx/filter #(not= (:type %) :progress))
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/subs!
|
|
||||||
(fn [value]
|
|
||||||
(let [[_ export-blob] value]
|
|
||||||
(resolve export-blob)))
|
|
||||||
reject))))))
|
|
||||||
|
|
||||||
(defn create-file-export [^string name]
|
|
||||||
(binding [cfeat/*current* cfeat/default-features]
|
|
||||||
(File. (fb/create-file name))))
|
|
||||||
|
|
||||||
(defn exports []
|
|
||||||
#js {:createFile create-file-export})
|
|
|
@ -1,28 +0,0 @@
|
||||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
||||||
;;
|
|
||||||
;; Copyright (c) KALEIDOS INC
|
|
||||||
|
|
||||||
(ns app.libs.render
|
|
||||||
(:require
|
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.main.render :as r]
|
|
||||||
[beicon.v2.core :as rx]
|
|
||||||
[promesa.core :as p]))
|
|
||||||
|
|
||||||
(defn render-page-export
|
|
||||||
[file ^string page-id]
|
|
||||||
|
|
||||||
;; Better to expose the api as a promise to be consumed from JS
|
|
||||||
(let [page-id (uuid/parse page-id)
|
|
||||||
file-data (.-file file)
|
|
||||||
data (get-in file-data [:data :pages-index page-id])]
|
|
||||||
(p/create
|
|
||||||
(fn [resolve reject]
|
|
||||||
(->> (r/render-page data)
|
|
||||||
(rx/take 1)
|
|
||||||
(rx/subs! resolve reject))))))
|
|
||||||
|
|
||||||
(defn exports []
|
|
||||||
#js {:renderPage render-page-export})
|
|
|
@ -771,12 +771,12 @@
|
||||||
|
|
||||||
;; --- Update Shape Attrs
|
;; --- Update Shape Attrs
|
||||||
|
|
||||||
;; FIXME: revisit this before merge
|
;; FIXME: rename to update-shape-generic-attrs because on the end we
|
||||||
|
;; only allow here to update generic attrs
|
||||||
(defn update-shape
|
(defn update-shape
|
||||||
[id attrs]
|
[id attrs]
|
||||||
(assert (uuid? id) "expected valid uuid for `id`")
|
(assert (uuid? id) "expected valid uuid for `id`")
|
||||||
|
(let [attrs (cts/check-shape-generic-attrs attrs)]
|
||||||
(let [attrs (cts/check-shape-attrs attrs)]
|
|
||||||
(ptk/reify ::update-shape
|
(ptk/reify ::update-shape
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ _]
|
(watch [_ _ _]
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.common.types.component :as ctc]
|
[app.common.types.component :as ctc]
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.path :as path]
|
|
||||||
[app.common.types.path.bool :as bool]
|
[app.common.types.path.bool :as bool]
|
||||||
[app.common.types.shape :as cts]
|
[app.common.types.shape :as cts]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
|
@ -30,9 +29,6 @@
|
||||||
(let [shape-id
|
(let [shape-id
|
||||||
(or id (uuid/next))
|
(or id (uuid/next))
|
||||||
|
|
||||||
shapes
|
|
||||||
(mapv #(path/convert-to-path % objects) shapes)
|
|
||||||
|
|
||||||
head
|
head
|
||||||
(if (= type :difference) (first shapes) (last shapes))
|
(if (= type :difference) (first shapes) (last shapes))
|
||||||
|
|
||||||
|
@ -48,13 +44,13 @@
|
||||||
:frame-id (:frame-id head)
|
:frame-id (:frame-id head)
|
||||||
:parent-id (:parent-id head)
|
:parent-id (:parent-id head)
|
||||||
:name name
|
:name name
|
||||||
:shapes (mapv :id shapes)}
|
:shapes (vec shapes)}
|
||||||
|
|
||||||
shape
|
shape
|
||||||
(-> shape
|
(-> shape
|
||||||
(merge (select-keys head bool/style-properties))
|
(merge (select-keys head bool/style-properties))
|
||||||
(cts/setup-shape)
|
(cts/setup-shape)
|
||||||
(gsh/update-bool shapes objects))]
|
(gsh/update-bool objects))]
|
||||||
|
|
||||||
[shape (cph/get-position-on-parent objects (:id head))]))
|
[shape (cph/get-position-on-parent objects (:id head))]))
|
||||||
|
|
||||||
|
@ -108,19 +104,16 @@
|
||||||
(defn group->bool
|
(defn group->bool
|
||||||
[type group objects]
|
[type group objects]
|
||||||
(let [shapes (->> (:shapes group)
|
(let [shapes (->> (:shapes group)
|
||||||
(map #(get objects %))
|
(map (d/getf objects)))
|
||||||
(mapv #(path/convert-to-path % objects)))
|
|
||||||
head (if (= type :difference) (first shapes) (last shapes))
|
head (if (= type :difference) (first shapes) (last shapes))
|
||||||
head (cond-> head
|
head (cond-> head
|
||||||
(and (contains? head :svg-attrs) (empty? (:fills head)))
|
(and (contains? head :svg-attrs) (empty? (:fills head)))
|
||||||
(assoc :fills bool/default-fills))
|
(assoc :fills bool/default-fills))]
|
||||||
head-data (select-keys head bool/style-properties)]
|
|
||||||
|
|
||||||
(-> group
|
(-> group
|
||||||
(assoc :type :bool)
|
(assoc :type :bool)
|
||||||
(assoc :bool-type type)
|
(assoc :bool-type type)
|
||||||
(merge head-data)
|
(merge (select-keys head bool/style-properties))
|
||||||
(gsh/update-bool shapes objects))))
|
(gsh/update-bool objects))))
|
||||||
|
|
||||||
(defn group-to-bool
|
(defn group-to-bool
|
||||||
[shape-id type]
|
[shape-id type]
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
(ns app.util.object
|
(ns app.util.object
|
||||||
"A collection of helpers for work with javascript objects."
|
"A collection of helpers for work with javascript objects."
|
||||||
(:refer-clojure :exclude [set! new get merge clone contains? array? into-array reify])
|
(:refer-clojure :exclude [set! new get merge clone contains? array? into-array reify class])
|
||||||
#?(:cljs (:require-macros [app.util.object]))
|
#?(:cljs (:require-macros [app.util.object]))
|
||||||
(:require
|
(:require
|
||||||
[clojure.core :as c]))
|
[clojure.core :as c]))
|
||||||
|
|
250
frontend/src/lib/file_builder.cljs
Normal file
250
frontend/src/lib/file_builder.cljs
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns lib.file-builder
|
||||||
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
|
[app.common.files.builder :as fb]
|
||||||
|
[app.common.json :as json]
|
||||||
|
[app.common.schema :as sm]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
|
(def BuilderError
|
||||||
|
(obj/class
|
||||||
|
:name "BuilderError"
|
||||||
|
:extends js/Error
|
||||||
|
:constructor
|
||||||
|
(fn [this type code hint cause]
|
||||||
|
(.call js/Error this hint)
|
||||||
|
(set! (.-name this) (str "Exception: " hint))
|
||||||
|
(set! (.-type this) type)
|
||||||
|
(set! (.-code this) code)
|
||||||
|
(set! (.-hint this) hint)
|
||||||
|
|
||||||
|
(when (exists? js/Error.captureStackTrace)
|
||||||
|
(.captureStackTrace js/Error this))
|
||||||
|
|
||||||
|
(obj/add-properties!
|
||||||
|
this
|
||||||
|
{:name "cause"
|
||||||
|
:enumerable true
|
||||||
|
:this false
|
||||||
|
:get (fn [] cause)}
|
||||||
|
{:name "data"
|
||||||
|
:enumerable true
|
||||||
|
:this false
|
||||||
|
:get (fn []
|
||||||
|
(let [data (ex-data cause)]
|
||||||
|
(when-let [explain (::sm/explain data)]
|
||||||
|
(json/->js (sm/simplify explain)))))}))))
|
||||||
|
|
||||||
|
(defn- handle-exception
|
||||||
|
[cause]
|
||||||
|
(let [data (ex-data cause)]
|
||||||
|
(throw (new BuilderError
|
||||||
|
(d/name (get data :type :unknown))
|
||||||
|
(d/name (get data :code :unknown))
|
||||||
|
(or (get data :hint) (ex-message cause))
|
||||||
|
cause))))
|
||||||
|
|
||||||
|
(defn- decode-params
|
||||||
|
[params]
|
||||||
|
(if (obj/plain-object? params)
|
||||||
|
(json/->js params)
|
||||||
|
params))
|
||||||
|
|
||||||
|
(defn- create-file*
|
||||||
|
[file]
|
||||||
|
(let [state* (volatile! file)]
|
||||||
|
(obj/reify {:name "File"}
|
||||||
|
:id
|
||||||
|
{:get #(dm/str (:id @state*))}
|
||||||
|
|
||||||
|
:currentFrameId
|
||||||
|
{:get #(dm/str (::fb/current-frame-id @state*))}
|
||||||
|
|
||||||
|
:currentPageId
|
||||||
|
{:get #(dm/str (::fb/current-page-id @state*))}
|
||||||
|
|
||||||
|
:lastId
|
||||||
|
{:get #(dm/str (::fb/last-id @state*))}
|
||||||
|
|
||||||
|
:addPage
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(decode-params)
|
||||||
|
(fb/decode-page))]
|
||||||
|
(vswap! state* fb/add-page params)
|
||||||
|
(dm/str (::fb/current-page-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:closePage
|
||||||
|
(fn []
|
||||||
|
(vswap! state* fb/close-page))
|
||||||
|
|
||||||
|
:addArtboard
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(assoc :type :frame)
|
||||||
|
(fb/decode-shape))]
|
||||||
|
(vswap! state* fb/add-artboard params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:closeArtboard
|
||||||
|
(fn []
|
||||||
|
(vswap! state* fb/close-artboard))
|
||||||
|
|
||||||
|
:addGroup
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(assoc :type :group)
|
||||||
|
(fb/decode-shape))]
|
||||||
|
(vswap! state* fb/add-group params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:closeGroup
|
||||||
|
(fn []
|
||||||
|
(vswap! state* fb/close-group))
|
||||||
|
|
||||||
|
:addBool
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(fb/decode-add-bool))]
|
||||||
|
(vswap! state* fb/add-bool params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addRect
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(assoc :type :rect)
|
||||||
|
(fb/decode-shape))]
|
||||||
|
(vswap! state* fb/add-shape params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addCircle
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(assoc :type :circle)
|
||||||
|
(fb/decode-shape))]
|
||||||
|
(vswap! state* fb/add-shape params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addPath
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(assoc :type :path)
|
||||||
|
(fb/decode-shape))]
|
||||||
|
(vswap! state* fb/add-shape params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addText
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(assoc :type :text)
|
||||||
|
(fb/decode-shape))]
|
||||||
|
(vswap! state* fb/add-shape params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addLibraryColor
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(fb/decode-library-color)
|
||||||
|
(d/without-nils))]
|
||||||
|
(vswap! state* fb/add-library-color params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addLibraryTypography
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(fb/decode-library-typography)
|
||||||
|
(d/without-nils))]
|
||||||
|
(vswap! state* fb/add-library-typography params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addComponent
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(fb/decode-component)
|
||||||
|
(d/without-nils))]
|
||||||
|
(vswap! state* fb/add-component params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:addComponentInstance
|
||||||
|
(fn [params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params
|
||||||
|
(json/->clj)
|
||||||
|
(fb/decode-add-component-instance)
|
||||||
|
(d/without-nils))]
|
||||||
|
(vswap! state* fb/add-component-instance params)
|
||||||
|
(dm/str (::fb/last-id @state*)))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
||||||
|
|
||||||
|
:getShape
|
||||||
|
(fn [shape-id]
|
||||||
|
(let [shape-id (uuid/parse shape-id)]
|
||||||
|
(some-> (fb/lookup-shape @state* shape-id)
|
||||||
|
(json/->js))))
|
||||||
|
|
||||||
|
:toMap
|
||||||
|
(fn []
|
||||||
|
(-> @state*
|
||||||
|
(d/without-qualified)
|
||||||
|
(json/->js))))))
|
||||||
|
|
||||||
|
(defn create-file
|
||||||
|
[params]
|
||||||
|
(try
|
||||||
|
(let [params (-> params json/->clj fb/decode-file)
|
||||||
|
file (fb/create-file params)]
|
||||||
|
(create-file* file))
|
||||||
|
(catch :default cause
|
||||||
|
(handle-exception cause))))
|
30
frontend/src/lib/playground/sample1.js
Normal file
30
frontend/src/lib/playground/sample1.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import * as penpot from "../../../target/library/penpot.js";
|
||||||
|
|
||||||
|
console.log(penpot);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const file = penpot.createFile({name: "Test"});
|
||||||
|
file.addPage({name: "Foo Page"})
|
||||||
|
const boardId = file.addArtboard({name: "Foo Board"})
|
||||||
|
const rectId = file.addRect({name: "Foo Rect", width:100, height: 200})
|
||||||
|
|
||||||
|
file.addLibraryColor({color: "#fabada", opacity: 0.5})
|
||||||
|
|
||||||
|
console.log("created board", boardId);
|
||||||
|
console.log("created rect", rectId);
|
||||||
|
|
||||||
|
const board = file.getShape(boardId);
|
||||||
|
console.log("=========== BOARD =============")
|
||||||
|
console.dir(board, {depth: 10});
|
||||||
|
|
||||||
|
const rect = file.getShape(rectId);
|
||||||
|
console.log("=========== RECT =============")
|
||||||
|
console.dir(rect, {depth: 10});
|
||||||
|
|
||||||
|
// console.dir(file.toMap(), {depth:10});
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
// console.log(e.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0);
|
|
@ -16,8 +16,7 @@
|
||||||
|
|
||||||
(t/deftest test-common-shape-properties
|
(t/deftest test-common-shape-properties
|
||||||
(let [;; ==== Setup
|
(let [;; ==== Setup
|
||||||
store (ths/setup-store
|
store (ths/setup-store (cthf/sample-file :file1 :page-label :page1))
|
||||||
(cthf/sample-file :file1 :page-label :page1))
|
|
||||||
|
|
||||||
^js context (api/create-context "TEST")
|
^js context (api/create-context "TEST")
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,21 @@
|
||||||
[cljs.pprint :refer [pprint]]
|
[cljs.pprint :refer [pprint]]
|
||||||
[cljs.test :as t :include-macros true]))
|
[cljs.test :as t :include-macros true]))
|
||||||
|
|
||||||
|
(def uuid-counter 1)
|
||||||
|
|
||||||
|
(defn get-mocked-uuid
|
||||||
|
[]
|
||||||
|
(let [counter (atom 0)]
|
||||||
|
(fn []
|
||||||
|
(uuid/custom 123456789 (swap! counter inc)))))
|
||||||
|
|
||||||
(t/deftest test-create-index
|
(t/deftest test-create-index
|
||||||
(t/testing "Create empty data"
|
(t/testing "Create empty data"
|
||||||
(let [data (sd/make-snap-data)]
|
(let [data (sd/make-snap-data)]
|
||||||
(t/is (some? data))))
|
(t/is (some? data))))
|
||||||
|
|
||||||
(t/testing "Add empty page (only root-frame)"
|
(t/testing "Add empty page (only root-frame)"
|
||||||
(let [page (-> (fb/create-file "Test")
|
(let [page (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/get-current-page))
|
(fb/get-current-page))
|
||||||
|
|
||||||
|
@ -28,10 +36,11 @@
|
||||||
(t/is (some? data))))
|
(t/is (some? data))))
|
||||||
|
|
||||||
(t/testing "Create simple shape on root"
|
(t/testing "Create simple shape on root"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/create-rect
|
(fb/add-shape
|
||||||
{:x 0
|
{:type :rect
|
||||||
|
:x 0
|
||||||
:y 0
|
:y 0
|
||||||
:width 100
|
:width 100
|
||||||
:height 100}))
|
:height 100}))
|
||||||
|
@ -57,7 +66,7 @@
|
||||||
(t/is (= (first (nth result-x 2)) 100))))
|
(t/is (= (first (nth result-x 2)) 100))))
|
||||||
|
|
||||||
(t/testing "Add page with single empty frame"
|
(t/testing "Add page with single empty frame"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-artboard
|
(fb/add-artboard
|
||||||
{:x 0
|
{:x 0
|
||||||
|
@ -66,10 +75,10 @@
|
||||||
:height 100})
|
:height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
|
|
||||||
;; frame-id (:last-id file)
|
;; frame-id (::fb/last-id file)
|
||||||
data (-> (sd/make-snap-data)
|
data (-> (sd/make-snap-data)
|
||||||
(sd/add-page page))
|
(sd/add-page page))
|
||||||
|
|
||||||
|
@ -81,47 +90,49 @@
|
||||||
(t/is (= (count result-frame-x) 3))))
|
(t/is (= (count result-frame-x) 3))))
|
||||||
|
|
||||||
(t/testing "Add page with some shapes inside frames"
|
(t/testing "Add page with some shapes inside frames"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(with-redefs [uuid/next (get-mocked-uuid)]
|
||||||
(fb/add-page {:name "Page 1"})
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-artboard
|
(fb/add-page {:name "Page 1"})
|
||||||
{:x 0
|
(fb/add-artboard
|
||||||
:y 0
|
{:x 0
|
||||||
:width 100
|
:y 0
|
||||||
:height 100}))
|
:width 100
|
||||||
frame-id (:last-id file)
|
:height 100}))
|
||||||
|
|
||||||
file (-> file
|
frame-id (::fb/last-id file)
|
||||||
(fb/create-rect
|
|
||||||
{:x 25
|
|
||||||
:y 25
|
|
||||||
:width 50
|
|
||||||
:height 50})
|
|
||||||
(fb/close-artboard))
|
|
||||||
|
|
||||||
page (fb/get-current-page file)
|
file (-> file
|
||||||
|
(fb/add-shape
|
||||||
|
{:type :rect
|
||||||
|
:x 25
|
||||||
|
:y 25
|
||||||
|
:width 50
|
||||||
|
:height 50})
|
||||||
|
(fb/close-artboard))
|
||||||
|
|
||||||
;; frame-id (:last-id file)
|
page (fb/get-current-page file)
|
||||||
data (-> (sd/make-snap-data)
|
|
||||||
(sd/add-page page))
|
|
||||||
|
|
||||||
result-zero-x (sd/query data (:id page) uuid/zero :x [0 100])
|
data (-> (sd/make-snap-data)
|
||||||
result-frame-x (sd/query data (:id page) frame-id :x [0 100])]
|
(sd/add-page page))
|
||||||
|
|
||||||
(t/is (some? data))
|
result-zero-x (sd/query data (:id page) uuid/zero :x [0 100])
|
||||||
(t/is (= (count result-zero-x) 3))
|
result-frame-x (sd/query data (:id page) frame-id :x [0 100])]
|
||||||
(t/is (= (count result-frame-x) 5))))
|
|
||||||
|
(t/is (some? data))
|
||||||
|
(t/is (= (count result-zero-x) 3))
|
||||||
|
(t/is (= (count result-frame-x) 5)))))
|
||||||
|
|
||||||
(t/testing "Add a global guide"
|
(t/testing "Add a global guide"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-guide {:position 50 :axis :x})
|
(fb/add-guide {:position 50 :axis :x})
|
||||||
(fb/add-artboard {:x 200 :y 200 :width 100 :height 100})
|
(fb/add-artboard {:x 200 :y 200 :width 100 :height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
|
|
||||||
;; frame-id (:last-id file)
|
;; frame-id (::fb/last-id file)
|
||||||
data (-> (sd/make-snap-data)
|
data (-> (sd/make-snap-data)
|
||||||
(sd/add-page page))
|
(sd/add-page page))
|
||||||
|
|
||||||
|
@ -140,26 +151,26 @@
|
||||||
(t/is (= (count result-frame-y) 0))))
|
(t/is (= (count result-frame-y) 0))))
|
||||||
|
|
||||||
(t/testing "Add a frame guide"
|
(t/testing "Add a frame guide"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-artboard {:x 200 :y 200 :width 100 :height 100})
|
(fb/add-artboard {:x 200 :y 200 :width 100 :height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
|
|
||||||
file (-> file
|
file (-> file
|
||||||
(fb/add-guide {:position 50 :axis :x :frame-id frame-id}))
|
(fb/add-guide {:position 50 :axis :x :frame-id frame-id}))
|
||||||
|
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
|
|
||||||
;; frame-id (:last-id file)
|
data (-> (sd/make-snap-data)
|
||||||
data (-> (sd/make-snap-data)
|
(sd/add-page page))
|
||||||
(sd/add-page page))
|
|
||||||
|
|
||||||
result-zero-x (sd/query data (:id page) uuid/zero :x [0 100])
|
result-zero-x (sd/query data (:id page) uuid/zero :x [0 100])
|
||||||
result-zero-y (sd/query data (:id page) uuid/zero :y [0 100])
|
result-zero-y (sd/query data (:id page) uuid/zero :y [0 100])
|
||||||
result-frame-x (sd/query data (:id page) frame-id :x [0 100])
|
result-frame-x (sd/query data (:id page) frame-id :x [0 100])
|
||||||
result-frame-y (sd/query data (:id page) frame-id :y [0 100])]
|
result-frame-y (sd/query data (:id page) frame-id :y [0 100])]
|
||||||
|
|
||||||
(t/is (some? data))
|
(t/is (some? data))
|
||||||
;; We can snap in the root
|
;; We can snap in the root
|
||||||
(t/is (= (count result-zero-x) 0))
|
(t/is (= (count result-zero-x) 0))
|
||||||
|
@ -171,7 +182,7 @@
|
||||||
|
|
||||||
(t/deftest test-update-index
|
(t/deftest test-update-index
|
||||||
(t/testing "Create frame on root and then remove it."
|
(t/testing "Create frame on root and then remove it."
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-artboard
|
(fb/add-artboard
|
||||||
{:x 0
|
{:x 0
|
||||||
|
@ -180,15 +191,15 @@
|
||||||
:height 100})
|
:height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
shape-id (:last-id file)
|
shape-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
|
|
||||||
;; frame-id (:last-id file)
|
;; frame-id (::fb/last-id file)
|
||||||
data (-> (sd/make-snap-data)
|
data (-> (sd/make-snap-data)
|
||||||
(sd/add-page page))
|
(sd/add-page page))
|
||||||
|
|
||||||
file (-> file
|
file (-> file
|
||||||
(fb/delete-object shape-id))
|
(fb/delete-shape shape-id))
|
||||||
|
|
||||||
new-page (fb/get-current-page file)
|
new-page (fb/get-current-page file)
|
||||||
data (sd/update-page data page new-page)
|
data (sd/update-page data page new-page)
|
||||||
|
@ -201,22 +212,23 @@
|
||||||
(t/is (= (count result-y) 0))))
|
(t/is (= (count result-y) 0))))
|
||||||
|
|
||||||
(t/testing "Create simple shape on root. Then remove it"
|
(t/testing "Create simple shape on root. Then remove it"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/create-rect
|
(fb/add-shape
|
||||||
{:x 0
|
{:type :rect
|
||||||
|
:x 0
|
||||||
:y 0
|
:y 0
|
||||||
:width 100
|
:width 100
|
||||||
:height 100}))
|
:height 100}))
|
||||||
|
|
||||||
shape-id (:last-id file)
|
shape-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
|
|
||||||
;; frame-id (:last-id file)
|
;; frame-id (::fb/last-id file)
|
||||||
data (-> (sd/make-snap-data)
|
data (-> (sd/make-snap-data)
|
||||||
(sd/add-page page))
|
(sd/add-page page))
|
||||||
|
|
||||||
file (fb/delete-object file shape-id)
|
file (fb/delete-shape file shape-id)
|
||||||
|
|
||||||
new-page (fb/get-current-page file)
|
new-page (fb/get-current-page file)
|
||||||
data (sd/update-page data page new-page)
|
data (sd/update-page data page new-page)
|
||||||
|
@ -229,17 +241,17 @@
|
||||||
(t/is (= (count result-y) 0))))
|
(t/is (= (count result-y) 0))))
|
||||||
|
|
||||||
(t/testing "Create shape inside frame, then remove it"
|
(t/testing "Create shape inside frame, then remove it"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-artboard
|
(fb/add-artboard
|
||||||
{:x 0
|
{:x 0
|
||||||
:y 0
|
:y 0
|
||||||
:width 100
|
:width 100
|
||||||
:height 100}))
|
:height 100}))
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
|
|
||||||
file (fb/create-rect file {:x 25 :y 25 :width 50 :height 50})
|
file (fb/add-shape file {:type :rect :x 25 :y 25 :width 50 :height 50})
|
||||||
shape-id (:last-id file)
|
shape-id (::fb/last-id file)
|
||||||
|
|
||||||
file (fb/close-artboard file)
|
file (fb/close-artboard file)
|
||||||
|
|
||||||
|
@ -247,7 +259,7 @@
|
||||||
data (-> (sd/make-snap-data)
|
data (-> (sd/make-snap-data)
|
||||||
(sd/add-page page))
|
(sd/add-page page))
|
||||||
|
|
||||||
file (fb/delete-object file shape-id)
|
file (fb/delete-shape file shape-id)
|
||||||
new-page (fb/get-current-page file)
|
new-page (fb/get-current-page file)
|
||||||
|
|
||||||
data (sd/update-page data page new-page)
|
data (sd/update-page data page new-page)
|
||||||
|
@ -260,16 +272,16 @@
|
||||||
(t/is (= (count result-frame-x) 3))))
|
(t/is (= (count result-frame-x) 3))))
|
||||||
|
|
||||||
(t/testing "Create global guide then remove it"
|
(t/testing "Create global guide then remove it"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-guide {:position 50 :axis :x}))
|
(fb/add-guide {:position 50 :axis :x}))
|
||||||
|
|
||||||
guide-id (:last-id file)
|
guide-id (::fb/last-id file)
|
||||||
|
|
||||||
file (-> (fb/add-artboard file {:x 200 :y 200 :width 100 :height 100})
|
file (-> (fb/add-artboard file {:x 200 :y 200 :width 100 :height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
data (-> (sd/make-snap-data) (sd/add-page page))
|
data (-> (sd/make-snap-data) (sd/add-page page))
|
||||||
|
|
||||||
|
@ -293,14 +305,14 @@
|
||||||
(t/is (= (count result-frame-y) 0))))
|
(t/is (= (count result-frame-y) 0))))
|
||||||
|
|
||||||
(t/testing "Create frame guide then remove it"
|
(t/testing "Create frame guide then remove it"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-artboard {:x 200 :y 200 :width 100 :height 100})
|
(fb/add-artboard {:x 200 :y 200 :width 100 :height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
file (fb/add-guide file {:position 50 :axis :x :frame-id frame-id})
|
file (fb/add-guide file {:position 50 :axis :x :frame-id frame-id})
|
||||||
guide-id (:last-id file)
|
guide-id (::fb/last-id file)
|
||||||
|
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
data (-> (sd/make-snap-data) (sd/add-page page))
|
data (-> (sd/make-snap-data) (sd/add-page page))
|
||||||
|
@ -324,7 +336,7 @@
|
||||||
(t/is (= (count result-frame-y) 0))))
|
(t/is (= (count result-frame-y) 0))))
|
||||||
|
|
||||||
(t/testing "Update frame coordinates"
|
(t/testing "Update frame coordinates"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-artboard
|
(fb/add-artboard
|
||||||
{:x 0
|
{:x 0
|
||||||
|
@ -333,17 +345,18 @@
|
||||||
:height 100})
|
:height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
data (-> (sd/make-snap-data) (sd/add-page page))
|
data (-> (sd/make-snap-data) (sd/add-page page))
|
||||||
|
|
||||||
frame (fb/lookup-shape file frame-id)
|
file (fb/update-shape file frame-id
|
||||||
new-frame (-> frame
|
(fn [shape]
|
||||||
(dissoc :selrect :points)
|
(-> shape
|
||||||
(assoc :x 200 :y 200)
|
(dissoc :selrect :points)
|
||||||
(cts/setup-shape))
|
(assoc :x 200 :y 200)
|
||||||
|
(cts/setup-shape))))
|
||||||
|
|
||||||
|
|
||||||
file (fb/update-object file frame new-frame)
|
|
||||||
new-page (fb/get-current-page file)
|
new-page (fb/get-current-page file)
|
||||||
|
|
||||||
data (sd/update-page data page new-page)
|
data (sd/update-page data page new-page)
|
||||||
|
@ -360,27 +373,30 @@
|
||||||
(t/is (= (count result-frame-x-2) 3))))
|
(t/is (= (count result-frame-x-2) 3))))
|
||||||
|
|
||||||
(t/testing "Update shape coordinates"
|
(t/testing "Update shape coordinates"
|
||||||
(let [file (-> (fb/create-file "Test")
|
(let [file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/create-rect
|
(fb/add-shape
|
||||||
{:x 0
|
{:type :rect
|
||||||
|
:x 0
|
||||||
:y 0
|
:y 0
|
||||||
:width 100
|
:width 100
|
||||||
:height 100}))
|
:height 100}))
|
||||||
|
|
||||||
shape-id (:last-id file)
|
shape-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
data (-> (sd/make-snap-data) (sd/add-page page))
|
data (-> (sd/make-snap-data)
|
||||||
|
(sd/add-page page))
|
||||||
|
|
||||||
shape (fb/lookup-shape file shape-id)
|
file (fb/update-shape file shape-id
|
||||||
new-shape (-> shape
|
(fn [shape]
|
||||||
(dissoc :selrect :points)
|
(-> shape
|
||||||
(assoc :x 200 :y 200))
|
(dissoc :selrect :points)
|
||||||
|
(assoc :x 200 :y 200)
|
||||||
|
(cts/setup-shape))))
|
||||||
|
|
||||||
file (fb/update-object file shape new-shape)
|
|
||||||
new-page (fb/get-current-page file)
|
new-page (fb/get-current-page file)
|
||||||
|
;; FIXME: update
|
||||||
data (sd/update-page data page new-page)
|
data (sd/update-page data page new-page)
|
||||||
|
|
||||||
result-zero-x-1 (sd/query data (:id page) uuid/zero :x [0 100])
|
result-zero-x-1 (sd/query data (:id page) uuid/zero :x [0 100])
|
||||||
result-zero-x-2 (sd/query data (:id page) uuid/zero :x [200 300])]
|
result-zero-x-2 (sd/query data (:id page) uuid/zero :x [200 300])]
|
||||||
|
@ -391,17 +407,17 @@
|
||||||
|
|
||||||
(t/testing "Update global guide"
|
(t/testing "Update global guide"
|
||||||
(let [guide {:position 50 :axis :x}
|
(let [guide {:position 50 :axis :x}
|
||||||
file (-> (fb/create-file "Test")
|
file (-> (fb/create-file {:name "Test"})
|
||||||
(fb/add-page {:name "Page 1"})
|
(fb/add-page {:name "Page 1"})
|
||||||
(fb/add-guide guide))
|
(fb/add-guide guide))
|
||||||
|
|
||||||
guide-id (:last-id file)
|
guide-id (::fb/last-id file)
|
||||||
guide (assoc guide :id guide-id)
|
guide (assoc guide :id guide-id)
|
||||||
|
|
||||||
file (-> (fb/add-artboard file {:x 500 :y 500 :width 100 :height 100})
|
file (-> (fb/add-artboard file {:x 500 :y 500 :width 100 :height 100})
|
||||||
(fb/close-artboard))
|
(fb/close-artboard))
|
||||||
|
|
||||||
frame-id (:last-id file)
|
frame-id (::fb/last-id file)
|
||||||
page (fb/get-current-page file)
|
page (fb/get-current-page file)
|
||||||
data (-> (sd/make-snap-data) (sd/add-page page))
|
data (-> (sd/make-snap-data) (sd/add-page page))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue