0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-03-16 01:31:22 -05:00

🎉 Adds support for auto

This commit is contained in:
alonso.torres 2020-05-19 10:52:11 +02:00 committed by Andrés Moya
parent 1d2ae6d5eb
commit ad99e6df9d
6 changed files with 261 additions and 105 deletions

View file

@ -263,11 +263,6 @@
padding: $x-small $big $x-small $x-small;
position: relative;
& hr {
margin: 0;
border-color: $color-gray-20;
}
.dropdown-button {
position: absolute;
right: $x-small;
@ -284,7 +279,9 @@
font-size: $fs13;
}
.custom-select-dropdown {
}
.custom-select-dropdown {
position: absolute;
left: 0;
z-index: 12;
@ -297,6 +294,11 @@
border-radius: $br-small;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.25);
hr {
margin: 0;
border-color: $color-gray-20;
}
li {
color: $color-gray-60;
cursor: pointer;
@ -327,63 +329,96 @@
}
}
& li.checked-element {
padding-left: 0;
& li.checked-element {
padding-left: 0;
& span {
margin: 0;
color: $color-black;
}
& span {
margin: 0;
color: $color-black;
}
& svg {
visibility: hidden;
width: 8px;
height: 8px;
background: none;
margin: 0.25rem;
fill: $color-black;
}
& svg {
visibility: hidden;
width: 8px;
height: 8px;
background: none;
margin: 0.25rem;
fill: $color-black;
}
&.is-selected {
& svg {
visibility: visible;
}
}
}
}
&.is-selected {
& svg {
visibility: visible;
}
}
}
.editable-select {
height: 38px;
margin-right: $small;
position: relative;
width: 60%;
.input-text {
left: 0;
position: absolute;
top: -1px;
position: relative;
height: 38px;
margin-right: $small;
position: relative;
width: 60%;
}
.input-select {
background-color: transparent;
border: none;
border-bottom: 1px solid $color-gray-40;
color: transparent;
left: 0;
position: absolute;
top: 0;
width: 100%;
option {
color: $color-gray-60;
background: $color-white;
font-size: $fs12;
svg {
fill: $color-gray-40;
height: 10px;
width: 10px;
}
.input-text {
left: 0;
position: absolute;
top: -1px;
width: 60%;
}
.input-select {
background-color: transparent;
border: none;
border-bottom: 1px solid $color-gray-40;
color: transparent;
left: 0;
position: absolute;
top: 0;
width: 100%;
option {
color: $color-gray-60;
background: $color-white;
font-size: $fs12;
}
}
.dropdown-button {
position: absolute;
top: 7px;
right: 0;
}
&.input-option {
height: 2rem;
border-bottom: 1px solid #64666A;
width: 100%;
margin-left: 0.25rem;
.input-text {
border: none;
margin: 0;
width: calc(100% - 12px);
height: 100%;
top: auto;
color: #b1b2b5;
}
}
}
}
}
.grid-option-main .editable-select.input-option .input-text {
padding: 0;
padding-top: 0.18rem;
}
.color-th {
background-color: $color-gray-10;
border: 1px solid $color-gray-10;

View file

@ -43,8 +43,8 @@
(mf/defc dropdown
{::mf/wrap-props false}
[props]
(assert (fn? (gobj/get props "on-close")) "missing `on-close` prop")
(assert (boolean? (gobj/get props "show")) "missing `show` prop")
#_(assert (fn? (gobj/get props "on-close")) "missing `on-close` prop")
#_(assert (boolean? (gobj/get props "show")) "missing `show` prop")
(when (gobj/get props "show")
(mf/element dropdown' props)))

View file

@ -0,0 +1,70 @@
;; 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/.
;;
;; This Source Code Form is "Incompatible With Secondary Licenses", as
;; defined by the Mozilla Public License, v. 2.0.
;;
;; Copyright (c) 2020 UXBOX Labs SL
(ns uxbox.main.ui.components.editable-select
(:require
[rumext.alpha :as mf]
[uxbox.common.uuid :as uuid]
[uxbox.common.data :as d]
[uxbox.util.dom :as dom]
[uxbox.main.ui.icons :as i]
[uxbox.main.ui.components.dropdown :refer [dropdown]]))
(mf/defc editable-select [{:keys [value type options class on-change]}]
(let [state (mf/use-state {:id (uuid/next)
:is-open? false
:current-value value})
open-dropdown #(swap! state assoc :is-open? true)
close-dropdown #(swap! state assoc :is-open? false)
select-item (fn [value]
(fn [event]
(swap! state assoc :current-value value)
(when on-change (on-change value))))
as-key-value (fn [item] (if (map? item) [(:value item) (:label item)] [item item]))
labels-map (into {} (->> options (map as-key-value)))
value->label (fn [value] (get labels-map value value))
handle-change-input (fn [event]
(let [value (-> event dom/get-target dom/get-value)
value (or (d/parse-integer value) value)]
(swap! state assoc :current-value value)
(when on-change (on-change value))))]
(mf/use-effect
(mf/deps value)
#(reset! state {:current-value value}))
(mf/use-effect
(mf/deps options)
#(reset! state {:is-open? false
:current-value value}))
[:div.editable-select {:class class}
[:input.input-text {:value (or (-> @state :current-value value->label) "")
:on-change handle-change-input
:type type}]
[:span.dropdown-button {:on-click open-dropdown} i/arrow-down]
[:& dropdown {:show (:is-open? @state)
:on-close close-dropdown}
[:ul.custom-select-dropdown
(for [[index item] (map-indexed vector options)]
(cond
(= :separator item) [:hr {:key (str (:id @state) "-" index)}]
:else (let [[value label] (as-key-value item)]
[:li.checked-element
{:key (str (:id @state) "-" index)
:class (when (= value (-> @state :current-value)) "is-selected")
:on-click (select-item value)}
[:span.check-icon i/tick]
[:span label]])))]]]))

View file

@ -20,17 +20,24 @@
[uxbox.main.ui.workspace.sidebar.options.rows.color-row :refer [color-row]]
[uxbox.main.ui.workspace.sidebar.options.rows.input-row :refer [input-row]]
[uxbox.main.ui.components.select :refer [select]]
[uxbox.main.ui.components.editable-select :refer [editable-select]]
[uxbox.main.ui.components.dropdown :refer [dropdown]]))
(mf/defc advanced-options [{:keys [visible? on-close children]}]
(when visible?
[:*
[:div.focus-overlay {:on-click #(when on-close (do
(dom/stop-propagation %)
(on-close)))}]
[:div.focus-overlay {:on-click #(when on-close
(do
(dom/stop-propagation %)
(on-close)))}]
[:div.advanced-options {}
children]]))
(def ^:private size-options
[{:value :auto :label "Auto"}
:separator
18 12 10 8 6 4 3 2])
(mf/defc layout-options [{:keys [layout default-layout-params on-change on-remove on-save-layout]}]
(let [state (mf/use-state {:show-advanced-options false
:changes {}})
@ -38,42 +45,46 @@
toggle-advanced-options #(swap! state update :show-advanced-options not)
size-options [{:value :auto :label "Auto"}
:separator
18 12 10 8 6 4 3 2]
emit-changes!
(fn [update-fn]
(swap! state update :changes update-fn)
(when on-change (on-change (d/deep-merge layout (-> @state :changes update-fn)))))
emit-changes! (fn [update-fn]
(swap! state update :changes update-fn)
(when on-change (on-change (d/deep-merge layout (-> @state :changes update-fn)))))
handle-toggle-visibility
(fn [event]
(emit-changes! (fn [changes] (update changes :display #(if (nil? %) false (not %))))))
handle-toggle-visibility (fn [event]
(emit-changes! (fn [changes] (update changes :display #(if (nil? %) false (not %))))))
handle-remove-layout
(fn [event]
(when on-remove (on-remove)))
handle-remove-layout (fn [event]
(when on-remove (on-remove)))
handle-change-type
(fn [type]
(let [defaults (type default-layout-params)
keys (keys defaults)
params (->> @state :changes params (select-keys keys) (merge defaults))
to-merge {:type type :params params}]
(emit-changes! #(d/deep-merge % to-merge))))
handle-change-type (fn [type]
(let [defaults (type default-layout-params)
params (merge
defaults
(select-keys (keys defaults) (-> @state :changes params)))
to-merge {:type type :params params}]
(emit-changes! #(d/deep-merge % to-merge))))
handle-change
(fn [& keys]
(fn [value]
(emit-changes! #(assoc-in % keys value))))
handle-change (fn [& keys]
(fn [value]
(emit-changes! #(assoc-in % keys value))))
handle-change-event
(fn [& keys]
(fn [event]
(let [change-fn (apply handle-change keys)]
(-> event dom/get-target dom/get-value parse-integer change-fn))))
handle-change-event (fn [& keys]
(fn [event]
(let [change-fn (apply handle-change keys)]
(-> event dom/get-target dom/get-value parse-integer change-fn))))
handle-use-default
(fn []
(emit-changes! #(hash-map :params ((:type layout) default-layout-params))))
handle-use-default (fn []
(emit-changes! #(hash-map :params ((:type layout) default-layout-params))))
handle-set-as-default (fn []
(let [current-layout (d/deep-merge layout (-> @state :changes))]
(on-save-layout current-layout)))
handle-set-as-default
(fn []
(let [current-layout (d/deep-merge layout (-> @state :changes))]
(on-save-layout current-layout)))
is-default (= (->> @state :changes (d/deep-merge layout) :params)
(->> layout :type default-layout-params))]
@ -97,10 +108,11 @@
:no-validate true
:value (:size params)
:on-change (handle-change-event :params :size)}]]
[:& select {:default-value (:size params)
:class "input-option"
:options size-options
:on-change (handle-change :params :size)}])
[:& editable-select {:value (:size params)
:type (when (number? (:size params)) "number" )
:class "input-option"
:options size-options
:on-change (handle-change :params :size)}])
[:div.grid-option-main-actions
[:button.custom-button {:on-click handle-toggle-visibility} (if display i/eye i/eye-closed)]
@ -117,18 +129,23 @@
(when (= :row type)
[:& input-row {:label "Rows"
:type :editable-select
:options size-options
:value (:size params)
:min 1
:on-change (handle-change :params :size)}])
(when (= :column type)
[:& input-row {:label "Columns"
:type :editable-select
:options size-options
:value (:size params)
:min 1
:on-change (handle-change :params :size)}])
(when (#{:row :column} type)
[:& input-row {:label "Type"
:type :select
:options [{:value :stretch :label "Stretch"}
{:value :left :label "Left"}
{:value :center :label "Center"}
@ -139,6 +156,7 @@
(when (= :row type)
[:& input-row {:label "Height"
:class "pixels"
:min 1
:value (or (:item-height params) "")
:on-change (handle-change :params :item-height)}])
@ -153,9 +171,11 @@
[:& input-row {:label "Gutter"
:class "pixels"
:value (:gutter params)
:min 0
:on-change (handle-change :params :gutter)}]
[:& input-row {:label "Margin"
:class "pixels"
:min 0
:value (:margin params)
:on-change (handle-change :params :margin)}]])

View file

@ -12,21 +12,38 @@
[rumext.alpha :as mf]
[uxbox.common.data :as d]
[uxbox.main.ui.components.select :refer [select]]
[uxbox.main.ui.components.editable-select :refer [editable-select]]
[uxbox.util.dom :as dom]))
(mf/defc input-row [{:keys [label options value class min max on-change]}]
(let [handle-change (fn [value] (when (and (or (not min) (>= value min)) (or (not max) (<= value max)))
(on-change value)))]
[:div.row-flex.input-row
[:span.element-set-subtitle label]
[:div.input-element {:class class}
(if options
[:& select {:default-value value
:class "input-option"
:options options
:on-change on-change}]
(mf/defc input-row [{:keys [label options value class min max on-change type]}]
[:div.row-flex.input-row
[:span.element-set-subtitle label]
[:div.input-element {:class class}
(case type
:select
[:& select {:default-value value
:class "input-option"
:options options
:on-change on-change}]
:editable-select
[:& editable-select {:value value
:class "input-option"
:options options
:type (when (number? value) "number")
:on-change on-change}]
(let [handle-change
(fn [event]
(let [value (-> event dom/get-target dom/get-value d/parse-integer)]
(when (and (not (nil? on-change))
(or (not min) (>= value min))
(or (not max) (<= value max)))
(on-change value))))]
[:input.input-text
{:placeholder label
:type "number"
:on-change #(-> % dom/get-target dom/get-value d/parse-integer handle-change)
:value value}])]]))
:on-change handle-change
:value value}]))
]])

View file

@ -9,10 +9,24 @@
(ns uxbox.util.geom.layout
(:require
[uxbox.util.math :as mth]
[uxbox.util.geom.point :as gpt]))
(def ^:private default-items 12)
(defn calculate-default-item-length [frame-length margin gutter]
(/ (- frame-length (+ margin (- margin gutter)) (* gutter default-items)) default-items))
(defn calculate-size
"Calculates the number of rows/columns given the other layout parameters"
[frame-length item-length margin gutter]
(let [item-length (or item-length (calculate-default-item-length frame-length margin gutter))
frame-length-no-margins (- frame-length (+ margin (- margin gutter)))]
(mth/floor (/ frame-length-no-margins (+ item-length gutter)))))
(defn calculate-column-layout [{:keys [width height x y] :as frame} {:keys [size gutter margin item-width type] :as params}]
(let [parts (/ width size)
(let [size (if (number? size) size (calculate-size width item-width margin gutter))
parts (/ width size)
item-width (or item-width (+ parts (- gutter) (/ gutter size) (- (/ (* margin 2) size))))
item-height height
initial-offset (case type
@ -25,7 +39,7 @@
[size item-width item-height next-x next-y]))
(defn calculate-row-layout [{:keys [width height x y] :as frame} {:keys [size gutter margin item-height type] :as params}]
(let [{:keys [width height x y]} frame
(let [size (if (number? size) size (calculate-size height item-height margin gutter))
parts (/ height size)
item-width width
item-height (or item-height (+ parts (- gutter) (/ gutter size) (- (/ (* margin 2) size))))