mirror of
https://github.com/penpot/penpot.git
synced 2025-05-10 22:46:37 +02:00
WIP
This commit is contained in:
parent
56f7613453
commit
6b6aba7358
8 changed files with 258 additions and 37 deletions
|
@ -1,32 +1,104 @@
|
||||||
(ns uxbox.data.projects
|
(ns uxbox.data.projects
|
||||||
(:require [uxbox.rstore :as rs]
|
(:require [uxbox.rstore :as rs]
|
||||||
|
[uxbox.router :as r]
|
||||||
[uxbox.state :as st]
|
[uxbox.state :as st]
|
||||||
[uxbox.schema :as sc]
|
[uxbox.schema :as sc]
|
||||||
[bouncer.validators :as v]))
|
[bouncer.validators :as v]))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Schemas
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(def ^:static +project-schema+
|
(def ^:static +project-schema+
|
||||||
{:name [v/required v/string]
|
{:name [v/required v/string]
|
||||||
:width [v/required v/integer]
|
:width [v/required v/integer]
|
||||||
:height [v/required v/integer]
|
:height [v/required v/integer]
|
||||||
:layout [v/required sc/keyword?]})
|
:layout [v/required sc/keyword]})
|
||||||
|
|
||||||
(defn create-project
|
(def ^:static +page-schema+
|
||||||
[{:keys [name width height layout] :as data}]
|
{:name [v/required v/string]
|
||||||
(sc/validate! +project-schema+ data)
|
:width [v/required v/integer]
|
||||||
(println "create-project")
|
:height [v/required v/integer]
|
||||||
|
:project [v/required sc/uuid]})
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Events
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(defn create-page
|
||||||
|
[{:keys [name width height project] :as data}]
|
||||||
|
(sc/validate! +page-schema+ data)
|
||||||
(reify
|
(reify
|
||||||
rs/UpdateEvent
|
rs/UpdateEvent
|
||||||
(-apply-update [_ state]
|
(-apply-update [_ state]
|
||||||
(let [uuid (random-uuid)
|
(let [uuid (random-uuid)
|
||||||
proj {:id uuid
|
page {:id uuid
|
||||||
|
:project project
|
||||||
:name name
|
:name name
|
||||||
:width width
|
:width width
|
||||||
:height height
|
:height height}]
|
||||||
:pages []}]
|
|
||||||
(-> state
|
(-> state
|
||||||
(update-in [:projects] conj uuid)
|
(update-in [:pages] conj uuid)
|
||||||
(update-in [:projects-by-id] assoc uuid {:name name}))))
|
(update-in [:projects-by-id project :pages] conj uuid)
|
||||||
|
(update-in [:pages-by-id] assoc uuid page))))
|
||||||
|
|
||||||
IPrintWithWriter
|
IPrintWithWriter
|
||||||
(-pr-writer [mv writer _]
|
(-pr-writer [mv writer _]
|
||||||
(-write writer "#<event:u.s.p/create-project>"))))
|
(-write writer "#<event:u.s.p/create-page>"))))
|
||||||
|
|
||||||
|
(defn create-project
|
||||||
|
[{:keys [name width height layout] :as data}]
|
||||||
|
(sc/validate! +project-schema+ data)
|
||||||
|
(let [uuid (random-uuid)]
|
||||||
|
(reify
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(let [proj {:id uuid
|
||||||
|
:name name
|
||||||
|
:width width
|
||||||
|
:height height
|
||||||
|
:pages []}]
|
||||||
|
(-> state
|
||||||
|
(update-in [:projects] conj uuid)
|
||||||
|
(update-in [:projects-by-id] assoc uuid proj))))
|
||||||
|
|
||||||
|
rs/EffectEvent
|
||||||
|
(-apply-effect [_ state]
|
||||||
|
(rs/emit! (create-page {:name "Page 1"
|
||||||
|
:width width
|
||||||
|
:height height
|
||||||
|
:project uuid})))
|
||||||
|
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [mv writer _]
|
||||||
|
(-write writer "#<event:u.s.p/create-project>")))))
|
||||||
|
|
||||||
|
(defn initialize-workspace
|
||||||
|
[projectid pageid]
|
||||||
|
(reify
|
||||||
|
rs/UpdateEvent
|
||||||
|
(-apply-update [_ state]
|
||||||
|
(assoc state :workspace {:project projectid :page pageid}))
|
||||||
|
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [mv writer _]
|
||||||
|
(-write writer "#<event:u.s.p/go-to-project>"))))
|
||||||
|
|
||||||
|
(defn go-to-project
|
||||||
|
"A shortcut event that redirects the user to the
|
||||||
|
first page of the project."
|
||||||
|
([projectid]
|
||||||
|
(go-to-project projectid nil))
|
||||||
|
([projectid pageid]
|
||||||
|
(reify
|
||||||
|
rs/EffectEvent
|
||||||
|
(-apply-effect [_ state]
|
||||||
|
(if pageid
|
||||||
|
(rs/emit! (r/navigate :main/page {:project-uuid projectid
|
||||||
|
:page-uuid pageid}))
|
||||||
|
(let [pages (get-in state [:projects-by-id projectid :pages])]
|
||||||
|
(rs/emit! (r/navigate :main/page {:project-uuid projectid
|
||||||
|
:page-uuid (first pages)})))))
|
||||||
|
IPrintWithWriter
|
||||||
|
(-pr-writer [mv writer _]
|
||||||
|
(-write writer "#<event:u.s.p/go-to-project")))))
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
(let [loc (merge {:handler name}
|
(let [loc (merge {:handler name}
|
||||||
(when params
|
(when params
|
||||||
{:route-params params}))]
|
{:route-params params}))]
|
||||||
|
(println "navigate" loc)
|
||||||
(bidi.router/set-location! +router+ loc))))))
|
(bidi.router/set-location! +router+ loc))))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -50,7 +51,7 @@
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(def ^:private project-route
|
(def ^:private project-route
|
||||||
[bidi/uuid :project-uuid])
|
[[bidi/uuid :project-uuid]])
|
||||||
|
|
||||||
(def ^:private page-route
|
(def ^:private page-route
|
||||||
[[bidi/uuid :project-uuid] "/" [bidi/uuid :page-uuid]])
|
[[bidi/uuid :project-uuid] "/" [bidi/uuid :page-uuid]])
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
(ns uxbox.schema
|
(ns uxbox.schema
|
||||||
(:refer-clojure :exclude [keyword?])
|
(:refer-clojure :exclude [keyword uuid])
|
||||||
(:require [bouncer.core :as b]
|
(:require [bouncer.core :as b]
|
||||||
[bouncer.validators :as v]))
|
[bouncer.validators :as v]))
|
||||||
|
|
||||||
|
@ -7,13 +7,21 @@
|
||||||
;; Validators
|
;; Validators
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(v/defvalidator keyword?
|
(v/defvalidator keyword
|
||||||
"Validates maybe-an-int is a valid integer.
|
"Validates maybe-an-int is a valid integer.
|
||||||
For use with validation functions such as `validate` or `valid?`"
|
For use with validation functions such as `validate` or `valid?`"
|
||||||
{:default-message-format "%s must be a keyword"}
|
{:default-message-format "%s must be a keyword"}
|
||||||
[v]
|
[v]
|
||||||
(cljs.core/keyword? v))
|
(cljs.core/keyword? v))
|
||||||
|
|
||||||
|
|
||||||
|
(v/defvalidator uuid
|
||||||
|
"Validates maybe-an-int is a valid integer.
|
||||||
|
For use with validation functions such as `validate` or `valid?`"
|
||||||
|
{:default-message-format "%s must be a uuid instance"}
|
||||||
|
[v]
|
||||||
|
(instance? cljs.core.UUID v))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Public Api
|
;; Public Api
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
(defonce stream
|
(defonce stream
|
||||||
(rs/init {:user {:fullname "Cirilla"
|
(rs/init {:user {:fullname "Cirilla"
|
||||||
:avatar "http://lorempixel.com/50/50/"}
|
:avatar "http://lorempixel.com/50/50/"}
|
||||||
|
:workspace nil
|
||||||
:projects []
|
:projects []
|
||||||
:pages []
|
:pages []
|
||||||
:projects-by-id {}
|
:projects-by-id {}
|
||||||
|
@ -16,5 +17,6 @@
|
||||||
|
|
||||||
(defonce +setup-stuff+
|
(defonce +setup-stuff+
|
||||||
(do
|
(do
|
||||||
(rx/to-atom stream state)))
|
(rx/to-atom stream state)
|
||||||
|
(rx/on-value stream #(println "state:" %))))
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
[rum.core :as rum]
|
[rum.core :as rum]
|
||||||
[cats.labs.lens :as l]
|
[cats.labs.lens :as l]
|
||||||
[uxbox.state :as s]
|
[uxbox.state :as s]
|
||||||
|
[uxbox.rstore :as rs]
|
||||||
[uxbox.util :as util]
|
[uxbox.util :as util]
|
||||||
|
[uxbox.data.projects :as dp]
|
||||||
[uxbox.ui.lightbox :as ui.lb]
|
[uxbox.ui.lightbox :as ui.lb]
|
||||||
[uxbox.ui.users :as ui.u]
|
[uxbox.ui.users :as ui.u]
|
||||||
|
[uxbox.ui.workspace :as ui.w]
|
||||||
[uxbox.ui.dashboard :as ui.d]))
|
[uxbox.ui.dashboard :as ui.d]))
|
||||||
|
|
||||||
(def ^:static state
|
(def ^:static state
|
||||||
|
@ -15,6 +18,7 @@
|
||||||
(defn app-render
|
(defn app-render
|
||||||
[own]
|
[own]
|
||||||
(let [{:keys [location location-params] :as state} (rum/react state)]
|
(let [{:keys [location location-params] :as state} (rum/react state)]
|
||||||
|
(println 1111 location location-params)
|
||||||
(html
|
(html
|
||||||
[:section
|
[:section
|
||||||
(ui.lb/lightbox)
|
(ui.lb/lightbox)
|
||||||
|
@ -23,8 +27,11 @@
|
||||||
;; :auth/register (u/register)
|
;; :auth/register (u/register)
|
||||||
;; :auth/recover (u/recover-password)
|
;; :auth/recover (u/recover-password)
|
||||||
:main/dashboard (ui.d/dashboard)
|
:main/dashboard (ui.d/dashboard)
|
||||||
;; :main/project (w/workspace conn location-params)
|
;; :main/project (ui.w/workspace (:project-uuid location-params))
|
||||||
;; :main/page (w/workspace conn location-params))))
|
:main/page (let [projectid (:project-uuid location-params)
|
||||||
|
pageid (:page-uuid location-params)]
|
||||||
|
(rs/emit! (dp/initialize-workspace projectid pageid))
|
||||||
|
(ui.w/workspace projectid pageid))
|
||||||
nil
|
nil
|
||||||
)])))
|
)])))
|
||||||
|
|
||||||
|
|
|
@ -197,25 +197,27 @@
|
||||||
|
|
||||||
(defn project-render
|
(defn project-render
|
||||||
[own project]
|
[own project]
|
||||||
(html
|
(println "project-render" project)
|
||||||
[:div.grid-item.project-th {:on-click (constantly nil)
|
(let [on-click #(rs/emit! (dp/go-to-project (:id project)))]
|
||||||
:key (:uuid project)}
|
(html
|
||||||
[:h3 (:name project)]
|
[:div.grid-item.project-th {:on-click on-click
|
||||||
[:span.project-th-update
|
:key (:id project)}
|
||||||
(str "Updated " (ago (:last-update project)))]
|
[:h3 (:name project)]
|
||||||
[:div.project-th-actions
|
[:span.project-th-update
|
||||||
[:div.project-th-icon.pages
|
(str "Updated " (ago (:last-update project)))]
|
||||||
icons/page
|
[:div.project-th-actions
|
||||||
[:span 0]]
|
[:div.project-th-icon.pages
|
||||||
[:div.project-th-icon.comments
|
icons/page
|
||||||
i/chat
|
[:span 0]]
|
||||||
[:span 0]]
|
[:div.project-th-icon.comments
|
||||||
[:div.project-th-icon.delete
|
i/chat
|
||||||
{:on-click #(do
|
[:span 0]]
|
||||||
(dom/stop-propagation %)
|
[:div.project-th-icon.delete
|
||||||
;; (actions/delete-project conn uuid)
|
{:on-click #(do
|
||||||
%)}
|
(dom/stop-propagation %)
|
||||||
icons/trash]]]))
|
;; (actions/delete-project conn uuid)
|
||||||
|
%)}
|
||||||
|
icons/trash]]])))
|
||||||
|
|
||||||
(def project-item
|
(def project-item
|
||||||
(util/component
|
(util/component
|
||||||
|
|
118
frontend/uxbox/ui/workspace.cljs
Normal file
118
frontend/uxbox/ui/workspace.cljs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
(ns uxbox.ui.workspace
|
||||||
|
(:require [sablono.core :as html :refer-macros [html]]
|
||||||
|
[rum.core :as rum]
|
||||||
|
[cats.labs.lens :as l]
|
||||||
|
[cuerdas.core :as str]
|
||||||
|
[uxbox.util :as util]
|
||||||
|
[uxbox.router :as r]
|
||||||
|
[uxbox.rstore :as rs]
|
||||||
|
[uxbox.state :as s]
|
||||||
|
[uxbox.data.projects :as dp]
|
||||||
|
[uxbox.ui.icons.dashboard :as icons]
|
||||||
|
[uxbox.ui.icons :as i]
|
||||||
|
[uxbox.ui.dom :as dom]
|
||||||
|
[uxbox.ui.header :as ui.h]
|
||||||
|
[uxbox.ui.lightbox :as lightbox]
|
||||||
|
[uxbox.time :refer [ago]]))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Header
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
;; (defn header-render
|
||||||
|
;; [conn page grid? project-bar-visible?]
|
||||||
|
;; (let [{page-title :page/title
|
||||||
|
;; page-width :page/width
|
||||||
|
;; page-height :page/height} page]
|
||||||
|
;; [:header#workspace-bar.workspace-bar
|
||||||
|
;; [:div.main-icon
|
||||||
|
;; (nav/link (nav/route-for :dashboard) icons/logo-icon)]
|
||||||
|
;; (project-tree page-title project-bar-visible?)
|
||||||
|
;; [:div.workspace-options
|
||||||
|
;; [:ul.options-btn
|
||||||
|
;; [:li.tooltip.tooltip-bottom {:alt "Undo (Ctrl + Z)"}
|
||||||
|
;; icons/undo]
|
||||||
|
;; [:li.tooltip.tooltip-bottom {:alt "Redo (Ctrl + Shift + Z)"}
|
||||||
|
;; icons/redo]]
|
||||||
|
;; [:ul.options-btn
|
||||||
|
;; ;; TODO: refactor
|
||||||
|
;; [:li.tooltip.tooltip-bottom
|
||||||
|
;; {:alt "Export (Ctrl + E)"}
|
||||||
|
;; ;; page-title
|
||||||
|
;; [:a {:download (str page-title ".svg")
|
||||||
|
;; :href "#"
|
||||||
|
;; :on-click (fn [e]
|
||||||
|
;; (let [innerHTML (.-innerHTML (.getElementById js/document "page-layout"))
|
||||||
|
;; width page-width
|
||||||
|
;; height page-height
|
||||||
|
;; html (str "<svg width='" width "' height='" height "'>" innerHTML "</svg>")
|
||||||
|
;; data (js/Blob. #js [html] #js {:type "application/octet-stream"})
|
||||||
|
;; url (.createObjectURL (.-URL js/window) data)]
|
||||||
|
;; (set! (.-href (.-currentTarget e)) url)))}
|
||||||
|
;; icons/export]]
|
||||||
|
;; [:li.tooltip.tooltip-bottom
|
||||||
|
;; {:alt "Image (Ctrl + I)"}
|
||||||
|
;; icons/image]]
|
||||||
|
;; [:ul.options-btn
|
||||||
|
;; [:li.tooltip.tooltip-bottom
|
||||||
|
;; {:alt "Ruler (Ctrl + R)"}
|
||||||
|
;; icons/ruler]
|
||||||
|
;; [:li.tooltip.tooltip-bottom
|
||||||
|
;; {:alt "Grid (Ctrl + G)"
|
||||||
|
;; :class (when (rum/react ws/grid?) "selected")
|
||||||
|
;; :on-click ws/toggle-grid!}
|
||||||
|
;; icons/grid]
|
||||||
|
;; [:li.tooltip.tooltip-bottom
|
||||||
|
;; {:alt "Align (Ctrl + A)"}
|
||||||
|
;; icons/alignment]
|
||||||
|
;; [:li.tooltip.tooltip-bottom
|
||||||
|
;; {:alt "Organize (Ctrl + O)"}
|
||||||
|
;; icons/organize]]]
|
||||||
|
;; (user conn)]))
|
||||||
|
|
||||||
|
;; (def header
|
||||||
|
;; (util/component
|
||||||
|
;; {:render header-render
|
||||||
|
;; :name "header"}))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;; Header
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(def project-state
|
||||||
|
(as-> (util/dep-in [:projects-by-id] [:workspace :project]) $
|
||||||
|
(l/focus-atom $ s/state)))
|
||||||
|
|
||||||
|
(def page-state
|
||||||
|
(as-> (util/dep-in [:pages-by-id] [:workspace :page]) $
|
||||||
|
(l/focus-atom $ s/state)))
|
||||||
|
|
||||||
|
(defn workspace-render
|
||||||
|
[own projectid]
|
||||||
|
(println "workspace-render" @s/state)
|
||||||
|
(println 22222 @page-state)
|
||||||
|
(html
|
||||||
|
[:div "hello world"
|
||||||
|
;; (header conn page ws/grid? project-bar-visible?)
|
||||||
|
;; [:main.main-content
|
||||||
|
;; [:section.workspace-content
|
||||||
|
;; ;; Toolbar
|
||||||
|
;; (toolbar open-toolboxes)
|
||||||
|
;; ;; Project bar
|
||||||
|
;; (project-bar conn project page pages @project-bar-visible?)
|
||||||
|
;; ;; Rules
|
||||||
|
;; (horizontal-rule (rum/react ws/zoom))
|
||||||
|
;; (vertical-rule (rum/react ws/zoom))
|
||||||
|
;; ;; Working area
|
||||||
|
;; (working-area conn @open-toolboxes page project shapes (rum/react ws/zoom) (rum/react ws/grid?))
|
||||||
|
;; ;; Aside
|
||||||
|
;; (when-not (empty? @open-toolboxes)
|
||||||
|
;; (aside conn open-toolboxes page shapes))
|
||||||
|
]))
|
||||||
|
|
||||||
|
(def ^:static workspace
|
||||||
|
(util/component
|
||||||
|
{:render workspace-render
|
||||||
|
:name "workspace"
|
||||||
|
:mixins [rum/static]}))
|
||||||
|
|
|
@ -112,9 +112,20 @@
|
||||||
}))
|
}))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Lenses Helpers
|
;; Lenses & Helpers
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
(defn dep-in
|
||||||
|
[where link]
|
||||||
|
{:pre [(vector? where) (vector? link)]}
|
||||||
|
(l/lens
|
||||||
|
(fn [s]
|
||||||
|
(let [value (get-in s link)
|
||||||
|
path (conj where value)]
|
||||||
|
(get-in s path)))
|
||||||
|
(fn [s f]
|
||||||
|
(throw (ex-info "Not implemented" {})))))
|
||||||
|
|
||||||
(defn derive
|
(defn derive
|
||||||
[a path]
|
[a path]
|
||||||
(l/focus-atom (l/in path) a))
|
(l/focus-atom (l/in path) a))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue