mirror of
https://github.com/penpot/penpot.git
synced 2026-07-22 22:17:58 +00:00
wip
This commit is contained in:
parent
217219f492
commit
726afaea25
@ -402,7 +402,8 @@
|
||||
[:map {:title "SetTokenThemeStatus"}
|
||||
[:type [:= :set-token-theme-status]]
|
||||
[:id ::sm/uuid]
|
||||
[:status :boolean]]]
|
||||
[:theme-ids [:set ::sm/uuid]]
|
||||
[:set-ids [:set ::sm/uuid]]]]
|
||||
|
||||
;; TODO deprecate this once everyone uses set-token-theme-status
|
||||
[:set-active-token-themes
|
||||
@ -1050,10 +1051,10 @@
|
||||
(ctob/make-token-theme (merge prev-token-theme attrs)))))))))
|
||||
|
||||
(defmethod process-change :set-token-theme-status
|
||||
[data {:keys [id status]}]
|
||||
[data {:keys [id theme-ids set-ids]}]
|
||||
(let [data' (ctf/ensure-tokens-lib data)]
|
||||
(-> data'
|
||||
(ctf/update-token-status ctos/set-theme-status (ctf/get-tokens-lib data') id status))))
|
||||
(ctf/update-token-status ctos/set-theme-status id theme-ids set-ids))))
|
||||
|
||||
(defmethod process-change :set-active-token-themes
|
||||
[data {:keys [theme-paths]}]
|
||||
|
||||
@ -1022,14 +1022,15 @@
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn set-token-theme-status
|
||||
[changes id status]
|
||||
[changes id theme-ids set-ids]
|
||||
(assert-library! changes)
|
||||
(let [library-data (::library-data (meta changes))
|
||||
token-status (ctf/get-token-status library-data)
|
||||
prev-status (ctos/theme-active? token-status id)]
|
||||
token-status (ctf/get-token-status library-data nil)
|
||||
prev-theme-ids (ctos/get-active-theme-ids token-status)
|
||||
prev-set-ids (ctos/get-active-set-ids token-status)]
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :set-token-theme-status :id id :status status})
|
||||
(update :undo-changes conj {:type :set-token-theme-status :id id :status prev-status})
|
||||
(update :redo-changes conj {:type :set-token-theme-status :id id :theme-ids theme-ids :set-ids set-ids})
|
||||
(update :undo-changes conj {:type :set-token-theme-status :id id :theme-ids prev-theme-ids :set-ids prev-set-ids})
|
||||
(apply-changes-local))))
|
||||
|
||||
(defn set-active-token-themes
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
(:require
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.types.token-status :as ctos]
|
||||
[app.common.types.tokens-lib :as ctob]))
|
||||
[app.common.types.tokens-lib :as ctob]
|
||||
[clojure.set :as set]))
|
||||
|
||||
(defn- generate-update-active-sets
|
||||
"Copy the active sets from the currently active themes and move them
|
||||
@ -52,16 +53,45 @@
|
||||
;; (disj active-token-themes ctob/hidden-theme-path))]
|
||||
;; (pcb/set-active-token-themes changes active-token-themes')))
|
||||
|
||||
(defn generate-activate-token-theme
|
||||
[changes token-status tokens-lib id]
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? id) "expected valid theme id")
|
||||
(if-not (ctos/theme-active? token-status id)
|
||||
(if-let [theme (ctob/get-theme tokens-lib id)]
|
||||
(let [group-themes (into #{} (ctob/get-themes-in-group tokens-lib (:group theme)))
|
||||
active-theme-ids (ctos/get-active-theme-ids token-status)
|
||||
active-theme-ids' (-> (set/difference active-theme-ids group-themes)
|
||||
(conj id))
|
||||
active-set-ids' (ctos/calculate-active-sets active-theme-ids' tokens-lib)]
|
||||
(pcb/set-token-theme-status changes id active-theme-ids' active-set-ids'))
|
||||
changes)
|
||||
changes))
|
||||
|
||||
(defn generate-deactivate-token-theme
|
||||
[changes token-status tokens-lib id]
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? id) "expected valid theme id")
|
||||
(if (ctos/theme-active? token-status id)
|
||||
(let [active-theme-ids' (disj (ctos/get-active-theme-ids token-status) id)
|
||||
active-set-ids' (ctos/calculate-active-sets active-theme-ids' tokens-lib)]
|
||||
(pcb/set-token-theme-status changes id active-theme-ids' active-set-ids'))
|
||||
changes))
|
||||
|
||||
(defn generate-set-token-theme-status
|
||||
"Activate or deactivate a token theme in `token-status`."
|
||||
[changes _ id active?]
|
||||
(pcb/set-token-theme-status changes id (not active?)))
|
||||
[changes token-status tokens-lib id active?]
|
||||
(if active?
|
||||
(generate-activate-token-theme changes token-status tokens-lib id)
|
||||
(generate-deactivate-token-theme changes token-status tokens-lib id)))
|
||||
|
||||
(defn generate-toggle-token-theme
|
||||
"Toggle the active status of a token theme in `token-status`."
|
||||
[changes token-status id]
|
||||
[changes token-status tokens-lib id]
|
||||
(let [active? (ctos/theme-active? token-status id)]
|
||||
(pcb/set-token-theme-status changes id (not active?))))
|
||||
(if active?
|
||||
(generate-deactivate-token-theme changes token-status tokens-lib id)
|
||||
(generate-activate-token-theme changes token-status tokens-lib id))))
|
||||
|
||||
(defn toggle-token-set-group
|
||||
"Toggle a token set group at `group-path` in `tokens-lib` for a `tokens-lib-theme`."
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
(defn get-token-status
|
||||
[file]
|
||||
(-> file (ctf/file-data) (ctf/get-token-status)))
|
||||
(-> file (ctf/file-data) (ctf/get-token-status nil)))
|
||||
|
||||
(defn add-tokens-lib
|
||||
"Ensure the file has a tokens-lib and a token-statusin its data, creating empty ones if not"
|
||||
@ -35,7 +35,8 @@
|
||||
|
||||
(defn update-token-status
|
||||
[file f]
|
||||
(ctf/update-file-data file #(ctf/update-token-status % f)))
|
||||
(let [tokens-lib (get-tokens-lib file)]
|
||||
(ctf/update-file-data file #(ctf/update-token-status % f tokens-lib))))
|
||||
|
||||
(defn sample-file-with-tokens [tokens-lib-fn token-status-fn]
|
||||
(-> (thf/sample-file :file1)
|
||||
|
||||
@ -323,11 +323,12 @@
|
||||
(:tokens-lib file-data))
|
||||
|
||||
(defn get-token-status
|
||||
[file-data]
|
||||
(if (and (some? (:tokens-lib file-data)) (nil? (:token-status file-data)))
|
||||
;; TODO: remove this when we deprecate old-style files without token-status
|
||||
(ctos/make-token-status-from-lib (:tokens-lib file-data))
|
||||
(:token-status file-data)))
|
||||
[file-data tokens-file-data]
|
||||
(let [tokens-file-data (or tokens-file-data file-data)]
|
||||
(if (and (some? (:tokens-lib tokens-file-data)) (nil? (:token-status file-data)))
|
||||
;; TODO: remove this when we deprecate old-style files without token-status
|
||||
(ctos/make-token-status-from-lib (:tokens-lib tokens-file-data))
|
||||
(:token-status file-data))))
|
||||
|
||||
(defn update-tokens-lib
|
||||
"Update the tokens-lib inside file-data through a callback function.
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
(:require
|
||||
#?(:clj [app.common.fressian :as fres])
|
||||
#?(:clj [clojure.data.json :as c.json])
|
||||
[app.common.data :as d]
|
||||
[app.common.schema :as sm]
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.transit :as t]
|
||||
@ -25,6 +26,9 @@
|
||||
(deactivate-theme [_ tokens-lib theme-id] "Deactivate a theme and update active sets")
|
||||
(set-theme-status [_ tokens-lib theme-id status] "Set the activation status of a theme")
|
||||
(theme-active? [_ theme-id] "Check if a theme is active")
|
||||
(get-active-theme-ids [_] "Return a clojure set of active theme ids")
|
||||
(get-active-set-ids [_] "Return a clojure set of active set ids")
|
||||
(active-themes [_ tokens-lib] "Return an ordered sequence of active themes")
|
||||
(active-themes-count [_] "Return the number of active themes")
|
||||
(activate-set [_ set-id] "Add a set to active sets")
|
||||
(deactivate-set [_ set-id] "Remove a set from active sets")
|
||||
@ -45,21 +49,27 @@
|
||||
(c.json/-write (datafy this) writter options))])
|
||||
|
||||
ITokenStatus
|
||||
(get-active-theme-ids [_]
|
||||
active-theme-ids)
|
||||
|
||||
(get-active-set-ids [_]
|
||||
active-set-ids)
|
||||
|
||||
(activate-theme [this tokens-lib theme-id]
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
;; (assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? theme-id) "expected valid theme-id")
|
||||
(if-not (theme-active? this theme-id)
|
||||
(if-let [theme (ctob/get-theme tokens-lib theme-id)]
|
||||
(let [group-themes (ctob/get-themes-in-group tokens-lib (:group theme))
|
||||
(let [group-themes (into #{} (ctob/get-themes-in-group tokens-lib (:group theme)))
|
||||
active-theme-ids' (-> (set/difference active-theme-ids group-themes)
|
||||
(conj theme-id))]
|
||||
(conj theme-id))]
|
||||
(TokenStatus. active-theme-ids'
|
||||
(calculate-active-sets active-theme-ids' tokens-lib)))
|
||||
this)
|
||||
this))
|
||||
|
||||
(deactivate-theme [this tokens-lib theme-id]
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
;; (assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? theme-id) "expected valid theme-id")
|
||||
(if (theme-active? this theme-id)
|
||||
(let [active-theme-ids' (disj active-theme-ids theme-id)]
|
||||
@ -67,18 +77,25 @@
|
||||
(calculate-active-sets active-theme-ids' tokens-lib)))
|
||||
this))
|
||||
|
||||
(set-theme-status [this tokens-lib theme-id status]
|
||||
(assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
(assert (uuid? theme-id) "expected valid theme-id")
|
||||
(assert (boolean? status) "expected boolean status")
|
||||
(if status
|
||||
(activate-theme this tokens-lib theme-id)
|
||||
(deactivate-theme this tokens-lib theme-id)))
|
||||
;; (set-theme-status [this tokens-lib theme-id status]
|
||||
;; (assert (ctob/tokens-lib? tokens-lib) "expected valid tokens-lib")
|
||||
;; (assert (uuid? theme-id) "expected valid theme-id")
|
||||
;; (assert (boolean? status) "expected boolean status")
|
||||
;; (if status
|
||||
;; (activate-theme this tokens-lib theme-id)
|
||||
;; (deactivate-theme this tokens-lib theme-id)))
|
||||
|
||||
(set-theme-status [_ _id theme-ids set-ids]
|
||||
(TokenStatus. theme-ids set-ids))
|
||||
|
||||
(theme-active? [_ theme-id]
|
||||
(assert (uuid? theme-id) "expected valid theme-id")
|
||||
(contains? active-theme-ids theme-id))
|
||||
|
||||
(active-themes [this tokens-lib]
|
||||
(->> (ctob/get-themes tokens-lib)
|
||||
(filter #(theme-active? this (ctob/get-id %)))))
|
||||
|
||||
(active-themes-count [_]
|
||||
(count active-theme-ids))
|
||||
|
||||
@ -103,7 +120,7 @@
|
||||
(active-set-count [_]
|
||||
(count active-set-ids)))
|
||||
|
||||
(defn- calculate-active-sets
|
||||
(defn calculate-active-sets
|
||||
[active-theme-ids tokens-lib]
|
||||
(let [active-themes (map #(ctob/get-theme tokens-lib %) active-theme-ids) ;; OJOOOOOOOOOOOOOOOOOOOOO
|
||||
active-set-names (reduce set/union #{} (map :sets active-themes))
|
||||
@ -162,6 +179,7 @@
|
||||
(ctob/get-active-themes tokens-lib))
|
||||
active-set-ids (into #{}
|
||||
(comp (map #(ctob/get-set-by-name tokens-lib %))
|
||||
(remove nil?)
|
||||
(map ctob/get-id))
|
||||
(ctob/get-active-themes-set-names tokens-lib))]
|
||||
(make-token-status :active-theme-ids active-theme-ids
|
||||
|
||||
@ -755,11 +755,15 @@
|
||||
|
||||
(def ^:private theme-separator "/")
|
||||
|
||||
(defn- join-theme-path [group name]
|
||||
(cpn/join-path [group name] :separator theme-separator :with-spaces? false))
|
||||
(defn- join-theme-path [group name with-spaces?]
|
||||
(let [path (if (and (str/empty? group) with-spaces?) [name] [group name])]
|
||||
(cpn/join-path path :separator theme-separator :with-spaces? with-spaces?)))
|
||||
|
||||
(defn get-theme-path [theme]
|
||||
(join-theme-path (:group theme) (:name theme)))
|
||||
(defn get-theme-path
|
||||
([theme]
|
||||
(get-theme-path theme false))
|
||||
([theme with-spaces?]
|
||||
(join-theme-path (:group theme) (:name theme) with-spaces?)))
|
||||
|
||||
(defn split-theme-path [path]
|
||||
(cpn/split-group-name path
|
||||
@ -767,7 +771,7 @@
|
||||
:with-spaces? false))
|
||||
|
||||
(def hidden-theme-path
|
||||
(join-theme-path hidden-theme-group hidden-theme-name))
|
||||
(join-theme-path hidden-theme-group hidden-theme-name false))
|
||||
|
||||
;; === TokenThemes (collection)
|
||||
|
||||
@ -1179,7 +1183,7 @@ Will return a value that matches this schema:
|
||||
(d/dissoc-in [group name])))
|
||||
(if same-path?
|
||||
active-themes
|
||||
(disj active-themes (join-theme-path group name)))))))
|
||||
(disj active-themes (join-theme-path group name false)))))))
|
||||
this))
|
||||
|
||||
(delete-theme [this id]
|
||||
@ -1188,14 +1192,14 @@ Will return a value that matches this schema:
|
||||
(if theme
|
||||
(TokensLib. sets
|
||||
(d/dissoc-in themes [group name])
|
||||
(disj active-themes (join-theme-path group name)))
|
||||
(disj active-themes (join-theme-path group name false)))
|
||||
this)))
|
||||
|
||||
(get-theme-tree [_]
|
||||
themes)
|
||||
|
||||
(get-theme-tree-no-hidden [_]
|
||||
(dissoc themes hidden-theme-group))
|
||||
(d/dissoc-in themes [hidden-theme-group hidden-theme-name]))
|
||||
|
||||
(get-theme-groups [_]
|
||||
(into [] (comp
|
||||
|
||||
@ -247,6 +247,16 @@
|
||||
theme' (ctob/toggle-set theme nil)]
|
||||
(t/is (= (:sets theme') #{})))))
|
||||
|
||||
(t/deftest get-theme-path
|
||||
(let [theme1 (ctob/make-token-theme :name "theme1")
|
||||
theme2 (ctob/make-token-theme :group "group1" :name "theme2")]
|
||||
(t/is (= "/theme1" (ctob/get-theme-path theme1))) ;; TODO perhaps we should remove the leading /
|
||||
(t/is (= "/theme1" (ctob/get-theme-path theme1 false))) ;; but this may be a breaking change
|
||||
(t/is (= " / theme1" (ctob/get-theme-path theme1 true)))
|
||||
(t/is (= "group1/theme2" (ctob/get-theme-path theme2)))
|
||||
(t/is (= "group1/theme2" (ctob/get-theme-path theme2 false)))
|
||||
(t/is (= "group1 / theme2" (ctob/get-theme-path theme2 true)))))
|
||||
|
||||
(t/deftest make-tokens-lib
|
||||
(let [tokens-lib (ctob/make-tokens-lib)]
|
||||
(t/is (= (ctob/set-count tokens-lib) 0))))
|
||||
|
||||
@ -38,17 +38,23 @@
|
||||
([state file-id]
|
||||
(dm/get-in state [:files file-id :data])))
|
||||
|
||||
(defn lookup-tokens-lib
|
||||
(defn lookup-tokens-file-data
|
||||
[state]
|
||||
(let [current-file-data (lookup-file-data state)
|
||||
tokens-file-id (or (:tokens-file current-file-data) (:id current-file-data))
|
||||
tokens-file-data (lookup-file-data state tokens-file-id)]
|
||||
tokens-file-id (or (:tokens-file current-file-data) (:id current-file-data))]
|
||||
(lookup-file-data state tokens-file-id)))
|
||||
|
||||
(defn lookup-tokens-lib
|
||||
[state]
|
||||
(let [tokens-file-data (lookup-tokens-file-data state)]
|
||||
(ctf/get-tokens-lib tokens-file-data)))
|
||||
|
||||
(defn lookup-token-status
|
||||
[state]
|
||||
(let [current-file-data (lookup-file-data state)]
|
||||
(ctf/get-token-status current-file-data)))
|
||||
(let [current-file-data (lookup-file-data state)
|
||||
tokens-file-id (or (:tokens-file current-file-data) (:id current-file-data))
|
||||
tokens-file-data (lookup-file-data state tokens-file-id)]
|
||||
(ctf/get-token-status current-file-data tokens-file-data)))
|
||||
|
||||
(defn get-page
|
||||
[fdata page-id]
|
||||
|
||||
@ -269,9 +269,10 @@
|
||||
(watch [_ state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
token-status (dsh/lookup-token-status state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-set-token-theme-status token-status id active?))]
|
||||
(clt/generate-set-token-theme-status token-status tokens-lib id active?))]
|
||||
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
@ -281,11 +282,12 @@
|
||||
(ptk/reify ::toggle-token-theme-active
|
||||
ptk/WatchEvent
|
||||
(watch [it state _]
|
||||
(let [data (dsh/lookup-file-data state)
|
||||
(let [data (dsh/lookup-tokens-file-data state)
|
||||
token-status (dsh/lookup-token-status state)
|
||||
tokens-lib (dsh/lookup-tokens-lib state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
(clt/generate-toggle-token-theme token-status id))]
|
||||
(clt/generate-toggle-token-theme token-status tokens-lib id))]
|
||||
(rx/of
|
||||
(dch/commit-changes changes)
|
||||
(dwtp/propagate-workspace-tokens))))))
|
||||
|
||||
@ -66,7 +66,6 @@
|
||||
[:> text* {:as "span" :typography "headline-small" :class (stl/css :group) :id (dm/str (str/kebab group) "-label") :title group} group])
|
||||
[:> themes-list* {:themes themes
|
||||
:token-status token-status
|
||||
;; :active-theme-paths active-theme-paths
|
||||
:on-close on-close
|
||||
:is-grouped true}]])
|
||||
[:li {:class (stl/css :separator)
|
||||
@ -81,22 +80,19 @@
|
||||
(mf/defc theme-selector*
|
||||
[{:keys []}]
|
||||
(let [;; Store
|
||||
tokens-lib (mf/use-ctx ctx/tokens-lib)
|
||||
token-status (mf/use-ctx ctx/token-status)
|
||||
tokens-lib (mf/use-ctx ctx/tokens-lib)
|
||||
token-status (mf/use-ctx ctx/token-status)
|
||||
|
||||
active-themes-count (ctos/active-themes-count token-status)
|
||||
active-theme-paths (-> (ctob/get-active-theme-paths tokens-lib) ;; TODO replace by a call to ctos
|
||||
(disj ctob/hidden-theme-path))
|
||||
active-themes (ctos/active-themes token-status tokens-lib)
|
||||
active-themes-count (count active-themes)
|
||||
|
||||
can-edit? (:can-edit (deref refs/permissions))
|
||||
|
||||
;; Data
|
||||
current-label (cond
|
||||
(> active-themes-count 1) (tr "workspace.tokens.active-themes" active-themes-count)
|
||||
(= active-themes-count 1) (some->> (first active-theme-paths)
|
||||
(ctob/split-theme-path)
|
||||
(remove empty?)
|
||||
(str/join " / "))
|
||||
(= active-themes-count 1) (-> (first active-themes)
|
||||
(ctob/get-theme-path true))
|
||||
:else (tr "workspace.tokens.no-active-theme"))
|
||||
|
||||
;; State
|
||||
@ -148,9 +144,7 @@
|
||||
|
||||
[:& dropdown {:show is-open?
|
||||
:on-close on-close-dropdown}
|
||||
[:> theme-options* {;;:active-theme-paths active-theme-paths
|
||||
;;:themes themes
|
||||
:tokens-lib tokens-lib
|
||||
[:> theme-options* {:tokens-lib tokens-lib
|
||||
:token-status token-status
|
||||
:on-close on-close-dropdown}]]])
|
||||
container))]))
|
||||
|
||||
@ -16,25 +16,27 @@
|
||||
(-> (thf/sample-file :file1)
|
||||
(tht/add-tokens-lib)
|
||||
(tht/update-tokens-lib
|
||||
#(-> %
|
||||
;; Add token sets
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-active)
|
||||
:name "set-active"))
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-inactive)
|
||||
:name "set-inactive"))
|
||||
;; Add themes
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-active)
|
||||
:name "theme-active"
|
||||
:group "group-1"
|
||||
:sets #{"set-active"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-inactive)
|
||||
:name "theme-inactive"
|
||||
:group "group-1"
|
||||
:sets #{"set-inactive"}))))
|
||||
(fn [tokens-lib]
|
||||
(-> tokens-lib
|
||||
;; Add token sets
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-active)
|
||||
:name "set-active"))
|
||||
(ctob/add-set (ctob/make-token-set :id (thi/new-id! :set-inactive)
|
||||
:name "set-inactive"))
|
||||
;; Add themes
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-active)
|
||||
:name "theme-active"
|
||||
:group "group-1"
|
||||
:sets #{"set-active"}))
|
||||
(ctob/add-theme (ctob/make-token-theme :id (thi/new-id! :theme-inactive)
|
||||
:name "theme-inactive"
|
||||
:group "group-1"
|
||||
:sets #{"set-inactive"})))))
|
||||
(tht/update-token-status
|
||||
#(-> %
|
||||
(ctos/activate-theme (thi/id :theme-active))
|
||||
(ctos/activate-set (thi/id :set-active))))))
|
||||
(fn [token-status tokens-lib]
|
||||
(-> token-status
|
||||
(ctos/activate-theme tokens-lib (thi/id :theme-active))
|
||||
(ctos/activate-set (thi/id :set-active)))))))
|
||||
|
||||
(t/deftest test-token-status-active-inactive
|
||||
(t/testing "lookup helpers and active checks"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user