🔧 Unify path name helper functions

This commit is contained in:
Andrés Moya
2025-09-22 12:19:36 +02:00
committed by Andrés Moya
parent 4e607d8da2
commit 194eded930
28 changed files with 288 additions and 297 deletions

View File

@@ -692,129 +692,9 @@
(walk/postwalk process-form data)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SHAPES ORGANIZATION (PATH MANAGEMENT)
;; SHAPES ORGANIZATION
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defn split-path
"Decompose a string in the form 'one / two / three' into
a vector of strings, normalizing spaces."
[path]
(let [xf (comp (map str/trim)
(remove str/empty?))]
(->> (str/split path "/")
(into [] xf))))
(defn join-path
"Regenerate a path as a string, from a vector."
[path-vec]
(str/join " / " path-vec))
(defn join-path-with-dot
"Regenerate a path as a string, from a vector."
[path-vec]
(str/join "\u00A0\u2022\u00A0" path-vec))
(defn clean-path
"Remove empty items from the path."
[path]
(->> (split-path path)
(join-path)))
(defn parse-path-name
"Parse a string in the form 'group / subgroup / name'.
Retrieve the path and the name in separated values, normalizing spaces."
[path-name]
(let [path-name-split (split-path path-name)
path (str/join " / " (butlast path-name-split))
name (or (last path-name-split) "")]
[path name]))
(defn merge-path-item
"Put the item at the end of the path."
[path name]
(if-not (empty? path)
(if-not (empty? name)
(str path " / " name)
path)
name))
(defn merge-path-item-with-dot
"Put the item at the end of the path."
[path name]
(if-not (empty? path)
(if-not (empty? name)
(str path "\u00A0\u2022\u00A0" name)
path)
name))
(defn compact-path
"Separate last item of the path, and truncate the others if too long:
'one' -> ['' 'one' false]
'one / two / three' -> ['one / two' 'three' false]
'one / two / three / four' -> ['one / two / ...' 'four' true]
'one-item-but-very-long / two' -> ['...' 'two' true] "
[path max-length dot?]
(let [path-split (split-path path)
last-item (last path-split)
merge-path (if dot?
merge-path-item-with-dot
merge-path-item)]
(loop [other-items (seq (butlast path-split))
other-path ""]
(if-let [item (first other-items)]
(let [full-path (-> other-path
(merge-path item)
(merge-path last-item))]
(if (> (count full-path) max-length)
[(merge-path other-path "...") last-item true]
(recur (next other-items)
(merge-path other-path item))))
[other-path last-item false]))))
(defn butlast-path
"Remove the last item of the path."
[path]
(let [split (split-path path)]
(if (= 1 (count split))
""
(join-path (butlast split)))))
(defn butlast-path-with-dots
"Remove the last item of the path."
[path]
(let [split (split-path path)]
(if (= 1 (count split))
""
(join-path-with-dot (butlast split)))))
(defn last-path
"Returns the last item of the path."
[path]
(last (split-path path)))
(defn compact-name
"Append the first item of the path and the name."
[path name]
(let [path-split (split-path path)]
(merge-path-item (first path-split) name)))
(defn inside-path? [child parent]
(let [child-path (split-path child)
parent-path (split-path parent)]
(and (<= (count parent-path) (count child-path))
(= parent-path (take (count parent-path) child-path)))))
(defn split-by-last-period
"Splits a string into two parts:
the text before and including the last period,
and the text after the last period."
[s]
(if-let [last-period (str/last-index-of s ".")]
[(subs s 0 (inc last-period)) (subs s (inc last-period))]
[s ""]))
(defn get-frame-objects
"Retrieves a new objects map only with the objects under frame-id (with frame-id)"
[objects frame-id]

View File

@@ -11,6 +11,7 @@
[app.common.exceptions :as ex]
[app.common.files.helpers :as cfh]
[app.common.files.variant :as cfv]
[app.common.path-names :as cpn]
[app.common.schema :as sm]
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctkl]
@@ -511,7 +512,7 @@
(report-error :variant-bad-name
(str/ffmt "Variant % has an invalid name" (:id shape))
shape file page))
(when-not (= (:name parent) (cfh/merge-path-item (:path component) (:name component)))
(when-not (= (:name parent) (cpn/merge-path-item (:path component) (:name component)))
(report-error :variant-component-bad-name
(str/ffmt "Component % has an invalid name" (:id shape))
shape file page))

View File

@@ -17,6 +17,7 @@
[app.common.logging :as log]
[app.common.logic.shapes :as cls]
[app.common.logic.variant-properties :as clvp]
[app.common.path-names :as cpn]
[app.common.spec :as us]
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctkl]
@@ -986,7 +987,7 @@
(defn generate-rename-component
"Generate the changes for rename the component with the given id, in the current file library."
[changes id new-name library-data]
(let [[path name] (cfh/parse-path-name new-name)]
(let [[path name] (cpn/split-group-name new-name)]
(-> changes
(pcb/with-library-data library-data)
(pcb/update-component id #(assoc % :path path :name name)))))
@@ -2235,7 +2236,7 @@
variant-id (when (ctk/is-variant? root) (:parent-id root))
props (when (ctk/is-variant? root) (get variant-props (:component-id root)))
[path name] (cfh/parse-path-name name)
[path name] (cpn/split-group-name name)
[root-shape updated-shapes]
(ctn/convert-shape-in-component root objects file-id)

View File

@@ -24,7 +24,7 @@
(ctob/set-sets active-token-set-names))
(update-theme-fn))]
(-> changes
(pcb/update-active-token-themes #{(ctob/theme-path hidden-theme')})
(pcb/update-active-token-themes #{(ctob/get-theme-path hidden-theme')})
(pcb/set-token-theme (:group hidden-theme)
(:name hidden-theme)
hidden-theme'))))

View File

@@ -7,8 +7,8 @@
(:require
[app.common.data :as d]
[app.common.files.changes-builder :as pcb]
[app.common.files.helpers :as cfh]
[app.common.files.variant :as cfv]
[app.common.path-names :as cpn]
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctcl]
[app.common.types.variant :as ctv]
@@ -127,7 +127,7 @@
(defn- generate-make-shape-no-variant
[changes shape]
(let [new-name (ctv/variant-name-to-name shape)
[cpath cname] (cfh/parse-path-name new-name)]
[cpath cname] (cpn/split-group-name new-name)]
(-> changes
(pcb/update-component (:component-id shape)
#(-> (dissoc % :variant-id :variant-properties)
@@ -146,7 +146,7 @@
(defn- create-new-properties-from-variant
[shape min-props data container-name base-properties]
(let [component (ctcl/get-component data (:component-id shape) true)
component-full-name (cfh/merge-path-item (:path component) (:name component))
component-full-name (cpn/merge-path-item (:path component) (:name component))
add-name? (not= component-full-name container-name)
props (ctv/merge-properties base-properties
(:variant-properties component))
@@ -188,7 +188,7 @@
(map #(assoc % :value "")))
num-base-props (count base-props)
[cpath cname] (cfh/parse-path-name (:name variant-container))
[cpath cname] (cpn/split-group-name (:name variant-container))
container-name (:name variant-container)
create-new-properties

View File

@@ -0,0 +1,134 @@
;; 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.common.path-names
(:require
[cuerdas.core :as str]))
"Functions to manipulate entity names that represent groups with paths,
e.g. 'Group / Subgroup / Name'.
Some naming conventions:
- Path string: the full string with groups and name, e.g. 'Group / Subgroup / Name'.
- Path: a vector of strings with the full path, e.g. ['Group' 'Subgroup' 'Name'].
- Group string: the group part of the path string, e.g. 'Group / Subgroup'.
- Group: a vector of strings with the group part of the path, e.g. ['Group' 'Subgroup'].
- Name: the final name part of the path, e.g. 'Name'."
(defn split-path
"Decompose a path string in the form 'one / two / three' into a vector
of strings, trimming spaces (e.g. ['one' 'two' 'three'])."
[path-str & {:keys [separator] :or {separator "/"}}]
(let [xf (comp (map str/trim)
(remove str/empty?))]
(->> (str/split path-str separator)
(into [] xf))))
(defn join-path
"Regenerate a path as a string, from a vector.
(e.g. ['one' 'two' 'three'] -> 'one / two / three')"
[path & {:keys [separator with-spaces?] :or {separator "/" with-spaces? true}}]
(if with-spaces?
(str/join (str " " separator " ") path)
(str/join separator path)))
(defn split-group-name
"Parse a path string. Retrieve the group and the name in separated values,
normalizing spaces (e.g. 'group / subgroup / name' -> ['group / subgroup' 'name'])."
[path-str & {:keys [separator with-spaces?] :or {separator "/" with-spaces? true}}]
(let [path (split-path path-str :separator separator)
group-str (join-path (butlast path) :separator separator :with-spaces? with-spaces?)
name (or (last path) "")]
[group-str name]))
(defn join-path-with-dot
"Regenerate a path as a string, from a vector."
[path-vec]
(str/join "\u00A0\u2022\u00A0" path-vec))
(defn clean-path
"Remove empty items from the path."
[path]
(->> (split-path path)
(join-path)))
(defn merge-path-item
"Put the item at the end of the path."
[path name]
(if-not (empty? path)
(if-not (empty? name)
(str path " / " name)
path)
name))
(defn merge-path-item-with-dot
"Put the item at the end of the path."
[path name]
(if-not (empty? path)
(if-not (empty? name)
(str path "\u00A0\u2022\u00A0" name)
path)
name))
(defn compact-path
"Separate last item of the path, and truncate the others if too long:
'one' -> ['' 'one' false]
'one / two / three' -> ['one / two' 'three' false]
'one / two / three / four' -> ['one / two / ...' 'four' true]
'one-item-but-very-long / two' -> ['...' 'two' true] "
[path max-length dot?]
(let [path-split (split-path path)
last-item (last path-split)
merge-path (if dot?
merge-path-item-with-dot
merge-path-item)]
(loop [other-items (seq (butlast path-split))
other-path ""]
(if-let [item (first other-items)]
(let [full-path (-> other-path
(merge-path item)
(merge-path last-item))]
(if (> (count full-path) max-length)
[(merge-path other-path "...") last-item true]
(recur (next other-items)
(merge-path other-path item))))
[other-path last-item false]))))
(defn butlast-path
"Remove the last item of the path."
[path]
(let [split (split-path path)]
(if (= 1 (count split))
""
(join-path (butlast split)))))
(defn butlast-path-with-dots
"Remove the last item of the path."
[path]
(let [split (split-path path)]
(if (= 1 (count split))
""
(join-path-with-dot (butlast split)))))
(defn last-path
"Returns the last item of the path."
[path]
(last (split-path path)))
(defn inside-path? [child parent]
(let [child-path (split-path child)
parent-path (split-path parent)]
(and (<= (count parent-path) (count child-path))
(= parent-path (take (count parent-path) child-path)))))
(defn split-by-last-period
"Splits a string into two parts:
the text before and including the last period,
and the text after the last period."
[s]
(if-let [last-period (str/last-index-of s ".")]
[(subs s 0 (inc last-period)) (subs s (inc last-period))]
[s ""]))

View File

@@ -12,6 +12,7 @@
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt]
[app.common.logic.libraries :as cll]
[app.common.path-names :as cpn]
[app.common.test-helpers.files :as thf]
[app.common.test-helpers.ids-map :as thi]
[app.common.test-helpers.shapes :as ths]
@@ -36,7 +37,7 @@
updated-root (first updated-shapes) ; Can't use new-root because it has a new id
[path name] (cfh/parse-path-name (:name updated-root))]
[path name] (cpn/split-group-name (:name updated-root))]
(thi/set-id! label (:component-id updated-root))
(ctf/update-file-data

View File

@@ -11,6 +11,7 @@
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.path-names :as cpn]
[app.common.schema :as sm]
[app.common.schema.generators :as sg]
[app.common.time :as ct]
@@ -24,42 +25,6 @@
[clojure.walk :as walk]
[cuerdas.core :as str]))
;; === Groups handling
;; TODO: add again the removed functions and refactor the rest of the module to use them
(def ^:private xf-map-trim
(comp
(map str/trim)
(remove str/empty?)))
(defn split-path
"Decompose a string in the form 'one.two.three' into a vector of strings, removing spaces."
[path separator]
(->> (str/split path separator)
(into [] xf-map-trim)
(not-empty)))
(defn join-path
"Regenerate a path as a string, from a vector."
[path separator]
(str/join separator path))
(defn split-path-name
"Decompose a string in the form 'one.two.three' into a vector with two elements: first the
path and second the name, removing spaces (e.g. ['one.two' 'three'])."
[path separator]
(let [pathv (split-path path separator)]
[(join-path (butlast pathv) separator)
(last pathv)]))
(defn get-path
"Get the path of object by specified separator (E.g. with '.' separator, the
'group.subgroup.name' -> ['group' 'subgroup'])"
[name separator]
(->> (split-path name separator)
(not-empty)))
;; === Common
(defprotocol INamedItem
@@ -180,7 +145,7 @@
(defn get-token-path
[token]
(get-path (:name token) token-separator))
(cpn/split-path (:name token) :separator token-separator))
(defn group-by-type [tokens]
(let [tokens' (if (or (map? tokens)
@@ -413,26 +378,26 @@
(defn get-set-path
[token-set]
(get-path (get-name token-set) set-separator))
(cpn/split-path (get-name token-set) :separator set-separator))
(defn split-set-name
[name]
(split-path name set-separator))
(cpn/split-path name :separator set-separator))
(defn join-set-path [path]
(join-path path set-separator))
(cpn/join-path path :separator set-separator :with-spaces? false))
(defn normalize-set-name
"Normalize a set name (ensure that there are no extra spaces, like ' group / set' -> 'group/set').
If `relative-to` is provided, the normalized name will preserve the same group prefix as reference name."
([name]
(->> (split-set-name name)
(str/join set-separator)))
(-> (split-set-name name)
(cpn/join-path :separator set-separator :with-spaces? false)))
([name relative-to]
(->> (concat (butlast (split-set-name relative-to))
(split-set-name name))
(str/join set-separator))))
(-> (concat (butlast (split-set-name relative-to))
(split-set-name name))
(cpn/join-path :separator set-separator :with-spaces? false))))
(defn replace-last-path-name
"Replaces the last element in a `path` vector with `name`."
@@ -479,12 +444,15 @@
(-> (set-group-path->set-group-prefixed-path path)
(join-set-path)))
(defn add-set-group-prefix [group-path]
(str set-group-prefix group-path))
(defn- set-name->prefixed-full-path [name-str]
(-> (split-set-name name-str)
(set-full-path->set-prefixed-full-path)))
(defn- get-set-prefixed-path [token-set]
(let [path (get-path (get-name token-set) set-separator)]
(let [path (cpn/split-path (get-name token-set) :separator set-separator)]
(set-full-path->set-prefixed-full-path path)))
(defn tokens-tree
@@ -565,23 +533,6 @@
;; === TokenTheme
(def ^:private theme-separator "/")
(defn join-theme-path [group name]
(join-path [group name] theme-separator))
(defn split-theme-path [path]
(split-path-name path theme-separator))
(def hidden-theme-group
"")
(def hidden-theme-name
"__PENPOT__HIDDEN__TOKEN__THEME__")
(def hidden-theme-path
(join-theme-path hidden-theme-group hidden-theme-name))
(defprotocol ITokenTheme
(set-sets [_ set-names] "set the active token sets")
(enable-set [_ set-name] "enable one set in theme")
@@ -590,10 +541,15 @@
(disable-sets [_ set-names] "disable several sets in theme")
(toggle-set [_ set-name] "toggle a set enabled / disabled in the theme")
(update-set-name [_ prev-set-name set-name] "update set-name when it exists")
(theme-path [_] "get `theme-path` from theme")
(theme-matches-group-name [_ group name] "if a theme matches the given group & name")
(hidden-theme? [_] "if a theme is the (from the user ui) hidden temporary theme"))
(def hidden-theme-group
"")
(def hidden-theme-name
"__PENPOT__HIDDEN__TOKEN__THEME__")
(defrecord TokenTheme [id name group description is-source external-id modified-at sets]
cp/Datafiable
(datafy [this] (into {} this))
@@ -660,9 +616,6 @@
(conj (disj sets prev-set-name) set-name))
this))
(theme-path [_]
(join-theme-path group name))
(theme-matches-group-name [this group name]
(and (= (:group this) group)
(= (:name this) name)))
@@ -758,6 +711,22 @@
(assoc :name hidden-theme-name)
(make-token-theme)))
(def ^:private theme-separator "/")
(defn- join-theme-path [group name]
(cpn/join-path [group name] :separator theme-separator :with-spaces? false))
(defn get-theme-path [theme]
(join-theme-path (:group theme) (:name theme)))
(defn split-theme-path [path]
(cpn/split-group-name path
:separator theme-separator
:with-spaces? false))
(def hidden-theme-path
(join-theme-path hidden-theme-group hidden-theme-name))
;; === TokenThemes (collection)
(defprotocol ITokenThemes
@@ -1205,10 +1174,10 @@ Will return a value that matches this schema:
(activate-theme [this group name]
(if-let [theme (get-theme this group name)]
(let [group-themes (->> (get themes group)
(map (comp theme-path val))
(map (comp get-theme-path val))
(into #{}))
active-themes' (-> (set/difference active-themes group-themes)
(conj (theme-path theme)))]
(conj (get-theme-path theme)))]
(TokensLib. sets
themes
active-themes'))

View File

@@ -7,8 +7,8 @@
(ns app.common.types.variant
(:require
[app.common.data :as d]
[app.common.files.helpers :as cfh]
[app.common.math :as math]
[app.common.path-names :as cpn]
[app.common.schema :as sm]
[cuerdas.core :as str]))
@@ -90,7 +90,7 @@
([path properties]
(path-to-properties path properties 0))
([path properties min-props]
(let [cpath (cfh/split-path path)
(let [cpath (cpn/split-path path)
total-props (max (count cpath) min-props)
assigned (mapv #(assoc % :value (nth cpath %2 "")) properties (range))
;; Add empty strings to the end of cpath to reach the minimum number of properties
@@ -309,4 +309,4 @@
"Transforms a variant-name (its properties values) into a standard name:
the real name of the shape joined by the properties values separated by '/'"
[variant]
(cfh/merge-path-item (:name variant) (str/replace (:variant-name variant) #", " " / ")))
(cpn/merge-path-item (:name variant) (str/replace (:variant-name variant) #", " " / ")))

View File

@@ -1,19 +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 common-tests.pages-helpers-test
(:require
[app.common.files.helpers :as cfh]
[clojure.pprint :refer [pprint]]
[clojure.test :as t]))
(t/deftest parse-path-name
(t/is (= ["foo" "bar"] (cfh/parse-path-name "foo/bar")))
(t/is (= ["" "foo"] (cfh/parse-path-name "foo")))
(t/is (= ["" "foo"] (cfh/parse-path-name "/foo")))
(t/is (= ["" ""] (cfh/parse-path-name "")))
(t/is (= ["" ""] (cfh/parse-path-name nil))))

View File

@@ -0,0 +1,33 @@
;; 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 common-tests.path-names-test
(:require
[app.common.path-names :as cpn]
[clojure.test :as t]))
(t/deftest split-group-name
(t/is (= ["foo" "bar"] (cpn/split-group-name "foo/bar")))
(t/is (= ["" "foo"] (cpn/split-group-name "foo")))
(t/is (= ["" "foo"] (cpn/split-group-name "/foo")))
(t/is (= ["" ""] (cpn/split-group-name "")))
(t/is (= ["" ""] (cpn/split-group-name nil))))
(t/deftest split-and-join-path
(let [name "group/subgroup/name"
path (cpn/split-path name :separator "/")
name' (cpn/join-path path :separator "/" :with-spaces? false)]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))
(t/is (= name' name))))
(t/deftest split-and-join-path-with-spaces
(let [name "group / subgroup / name"
path (cpn/split-path name :separator "/")]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))))

View File

@@ -30,7 +30,7 @@
[common-tests.logic.swap-as-override-test]
[common-tests.logic.token-test]
[common-tests.media-test]
[common-tests.pages-helpers-test]
[common-tests.path-names-test]
[common-tests.record-test]
[common-tests.schema-test]
[common-tests.svg-path-test]
@@ -81,7 +81,7 @@
'common-tests.logic.swap-as-override-test
'common-tests.logic.token-test
'common-tests.media-test
'common-tests.pages-helpers-test
'common-tests.path-names-test
'common-tests.record-test
'common-tests.schema-test
'common-tests.svg-path-test

View File

@@ -11,6 +11,7 @@
#?(:clj [app.common.test-helpers.tokens :as tht])
#?(:clj [clojure.datafy :refer [datafy]])
[app.common.data :as d]
[app.common.path-names :as cpn]
[app.common.test-helpers.ids-map :as thi]
[app.common.time :as ct]
[app.common.transit :as tr]
@@ -872,22 +873,6 @@
(t/is (= (ctob/set-count tokens-lib') 1))
(t/is (= (ctob/theme-count tokens-lib') 2)))))
(t/deftest split-and-join-path
(let [name "group/subgroup/name"
path (ctob/split-path name "/")
name' (ctob/join-path path "/")]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))
(t/is (= name' name))))
(t/deftest split-and-join-path-with-spaces
(let [name "group / subgroup / name"
path (ctob/split-path name "/")]
(t/is (= (first path) "group"))
(t/is (= (second path) "subgroup"))
(t/is (= (nth path 2) "name"))))
(t/deftest add-tokens-in-set
(let [tokens-lib (-> (ctob/make-tokens-lib)
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :test-token-set)

View File

@@ -230,7 +230,7 @@
Uses `font-size-value` to calculate the relative line-height value.
Returns an error for an invalid font-size value."
[line-height-value font-size-value font-size-errors]
(let [missing-references (seq (some ctob/find-token-value-references line-height-value))
(let [missing-references (seq (some cto/find-token-value-references line-height-value))
error
(cond
missing-references

View File

@@ -17,6 +17,7 @@
[app.common.geom.proportions :as gpp]
[app.common.geom.shapes :as gsh]
[app.common.logging :as log]
[app.common.path-names :as cpn]
[app.common.transit :as t]
[app.common.types.component :as ctc]
[app.common.types.fills :as types.fills]
@@ -569,7 +570,7 @@
(when-let [shape-id (d/nilv shape-id (dm/get-in state [:workspace-local :shape-for-rename]))]
(let [shape (dsh/lookup-shape state shape-id)
name (str/trim name)
clean-name (cfh/clean-path name)
clean-name (cpn/clean-path name)
valid? (and (not (str/ends-with? name "/"))
(string? clean-name)
(not (str/blank? clean-name)))
@@ -946,8 +947,8 @@
fdata (dsh/lookup-file-data state file-id)
component (cfv/get-primary-component fdata component-id)
cpath (:path component)
cpath (cfh/split-path cpath)
paths (map (fn [i] (cfh/join-path (take (inc i) cpath)))
cpath (cpn/split-path cpath)
paths (map (fn [i] (cpn/join-path (take (inc i) cpath)))
(range (count cpath)))]
(rx/concat
(rx/from (map #(set-assets-group-open file-id :components % true) paths))

View File

@@ -17,6 +17,7 @@
[app.common.logic.libraries :as cll]
[app.common.logic.shapes :as cls]
[app.common.logic.variants :as clv]
[app.common.path-names :as cpn]
[app.common.time :as ct]
[app.common.types.color :as ctc]
[app.common.types.component :as ctk]
@@ -103,7 +104,7 @@
(defn extract-path-if-missing
[item]
(let [[path name] (cfh/parse-path-name (:name item))]
(let [[path name] (cpn/split-group-name (:name item))]
(if (and
(= (:name item) name)
(contains? item :path))
@@ -145,7 +146,7 @@
(defn- update-color*
[it state color file-id]
(let [data (dsh/lookup-file-data state)
[path name] (cfh/parse-path-name (:name color))
[path name] (cpn/split-group-name (:name color))
color (assoc color :path path :name name)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
@@ -250,7 +251,7 @@
(let [new-name (str/trim new-name)]
(if (str/empty? new-name)
(rx/empty)
(let [[path name] (cfh/parse-path-name new-name)
(let [[path name] (cpn/split-group-name new-name)
data (dsh/lookup-file-data state)
object (get-in data [:media id])
new-object (assoc object :path path :name name)
@@ -327,7 +328,7 @@
(watch [it state _]
(when (and (some? new-name) (not= "" new-name))
(let [data (dsh/lookup-file-data state)
[path name] (cfh/parse-path-name new-name)
[path name] (cpn/split-group-name new-name)
object (get-in data [:typographies id])
new-object (assoc object :path path :name name)]
(do-update-tipography it state new-object file-id))))))
@@ -449,7 +450,7 @@
ptk/WatchEvent
(watch [_ state _]
(let [name (str/trim name)
clean-name (cfh/clean-path name)
clean-name (cpn/clean-path name)
valid? (and (not (str/ends-with? name "/"))
(string? clean-name)
(not (str/blank? clean-name)))

View File

@@ -6,8 +6,8 @@
(ns app.main.data.workspace.tokens.import-export
(:require
[app.common.files.helpers :as cfh]
[app.common.json :as json]
[app.common.path-names :as cpn]
[app.common.types.token :as ctt]
[app.common.types.tokens-lib :as ctob]
[app.config :as cf]
@@ -99,7 +99,7 @@
(defn- drop-parent-directory
[path]
(->> (cfh/split-path path)
(->> (cpn/split-path path)
(rest)
(str/join "/")))

View File

@@ -14,6 +14,7 @@
[app.common.geom.point :as gpt]
[app.common.logic.variant-properties :as clvp]
[app.common.logic.variants :as clv]
[app.common.path-names :as cpn]
[app.common.types.color :as clr]
[app.common.types.component :as ctc]
[app.common.types.components-list :as ctkl]
@@ -374,11 +375,11 @@
(:name main))
;; If there is a prefix, set is as first item of path
cpath (-> name
cfh/split-path
cpn/split-path
(cond->
(seq prefix)
(->> (drop (count prefix))
(cons (cfh/join-path prefix))
(cons (cpn/join-path prefix))
vec)))
name (first cpath)
@@ -522,7 +523,7 @@
objects (-> (dsh/get-page data page-id)
(get :objects))
variant-components (cfv/find-variant-components data objects variant-id)
clean-name (cfh/clean-path name)
clean-name (cpn/clean-path name)
undo-id (js/Symbol)]
(rx/concat
@@ -591,7 +592,7 @@
(let [shapes (mapv #(get objects %) ids)
rect (bounding-rect shapes)
prefix (->> shapes
(mapv #(cfh/split-path (:name %)))
(mapv #(cpn/split-path (:name %)))
(common-prefix))
;; When the common parent is root, add a wrapper
add-wrapper? (empty? prefix)

View File

@@ -9,7 +9,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.path-names :as cpn]
[app.main.constants :refer [max-input-length]]
[app.main.data.event :as ev]
[app.main.data.modal :as modal]
@@ -75,7 +75,7 @@
(mf/use-fn
(mf/deps color file-id)
(fn [attrs]
(let [name (cfh/merge-path-item (:path color) (:name color))
(let [name (cpn/merge-path-item (:path color) (:name color))
color (-> attrs
(assoc :id (:id color))
(assoc :name name))]
@@ -221,7 +221,7 @@
:on-key-down input-key-down
:auto-focus true
:max-length max-input-length
:default-value (cfh/merge-path-item (:path color) (:name color))}]
:default-value (cpn/merge-path-item (:path color) (:name color))}]
[:div {:title (if (= (:name color) default-name)
default-name
@@ -345,7 +345,7 @@
(for [[path-item content] groups]
(when-not (empty? path-item)
[:& colors-group {:file-id file-id
:prefix (cfh/merge-path-item prefix path-item)
:prefix (cpn/merge-path-item prefix path-item)
:key (dm/str "group-" path-item)
:groups content
:open-groups open-groups

View File

@@ -10,6 +10,7 @@
(:require
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.path-names :as cpn]
[app.common.spec :as us]
[app.common.thumbnails :as thc]
[app.common.types.component :as ctk]
@@ -62,7 +63,7 @@
(let [path (if (str/empty? path)
(if reverse? "z" "a")
path)]
(str/lower (cfh/merge-path-item path name))))
(str/lower (cpn/merge-path-item path name))))
(if ^boolean reverse? > <))
:always
@@ -71,30 +72,30 @@
(defn add-group
[asset group-name]
(-> (:path asset)
(cfh/merge-path-item group-name)
(cfh/merge-path-item (:name asset))))
(cpn/merge-path-item group-name)
(cpn/merge-path-item (:name asset))))
(defn rename-group
[asset path last-path]
(-> (:path asset)
(str/slice 0 (count path))
(cfh/split-path)
(cpn/split-path)
butlast
(vec)
(conj last-path)
(cfh/join-path)
(cpn/join-path)
(str (str/slice (:path asset) (count path)))
(cfh/merge-path-item (:name asset))))
(cpn/merge-path-item (:name asset))))
(defn ungroup
[asset path]
(-> (:path asset)
(str/slice 0 (count path))
(cfh/split-path)
(cpn/split-path)
butlast
(cfh/join-path)
(cpn/join-path)
(str (str/slice (:path asset) (count path)))
(cfh/merge-path-item (:name asset))))
(cpn/merge-path-item (:name asset))))
(s/def ::asset-name ::us/not-empty-string)
(s/def ::name-group-form
@@ -282,7 +283,7 @@
(st/emit!
(rename
(:id target-asset)
(cfh/merge-path-item prefix (:name target-asset))))))))
(cpn/merge-path-item prefix (:name target-asset))))))))
(mf/defc component-item-thumbnail*
"Component that renders the thumbnail image or the original SVG."

View File

@@ -9,7 +9,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.path-names :as cpn]
[app.common.types.component :as ctc]
[app.common.types.file :as ctf]
[app.main.data.event :as ev]
@@ -150,8 +150,8 @@
{:class (stl/css-case :cell-name listing-thumbs?
:item-name (not listing-thumbs?)
:editing renaming?)
:value (cfh/merge-path-item (:path component) (:name component))
:tooltip (cfh/merge-path-item (:path component) (:name component))
:value (cpn/merge-path-item (:path component) (:name component))
:tooltip (cpn/merge-path-item (:path component) (:name component))
:display-value (:name component)
:editing renaming?
:disable-dbl-click true
@@ -289,7 +289,7 @@
(when-not (empty? path-item)
[:& components-group {:file-id file-id
:key path-item
:prefix (cfh/merge-path-item prefix path-item)
:prefix (cpn/merge-path-item prefix path-item)
:groups content
:open-groups open-groups
:force-open? force-open?
@@ -457,7 +457,7 @@
(st/emit! (dwu/start-undo-transaction undo-id))
(run! st/emit!
(->> components
(filter #(cfh/inside-path? (:path %) path))
(filter #(cpn/inside-path? (:path %) path))
(map #(dwv/rename-comp-or-variant-and-main
(:id %)
(cmm/rename-group % path last-path)))))
@@ -488,7 +488,7 @@
(st/emit! (dwu/start-undo-transaction undo-id))
(run! st/emit!
(->> components
(filter #(cfh/inside-path? (:path %) path))
(filter #(cpn/inside-path? (:path %) path))
(map #(dwv/rename-comp-or-variant-and-main (:id %) (cmm/ungroup % path)))))
(st/emit! (dwu/commit-undo-transaction undo-id)))))
@@ -498,7 +498,7 @@
(fn [path]
(on-clear-selection)
(let [comps (->> components
(filter #(cfh/inside-path? (:path %) path)))
(filter #(cpn/inside-path? (:path %) path)))
ids (into #{} (map :main-instance-id comps))
page-id (->> comps first :main-instance-page)]

View File

@@ -7,7 +7,7 @@
(ns app.main.ui.workspace.sidebar.assets.groups
(:require-macros [app.main.style :as stl])
(:require
[app.common.files.helpers :as cfh]
[app.common.path-names :as cpn]
[app.common.schema :as sm]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
@@ -25,7 +25,7 @@
(mf/defc asset-group-title
[{:keys [file-id section path group-open? on-rename on-ungroup on-group-combine-variants can-combine?]}]
(when-not (empty? path)
(let [[other-path last-path truncated] (cfh/compact-path path 35 true)
(let [[other-path last-path truncated] (cpn/compact-path path 35 true)
menu-state (mf/use-state cmm/initial-context-menu-state)
on-fold-group
(mf/use-fn
@@ -94,7 +94,7 @@
[assets reverse-sort?]
(when-not (empty? assets)
(reduce (fn [groups {:keys [path] :as asset}]
(let [path (cfh/split-path (or path ""))]
(let [path (cpn/split-path (or path ""))]
(update-in groups
(conj path "")
(fn [group]

View File

@@ -9,7 +9,7 @@
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.path-names :as cpn]
[app.main.data.event :as ev]
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
@@ -212,7 +212,7 @@
(for [[path-item content] groups]
(when-not (empty? path-item)
[:& typographies-group {:file-id file-id
:prefix (cfh/merge-path-item prefix path-item)
:prefix (cpn/merge-path-item prefix path-item)
:key (dm/str "group-" path-item)
:groups content
:open-groups open-groups

View File

@@ -11,6 +11,7 @@
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.files.variant :as cfv]
[app.common.path-names :as cpn]
[app.common.types.component :as ctk]
[app.common.types.components-list :as ctkl]
[app.common.types.file :as ctf]
@@ -556,7 +557,7 @@
:title group-name}
[:span {:class (stl/css :component-group-name)}
(cfh/last-path group-name)]
(cpn/last-path group-name)]
[:> icon* {:class (stl/css :component-group-icon)
:variant "ghost"
@@ -565,7 +566,7 @@
(defn- find-common-path
([components]
(let [paths (map (comp cfh/split-path :path) components)]
(let [paths (map (comp cpn/split-path :path) components)]
(find-common-path paths [] 0)))
([paths path n]
(let [current (nth (first paths) n nil)]
@@ -608,7 +609,7 @@
path (if single?
(:path (first components))
(cfh/join-path (if (not every-same-file?)
(cpn/join-path (if (not every-same-file?)
""
(find-common-path components))))
@@ -636,7 +637,7 @@
vals
(remove #(true? (:deleted %)))
(remove #(cfv/is-secondary-variant? % current-lib-data))
(map #(assoc % :full-name (cfh/merge-path-item-with-dot (:path %) (:name %)))))
(map #(assoc % :full-name (cpn/merge-path-item-with-dot (:path %) (:name %)))))
count-variants (fn [component]
(->> (ctkl/components-seq current-lib-data)
@@ -644,7 +645,7 @@
count))
get-subgroups (fn [path]
(let [split-path (cfh/split-path path)]
(let [split-path (cpn/split-path path)]
(reduce (fn [acc dir]
(conj acc (str (last acc) " / " dir)))
[(first split-path)] (rest split-path))))
@@ -655,7 +656,7 @@
(remove str/empty?)
(remove nil?)
(distinct)
(filter #(= (cfh/butlast-path %) (:path filters))))
(filter #(= (cpn/butlast-path %) (:path filters))))
groups (when-not is-search?
(->> (sort (sequence xform components))
@@ -700,7 +701,7 @@
on-go-back
(mf/use-fn
(mf/deps (:path filters))
#(swap! filters* assoc :path (cfh/butlast-path (:path filters))))
#(swap! filters* assoc :path (cpn/butlast-path (:path filters))))
on-enter-group
(mf/use-fn #(swap! filters* assoc :path %))
@@ -709,7 +710,7 @@
(mf/use-fn
(fn [style]
(swap! filters* assoc :listing-thumbs? (= style "grid"))))
filter-path-with-dots (->> (:path filters) (cfh/split-path) (cfh/join-path-with-dot))]
filter-path-with-dots (->> (:path filters) (cpn/split-path) (cpn/join-path-with-dot))]
[:div {:class (stl/css :component-swap)}
[:div {:class (stl/css :element-set-title)}
@@ -918,7 +919,7 @@
menu-entries (cmm/generate-components-menu-entries shapes {:for-design-tab? true})
show-menu? (seq menu-entries)
path (->> component (:path) (cfh/split-path) (cfh/join-path-with-dot))]
path (->> component (:path) (cpn/split-path) (cpn/join-path-with-dot))]
(when (seq shapes)
[:div {:class (stl/css :element-set)}
@@ -979,13 +980,13 @@
[:span {:class (stl/css :component-name-inside)}
(if (and multi (not same-variant?))
(tr "settings.multiple")
(cfh/last-path shape-name))]]
(cpn/last-path shape-name))]]
(when (and can-swap? (or (not multi) same-variant?))
[:div {:class (stl/css :component-parent-name)}
(if (:deleted component)
(tr "workspace.options.component.unlinked")
(cfh/merge-path-item-with-dot path (:name component)))])]]
(cpn/merge-path-item-with-dot path (:name component)))])]]
(when show-menu?
[:div {:class (stl/css :component-actions)}
@@ -1208,7 +1209,7 @@
[:span {:class (stl/css :component-name-inside)}
(if multi?
(tr "settings.multiple")
(cfh/last-path shape-name))]]]]
(cpn/last-path shape-name))]]]]
(when-not multi?
[:div {:class (stl/css :component-actions)}

View File

@@ -10,8 +10,8 @@
[app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.files.helpers :as cfh]
[app.common.files.tokens :as cft]
[app.common.path-names :as cpn]
[app.common.types.token :as ctt]
[app.main.data.workspace.tokens.application :as dwta]
[app.main.data.workspace.tokens.color :as dwtc]
@@ -306,7 +306,7 @@
:class (stl/css :token-pill-icon)}])
(if contains-path?
(let [[first-part last-part] (cfh/split-by-last-period name)]
(let [[first-part last-part] (cpn/split-by-last-period name)]
[:span {:class (stl/css :divided-name-wrapper)
:aria-label name}
[:span {:class (stl/css :first-name-wrapper)} first-part]

View File

@@ -106,7 +106,7 @@
[:> text* {:as "span" :typography "body-medium" :class (stl/css :group-title-name)} group]]])
[:ul {:class (stl/css :theme-group-rows-wrapper)}
(for [[_ {:keys [group name] :as theme}] themes
:let [theme-id (ctob/theme-path theme)
:let [theme-id (ctob/get-theme-path theme)
selected? (some? (get active-theme-ids theme-id))
delete-theme
(fn [e]

View File

@@ -27,7 +27,7 @@
(when (seq themes)
[:ul {:class (stl/css :theme-options)}
(for [[_ {:keys [group name] :as theme}] themes
:let [theme-id (ctob/theme-path theme)
:let [theme-id (ctob/get-theme-path theme)
selected? (get active-theme-paths theme-id)
select-theme (fn [e]
(dom/stop-propagation e)

View File

@@ -11,6 +11,7 @@
[app.common.files.helpers :as cfh]
[app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh]
[app.common.path-names :as cpn]
[app.common.record :as crc]
[app.common.schema :as sm]
[app.common.spec :as us]
@@ -200,7 +201,7 @@
:set
(fn [self value]
(let [id (obj/get self "$id")
value (when (string? value) (-> value str/trim cfh/clean-path))
value (when (string? value) (-> value str/trim cpn/clean-path))
valid? (and (some? value)
(not (str/ends-with? value "/"))
(not (str/blank? value)))]