chore(quo): add profile - collectibles list item component (#19125)

This commit is contained in:
Jamie Caprani 2024-03-15 20:58:04 +00:00 committed by GitHub
parent 9da0559b15
commit 219dd7cb46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 556 additions and 13 deletions

View File

@ -2,10 +2,17 @@
(:require
[quo.foundations.colors :as colors]))
(defn- get-dimensions
[size]
(case size
:size-24 24
:size-20 20
nil))
(defn collection-avatar
[theme]
{:width 24
:height 24
[theme size]
{:width (get-dimensions size)
:height (get-dimensions size)
:border-width 1
:border-color (colors/theme-colors colors/neutral-80-opa-10 colors/white-opa-10 theme)
:border-radius 6})

View File

@ -9,10 +9,10 @@
:image - collection image
:theme - keyword -> :light/:dark"
[{:keys [image theme]}]
[{:keys [image theme size] :or {size :size-24}}]
[fast-image/fast-image
{:accessibility-label :collection-avatar
:source image
:style (style/collection-avatar theme)}])
:style (style/collection-avatar theme size)}])
(def view (quo.theme/with-theme view-internal))

View File

@ -11,6 +11,7 @@
[:catn
[:props
[:map {:closed true}
[:container-style {:optional true} [:maybe :map]]
[:value {:optional true} [:maybe [:or :string :int]]]
[:status {:optional true} [:maybe :keyword]]
[:size {:optional true} [:maybe [:enum :size-32 :size-24]]]
@ -19,7 +20,7 @@
:any])
(defn- view-internal
[{:keys [value accessibility-label]
[{:keys [value accessibility-label container-style]
:as props}]
(let [default-props {:status :default
:size :size-32}
@ -27,7 +28,7 @@
[rn/view
{:accessible true
:accessibility-label (or accessibility-label :collectible-counter)
:style (style/container props)}
:style (merge (style/container props) container-style)}
[text/text
{:weight :medium
:size (style/get-text-size props)

View File

@ -76,12 +76,12 @@
:blur? overflow-label blur?}
items preview list items (only 4 items is required for preview)
"
[{:keys [type size number blur?]} items]
[{:keys [type size number blur? container-style]} items]
(let [size-key (if (contains? properties/sizes size) size :size-24)
number (or number (count items))
border-type (properties/border-type type)
margin-left (get-in properties/sizes [size-key :margin-left])]
[rn/view {:style {:flex-direction :row}}
[rn/view {:style (assoc container-style :flex-direction :row)}
(for [index (range (if (> number 4) 3 number))]
^{:key (str index number)}
[list-item

View File

@ -0,0 +1,116 @@
(ns quo.components.profile.collectible-list-item.component-spec
(:require
[quo.components.profile.collectible-list-item.view :as collectible-list-item]
[test-helpers.component :as h]))
(h/describe "Profile/ collectible list item tests"
(h/describe "type card"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders counter and collectible name"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:collectible-name "Doodle #6822"
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-text "Doodle #6822")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :card
:status :unsupported
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500"))
(h/is-truthy (h/get-by-translation-text :t/unsupported-file))))
(h/describe "type image"
(h/test "Renders default and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-called on-press)))
(h/test "Renders loading and on press fires"
(let [on-press (h/mock-fn)]
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :loading
:on-press on-press}])
(h/fire-event :press (h/get-by-label-text :collectible-list-item))
(h/was-not-called on-press)
(h/is-truthy (h/get-by-label-text :gradient-overlay))))
(h/test "Renders counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:counter "x500"}])
(h/is-truthy (h/get-by-text "x500")))
(h/test "Renders status cant-fetch"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :cant-fetch}])
(h/is-truthy (h/get-by-translation-text :t/cant-fetch-info)))
(h/test "Renders status unsupported"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported}])
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))
(h/test "Renders status unsupported and counter"
(h/render-with-theme-provider
[collectible-list-item/view
{:type :image
:status :unsupported
:counter "x500"}])
(h/get-by-text "x500")
(h/is-truthy (h/get-by-translation-text :t/unsupported-file)))))

View File

@ -0,0 +1,90 @@
(ns quo.components.profile.collectible-list-item.style
(:require [quo.foundations.colors :as colors]
[quo.foundations.shadows :as shadows]))
(def container-border-radius 12)
(def card-image-padding-vertical 3)
(def card-image-padding-horizontal 3)
(defn fallback
[{:keys [theme]}]
{:background-color (colors/theme-colors colors/neutral-2_5 colors/neutral-90 theme)
:border-style :dashed
:border-color (colors/theme-colors colors/neutral-20 colors/neutral-80 theme)
:border-width 1
:border-radius container-border-radius
:width "100%"
:aspect-ratio 1
:align-items :center
:justify-content :center})
(def collectible-counter
{:position :absolute
:top 12
:right 12})
(def avatar
{:position :absolute
:bottom 12
:left 12})
(def container
{:flex 1})
(defn card-view-container
[theme]
(merge
{:background-color (colors/theme-colors colors/white colors/neutral-95 theme)
:padding-top card-image-padding-vertical
:padding-left card-image-padding-horizontal
:padding-right card-image-padding-horizontal
:padding-bottom card-image-padding-vertical
:border-radius 14
:border-width 1
:border-color (colors/theme-colors colors/neutral-10 colors/neutral-80 theme)}
(shadows/get 2)))
(def image
{:width "100%"
:flex 1
:border-radius container-border-radius})
(def card-details-container
{:flex-direction :row
:height 27
:margin-top 3
:margin-bottom 2
:align-items :center
:padding-left 8
:padding-right 0
:padding-top 4})
(def card-detail-text
{:flex 1})
(def image-view-container
{:aspect-ratio 1
:border-radius container-border-radius})
(defn loading-square
[theme]
{:height 20
:width 20
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-message
[theme]
{:height 14
:width 72
:margin-left 8
:border-radius 6
:align-self :center
:background-color (colors/theme-colors colors/neutral-5 colors/neutral-90 theme)})
(defn loading-image
[theme]
{:flex 1
:border-radius container-border-radius
:background-color (colors/theme-colors colors/white-70-blur colors/neutral-95-opa-70-blur theme)})

View File

@ -0,0 +1,195 @@
(ns quo.components.profile.collectible-list-item.view
(:require
[quo.components.avatars.collection-avatar.view :as collection-avatar]
[quo.components.counter.collectible-counter.view :as collectible-counter]
[quo.components.icon :as icon]
[quo.components.list-items.preview-list.view :as preview-list]
[quo.components.markdown.text :as quo]
[quo.components.profile.collectible-list-item.style :as style]
[quo.foundations.colors :as colors]
[quo.foundations.gradients :as gradients]
[quo.theme]
[react-native.core :as rn]
[schema.core :as schema]
[utils.i18n :as i18n]))
(defn- fallback-view
[{:keys [label theme type]}]
[rn/view
{:style (style/fallback {:type type
:theme theme})}
[rn/view
[icon/icon :i/sad {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}]]
[rn/view {:style {:height 4}}]
[quo/text
{:size :paragraph-2
:style {:color (colors/theme-colors colors/neutral-40 colors/neutral-50 theme)}}
label]])
(defn- loading-square
[theme]
[rn/view {:style (style/loading-square theme)}])
(defn- loading-message
[theme]
[rn/view {:style (style/loading-message theme)}])
(defn- loading-image
[{:keys [theme gradient-color-index]}]
[gradients/view
{:theme theme
:container-style (style/loading-image theme)
:color-index gradient-color-index}])
(defn- card-details
[{:keys [status community? avatar-image-src collectible-name theme]}]
[rn/view {:style style/card-details-container}
(cond (= :cant-fetch status)
[quo/text
{:size :paragraph-1
:weight :medium
:style {:color (colors/theme-colors colors/neutral-50 colors/neutral-40 theme)}}
(i18n/label :t/unknown)]
(= :loading status)
[rn/view {:style {:flex-direction :row}}
[loading-square theme]
[loading-message theme]]
community?
[:<>
[preview-list/view
{:type :communities
:size :size-20}
[avatar-image-src]]
[rn/view {:style {:width 8}}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:style style/card-detail-text}
collectible-name]]
:else
[:<>
[collection-avatar/view
{:size :size-20
:image avatar-image-src}]
[rn/view {:style {:width 8}}]
[quo/text
{:size :paragraph-1
:weight :semi-bold
:ellipsize-mode :tail
:number-of-lines 1
:style style/card-detail-text}
collectible-name]])])
(defn- card-view
[{:keys [avatar-image-src collectible-name community? counter
gradient-color-index image-src status type]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style (style/card-view-container theme)}
[rn/view {:style {:aspect-ratio 1}}
(cond
(= :loading status)
[loading-image
{:theme theme
:gradient-color-index gradient-color-index}]
(= status :unsupported)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/cant-fetch-info)}]
:else
[rn/view {:style {:aspect-ratio 1}}
[rn/image
{:style style/image
:source image-src}]])]
(when (and (not= status :loading) (not= status :cant-fetch) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
:value counter}])
[card-details
{:status status
:community? community?
:avatar-image-src avatar-image-src
:collectible-name collectible-name
:theme theme}]]))
(defn- image-view
[{:keys [avatar-image-src community? counter
gradient-color-index image-src status]}]
(let [theme (quo.theme/use-theme-value)]
[rn/view {:style style/image-view-container}
(cond
(= :loading status)
[loading-image
{:theme theme
:gradient-color-index gradient-color-index}]
(= status :unsupported)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/unsupported-file)}]
(= status :cant-fetch)
[fallback-view
{:theme theme
:type type
:label (i18n/label :t/cant-fetch-info)}]
:else [rn/view {:style {:aspect-ratio 1}}
[rn/image
{:style style/image
:source image-src}]])
(when (and (not= status :loading) (not= status :cant-fetch) counter)
[collectible-counter/view
{:container-style style/collectible-counter
:size :size-24
:value counter}])
(when (and (not= status :loading) (not= status :cant-fetch) community?)
[preview-list/view
{:container-style style/avatar
:type :communities
:size :size-24}
[avatar-image-src]])]))
(defn- view-internal
[{:keys [container-style type on-press status]
:as props}]
[rn/pressable
{:on-press (when-not (= status :loading) on-press)
:accessibility-label :collectible-list-item
:style (merge container-style style/container)}
(if (= type :card)
[card-view props]
[image-view props])])
(def ?schema
[:=>
[:catn
[:props
[:map {:closed true}
[:avatar-image-src {:optional true} [:maybe :schema.common/image-source]]
[:collectible-name {:optional true} [:maybe string?]]
[:community? {:optional true} [:maybe boolean?]]
[:counter {:optional true} [:maybe string?]]
[:gradient-color-index {:optional true}
[:maybe [:enum :gradient-1 :gradient-2 :gradient-3 :gradient-4 :gradient-5]]]
[:image-src {:optional true} [:maybe :schema.common/image-source]]
[:on-press {:optional true} [:maybe fn?]]
[:status {:optional true} [:maybe [:enum :default :loading :cant-fetch :unsupported]]]
[:type [:enum :card :image]]]]]
:any])
(def view (schema/instrument #'view-internal ?schema))

View File

@ -56,7 +56,7 @@
quo.components.dropdowns.network-dropdown.view
quo.components.empty-state.empty-state.view
quo.components.gradient.gradient-cover.view
[quo.components.graph.interactive-graph.view :as interactive-graph]
quo.components.graph.interactive-graph.view
quo.components.graph.wallet-graph.view
quo.components.header
quo.components.icon
@ -110,6 +110,7 @@
quo.components.onboarding.small-option-card.view
quo.components.overlay.view
quo.components.password.tips.view
quo.components.profile.collectible-list-item.view
quo.components.profile.collectible.view
quo.components.profile.link-card.view
quo.components.profile.profile-card.view
@ -352,6 +353,7 @@
;;;; Profile
(def collectible quo.components.profile.collectible.view/collectible)
(def collectible-list-item quo.components.profile.collectible-list-item.view/view)
(def link-card quo.components.profile.link-card.view/view)
(def profile-card quo.components.profile.profile-card.view/profile-card)
(def select-profile quo.components.profile.select-profile.view/view)

View File

@ -63,6 +63,7 @@
quo.components.numbered-keyboard.keyboard-key.component-spec
quo.components.onboarding.small-option-card.component-spec
quo.components.password.tips.component-spec
quo.components.profile.collectible-list-item.component-spec
quo.components.profile.link-card.component-spec
quo.components.profile.select-profile.component-spec
quo.components.profile.showcase-nav.component-spec

View File

@ -0,0 +1,34 @@
(ns quo.foundations.gradients
(:require
[quo.foundations.colors :as colors]
[quo.theme]
[react-native.linear-gradient :as linear-gradient]))
(defn- gradient-colors
[index theme]
(case index
:gradient-1 [(colors/resolve-color :yellow theme)
(colors/resolve-color :sky theme)
(colors/resolve-color :purple theme)]
:gradient-2 [(colors/resolve-color :orange theme)
(colors/resolve-color :purple theme)
(colors/resolve-color :blue theme)]
:gradient-3 [(colors/resolve-color :blue theme)
(colors/resolve-color :magenta theme)
(colors/resolve-color :yellow theme)]
:gradient-4 [(colors/resolve-color :army theme)
(colors/resolve-color :orange theme)
(colors/resolve-color :blue theme)]
[(colors/resolve-color :purple theme)
(colors/resolve-color :army theme)
(colors/resolve-color :yellow theme)]))
(defn view
[{:keys [color-index container-style] :or {color-index 1}}]
(let [theme (quo.theme/use-theme-value)]
[linear-gradient/linear-gradient
{:style (merge {:border-radius 16} container-style)
:accessibility-label :gradient-overlay
:colors (gradient-colors color-index theme)
:start {:x 0 :y 0}
:end {:x 0 :y 1}}]))

View File

@ -7,7 +7,11 @@
[status-im.contexts.preview.quo.preview :as preview]))
(def descriptor
[{:key :image
[{:key :size
:type :select
:options [{:key :size-24}
{:key :size-20}]}
{:key :image
:type :select
:options [{:key (resources/get-mock-image :bored-ape)
:value "Bored ape"}

View File

@ -0,0 +1,28 @@
(ns status-im.contexts.preview.quo.foundations.gradients
(:require [quo.foundations.gradients :as quo.gradients]
[reagent.core :as reagent]
[status-im.contexts.preview.quo.preview :as preview]))
(def ^:private descriptor
[{:key :color-index
:type :select
:options [{:key :gradient-1}
{:key :gradient-2}
{:key :gradient-3}
{:key :gradient-4}
{:key :gradient-5}]}])
(defn view
[]
(let [state (reagent/atom {:color-index 1})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:blur? (:blur? @state)
:show-blur-background? (:blur? @state)}
[quo.gradients/view
{:container-style {:align-self :center
:height 200
:width 200}
:color-index (:color-index @state)}]])))

View File

@ -68,6 +68,7 @@
[status-im.contexts.preview.quo.dropdowns.network-dropdown :as
network-dropdown]
[status-im.contexts.preview.quo.empty-state.empty-state :as empty-state]
[status-im.contexts.preview.quo.foundations.gradients :as gradients]
[status-im.contexts.preview.quo.foundations.shadows :as shadows]
[status-im.contexts.preview.quo.gradient.gradient-cover :as gradient-cover]
[status-im.contexts.preview.quo.graph.interactive-graph :as
@ -133,6 +134,7 @@
small-option-card]
[status-im.contexts.preview.quo.password.tips :as tips]
[status-im.contexts.preview.quo.profile.collectible :as collectible]
[status-im.contexts.preview.quo.profile.collectible-list-item :as collectible-list-item]
[status-im.contexts.preview.quo.profile.link-card :as link-card]
[status-im.contexts.preview.quo.profile.profile-card :as profile-card]
[status-im.contexts.preview.quo.profile.select-profile :as select-profile]
@ -201,7 +203,9 @@
[utils.re-frame :as rf]))
(def screens-categories
{:foundations [{:name :shadows
{:foundations [{:name :gradients
:component gradients/view}
{:name :shadows
:component shadows/view}]
:animated-list [{:name :animated-header-list
:component animated-header-list/mock-screen}]
@ -414,6 +418,8 @@
:component tips/view}]
:profile [{:name :collectible
:component collectible/view}
{:name :collectible-list-item
:component collectible-list-item/view}
{:name :link-card
:component link-card/view}
{:name :profile-card

View File

@ -0,0 +1,56 @@
(ns status-im.contexts.preview.quo.profile.collectible-list-item
(:require
[quo.core :as quo]
[reagent.core :as reagent]
[status-im.common.resources :as resources]
[status-im.contexts.preview.quo.preview :as preview]))
(defonce test-image (resources/get-mock-image :collectible))
(defonce test-avatar (resources/get-mock-image :monkey))
(def descriptor
[{:key :type
:type :select
:options [{:key :card}
{:key :image}]}
{:key :community?
:type :boolean}
{:key :status
:type :select
:options [{:key :loading}
{:key :default}
{:key :unsupported}
{:key :cant-fetch}]}
{:key :gradient-color-index
:type :select
:options [{:key :gradient-1}
{:key :gradient-2}
{:key :gradient-3}
{:key :gradient-4}
{:key :gradient-5}]}
{:key :counter
:type :text}
{:key :collectible-name
:type :text}])
(defn view
[]
(let [state (reagent/atom {:type :card
:collectible-name "Doodle #6822"
:gradient-color-index :gradient-1
:community? false
:status :loading
:counter ""})]
(fn []
[preview/preview-container
{:state state
:descriptor descriptor
:component-container-style {:padding-vertical 20
:margin-horizontal 95}}
[quo/collectible-list-item
(assoc @state
:counter (when (seq (:counter @state)) (:counter @state))
:gradient-color-index (:gradient-color-index @state)
:image-src test-image
:avatar-image-src test-avatar
:on-press #(js/alert "Pressed"))]])))

View File

@ -2531,5 +2531,8 @@
"goerli-testnet-toggle-confirmation": "Are you sure you want to toggle Goerli? This will log you out and you will have to login again.",
"bridged-to": "Bridged to {{network}}",
"slide-to-bridge": "Slide to bridge",
"provider-is-down": "The provider for the following chain(s) is down: {{chains}}"
"provider-is-down": "The provider for the following chain(s) is down: {{chains}}",
"unknown": "Unknown",
"unsupported-file": "Unsupported file",
"cant-fetch-info": "Can't fetch info"
}