Refactor Quo preview (#16996)

Improvements to quo previews:

- Change quo-preview.preview code to be more aligned with our guidelines.
- Remove duplication when setting up preview screens in quo-preview.main. Now we
  only need to specify the :name and :component keys and fallback to a good
  default for "{:options {:topBar {:visible true}}".
- Auto-generate descriptor labels based on the key.
- Fix form field colors for dark & light, especially for Android.
- Redesigned form fields to look nicer 💄
- Create component that abstracts away the code for rendering the form fields
  and the preview area. This will aid us in creating more consistent looking
  preview screens and keep things DRY.

How do we use the new code?

Just as before, define a state binding and use it to build up the arguments of
the component. Then, use the preview/preview-container to wrap the component.
You can use certain props to control how the preview is styled, etc, but that's
about it.

    (def descriptor
      [{:type :text :key :label}
       {:key     :chevron-position
        :type    :select
        :options [{:key :left}
                  {:key :right}]}])
    
    (defn view
      []
      (let [state (reagent/atom {:chevron-position :left
                                 :label            "Welcome"})]
        (fn []
          [preview/preview-container {:state state :descriptor descriptor}
           [quo/divider-label @state]])))
This commit is contained in:
Icaro Motta 2023-08-16 11:30:21 +00:00 committed by GitHub
parent d988296ecf
commit b0f748cb73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 536 additions and 647 deletions

View File

@ -1,48 +1,26 @@
(ns status-im2.contexts.quo-preview.colors.color-picker (ns status-im2.contexts.quo-preview.colors.color-picker
(:require [quo2.core :as quo] (:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.blur :as blur]
[react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview])) [status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor (def descriptor
[{:label "Color:" [{:key :selected
:key :color
:type :select :type :select
:options (map (fn [color] :options (map (fn [color]
(let [k (get color :name)] (let [k (get color :name)]
{:key k :value k})) {:key k :value k}))
(quo/picker-colors))} (quo/picker-colors))}
{:label "Blur?" {:key :blur?
:key :blur :type :boolean}])
:type :boolean}])
(defn cool-preview (defn view
[] []
(let [state (reagent/atom {:color "orange" :blur false}) (let [state (reagent/atom {:selected :orange
blur (reagent/cursor state [:blur]) :blur? false})]
color (reagent/cursor state [:color])]
(fn [] (fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} [preview/preview-container
[rn/view {:padding-bottom 150} {:state state
[preview/customizer state descriptor] :descriptor descriptor
[(if @blur blur/view :<>) :blur? (:blur? @state)
[rn/view {:padding-vertical 60 :align-items :center} :show-blur-background? true}
[quo/color-picker [quo/color-picker (assoc @state :on-change #(swap! state assoc :selected %))]])))
{:blur? @blur
:selected @color
:on-change #(reset! color %)}]]]]])))
(defn preview-color-picker
[]
[rn/view
{:background-color (colors/theme-colors
colors/white
colors/neutral-95)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -1,54 +1,29 @@
(ns status-im2.contexts.quo-preview.dividers.divider-label (ns status-im2.contexts.quo-preview.dividers.divider-label
(:require [quo2.components.dividers.divider-label :as divider-label] (:require [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.contexts.quo-preview.preview :as preview])) [status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor (def descriptor
[{:label "Label:" [{:type :text :key :label}
:key :label {:type :text :key :counter-value}
:type :text} {:type :boolean :key :increase-padding-top?}
{:label "Chevron position:" {:type :boolean :key :blur?}
:key :chevron-position {:key :chevron-position
:type :select :type :select
:options [{:key :left :options [{:key :left}
:value "Left"} {:key :right}]}])
{:key :right
:value "Right"}]}
{:label "Counter value:"
:key :counter-value
:type :text}
{:label "Increase padding top:"
:key :increase-padding-top?
:type :boolean}
{:label "Blur:"
:key :blur?
:type :boolean}])
(defn cool-preview (defn view
[] []
(let [state (reagent/atom {:label "Welcome" (let [state (reagent/atom {:blur? false
:chevron-position :left :chevron-position :left
:counter-value 0 :counter-value "0"
:increase-padding-top? true :increase-padding-top? true
:blur? false})] :label "Welcome"})]
(fn [] (fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} [preview/preview-container
[rn/view {:padding-bottom 150} {:state state
[preview/customizer state descriptor] :descriptor descriptor
[rn/view {:padding-vertical 60} :blur? (:blur? @state)
[divider-label/divider-label @state]]]]))) :show-blur-background? true}
[quo/divider-label @state]])))
(defn preview-divider-label
[]
[rn/view
{:background-color (colors/theme-colors
colors/white
colors/neutral-90)
:flex 1}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -1,100 +1,56 @@
(ns status-im2.contexts.quo-preview.links.link-preview (ns status-im2.contexts.quo-preview.links.link-preview
(:require [clojure.string :as string] (:require [quo2.core :as quo]
[quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.resources :as resources] [status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview] [status-im2.contexts.quo-preview.preview :as preview]))
utils.number))
(def descriptor (def descriptor
[{:label "Title" [{:type :text :key :title}
:key :title {:type :text :key :description}
:type :text} {:type :text :key :link}
{:label "Description" {:type :number :key :width}
:key :description {:type :boolean :key :with-logo?}
:type :text} {:type :boolean :key :with-description?}
{:label "Link" {:type :boolean :key :with-thumbnail?}
:key :link {:type :text :key :disabled-text}
:type :text} {:type :boolean :key :enabled?}
{:label "Container width" {:key :thumbnail
:key :width
:type :text}
{:label "With logo?"
:key :with-logo?
:type :boolean}
{:label "With description?"
:key :with-description?
:type :boolean}
{:label "With thumbnail?"
:key :with-thumbnail?
:type :boolean}
{:label "Disabled text"
:key :disabled-text
:type :text}
{:label "Enabled?"
:key :enabled?
:type :boolean}
{:label "Thumbnail"
:key :thumbnail
:type :select :type :select
:options (mapv (fn [k] :options (mapv (fn [k] {:key k})
{:key k
:value (string/capitalize (name k))})
(keys resources/mock-images))} (keys resources/mock-images))}
{:label "Thumbnail size" {:key :thumbnail-size
:key :thumbnail-size
:type :select :type :select
:options [{:key :normal :options [{:key :normal}
:value :normal} {:key :large}]}])
{:key :large
:value :large}]}])
(defn cool-preview (defn view
[] []
(let [state (reagent/atom (let [state (reagent/atom
{:title "Rarible - NFT Marketplace" {:description "Turn your products or services into publicly tradeable items"
:description "Turn your products or services into publicly tradeable items" :disabled-text "Enable Preview"
:enabled? true
:link "rarible.com" :link "rarible.com"
:thumbnail :collectible :thumbnail :collectible
:width "295"
:with-logo? true
:with-thumbnail? true
:with-description? true
:enabled? true
:thumbnail-size :normal :thumbnail-size :normal
:disabled-text "Enable Preview"})] :title "Rarible - NFT Marketplace"
:width 295
:with-description? true
:with-logo? true
:with-thumbnail? true})]
(fn [] (fn []
(let [width (utils.number/parse-int (:width @state) 295) (let [thumbnail (get resources/mock-images (:thumbnail @state))]
thumbnail (get resources/mock-images (:thumbnail @state))] [preview/preview-container {:state state :descriptor descriptor}
[rn/view {:style {:margin-bottom 20}} [quo/link-preview
[preview/customizer state descriptor] {:logo (when (:with-logo? @state)
[rn/view (resources/get-mock-image :status-logo))
{:style {:align-items :center :title (:title @state)
:margin-top 20}} :description (when (:with-description? @state)
[quo/link-preview (:description @state))
{:logo (when (:with-logo? @state) :enabled? (:enabled? @state)
(resources/get-mock-image :status-logo)) :on-enable #(js/alert "Button pressed")
:title (:title @state) :disabled-text (:disabled-text @state)
:description (when (:with-description? @state) :link (:link @state)
(:description @state)) :thumbnail (when (:with-thumbnail? @state)
:enabled? (:enabled? @state) thumbnail)
:on-enable #(js/alert "Button pressed") :thumbnail-size (:thumbnail-size @state)
:disabled-text (:disabled-text @state) :container-style {:width (:width @state)}}]]))))
:link (:link @state)
:thumbnail (when (:with-thumbnail? @state)
thumbnail)
:thumbnail-size (:thumbnail-size @state)
:container-style {:width width}}]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -1,30 +1,18 @@
(ns status-im2.contexts.quo-preview.links.url-preview (ns status-im2.contexts.quo-preview.links.url-preview
(:require (:require
[quo2.core :as quo] [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.resources :as resources] [status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview])) [status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor (def descriptor
[{:label "Title" [{:type :text :key :title}
:key :title {:type :text :key :body}
:type :text} {:type :boolean :key :with-logo?}
{:label "Body" {:type :boolean :key :loading?}
:key :body {:type :text :key :loading-message}])
:type :text}
{:label "With logo?"
:key :with-logo?
:type :boolean}
{:label "Loading?"
:key :loading?
:type :boolean}
{:label "Loading message"
:key :loading-message
:type :text}])
(defn cool-preview (defn view
[] []
(let [state (reagent/atom (let [state (reagent/atom
{:title "Status - Private, Secure Communication" {:title "Status - Private, Secure Communication"
@ -33,29 +21,12 @@
:loading? false :loading? false
:loading-message "Generating preview"})] :loading-message "Generating preview"})]
(fn [] (fn []
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} [preview/preview-container {:state state :descriptor descriptor}
[rn/view {:style {:padding-bottom 150}} [quo/url-preview
[preview/customizer state descriptor] {:title (:title @state)
[rn/view :body (:body @state)
{:style {:align-items :center :logo (when (:with-logo? @state)
:padding-horizontal 16 (resources/get-mock-image :status-logo))
:margin-top 50}} :loading? (:loading? @state)
[quo/url-preview :loading-message (:loading-message @state)
{:title (:title @state) :on-clear #(js/alert "Clear button pressed")}]])))
:body (:body @state)
:logo (when (:with-logo? @state)
(resources/get-mock-image :status-logo))
:loading? (:loading? @state)
:loading-message (:loading-message @state)
:on-clear #(js/alert "Clear button pressed")}]]]])))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -1,50 +1,34 @@
(ns status-im2.contexts.quo-preview.links.url-preview-list (ns status-im2.contexts.quo-preview.links.url-preview-list
(:require (:require
[quo2.core :as quo] [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[react-native.core :as rn] [react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.resources :as resources] [status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.preview :as preview] [status-im2.contexts.quo-preview.preview :as preview]))
utils.number))
(def descriptor (def descriptor
[{:label "Number of previews" [{:type :number :key :previews-length}])
:key :previews-length
:type :text}])
(defn cool-preview (defn view
[] []
(let [state (reagent/atom {:previews-length "3"})] (let [state (reagent/atom {:previews-length 3})
padding 20]
(fn [] (fn []
(let [previews-length (min 6 (utils.number/parse-int (:previews-length @state))) [preview/preview-container
padding 20] {:state state
[rn/view {:style {:padding-bottom 150}} :descriptor descriptor
[preview/customizer state descriptor] :component-container-style {:padding-horizontal 0}}
[rn/view [quo/url-preview-list
{:style {:align-items :center {:horizontal-spacing padding
:margin-top 50}} :preview-width (- (:width (rn/get-window))
[quo/url-preview-list (* 2 padding))
{:horizontal-spacing padding :on-clear #(js/alert "Clear button pressed")
:preview-width (- (:width (rn/get-window)) :key-fn :url
(* 2 padding)) :data (for [index (range (:previews-length @state))
:on-clear #(js/alert "Clear button pressed") :let [index (inc index)]]
:key-fn :url {:title (str "Title " index)
:data (for [index (range previews-length) :body (str "status.im." index)
:let [index (inc index)]] :logo (resources/get-mock-image
{:title (str "Title " index) :status-logo)
:body (str "status.im." index) :loading? false
:logo (resources/get-mock-image :status-logo) :url (str "status.im." index)})}]])))
:loading? false
:url (str "status.im." index)})}]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1}}
[rn/flat-list
{:flex 1
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -2,39 +2,33 @@
(:require [quo2.core :as quo] (:require [quo2.core :as quo]
[quo2.foundations.colors :as colors] [quo2.foundations.colors :as colors]
[quo2.theme :as quo.theme] [quo2.theme :as quo.theme]
[react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.resources :as resources] [status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.community.data :as data] [status-im2.contexts.quo-preview.community.data :as data]
[status-im2.contexts.quo-preview.preview :as preview])) [status-im2.contexts.quo-preview.preview :as preview]))
(def descriptor-type (def descriptor-type
{:label "Type:" {:type :select
:key :type :key :type
:type :select :options [{:key :discover}
:options [{:key :discover :value "Discover"} {:key :engage}
{:key :engage :value "Engage"} {:key :share}]})
{:key :share :value "Share"}]})
(def descriptor-locked (def descriptor-locked
{:label "Locked?" :key :locked? :type :boolean}) {:type :boolean :key :locked?})
(def descriptor-unread-count (def descriptor-unread-count
{:label "Unread count:" :key :unread-count :type :number}) {:type :number :key :unread-count})
(def descriptor-title (def descriptor-title
{:label "Title:" :key :title :type :text}) {:type :text :key :title})
(def descriptor-blur (def descriptor-blur
{:label "Blur?" :key :blur? :type :boolean}) {:type :boolean :key :blur?})
(def descriptor-member-stats (def descriptor-member-stats
[{:label "Total member count:" [{:type :number :key :members-count}
:key :members-count {:type :number :key :active-count}])
:type :number}
{:label "Active member count:"
:key :active-count
:type :number}])
(def descriptors-base (def descriptors-base
[descriptor-type [descriptor-type
@ -43,29 +37,27 @@
(def descriptors-type-discover (def descriptors-type-discover
(conj descriptors-base (conj descriptors-base
{:label "Info:" {:type :select
:key :info :key :info
:type :select :options [{:key :token-gated}
:options [{:key :token-gated :value "Token gated"} {:key :default}]}
{:key :default :value "Default"}]}
{:label "Member stats?" {:label "Member stats?"
:key :members? :type :boolean
:type :boolean})) :key :members?}))
(def descriptors-type-engage (def descriptors-type-engage
(conj descriptors-base (conj descriptors-base
{:label "Info:" {:type :select
:key :info :key :info
:type :select :options [{:key :notification}
:options [{:key :notification :value "Notification"} {:key :mention}
{:key :mention :value "Mention"} {:key :muted}
{:key :muted :value "Muted"} {:key :token-gated}
{:key :token-gated :value "Token gated"} {:key :navigation}
{:key :navigation :value "Navigation"} {:key :default}]}))
{:key :default :value "Default"}]}))
(def descriptors-type-share (def descriptors-type-share
(conj descriptors-base {:label "Subtitle:" :key :subtitle :type :text})) (conj descriptors-base {:type :text :key :subtitle}))
(defn descriptors (defn descriptors
[{:keys [members? info] :as state}] [{:keys [members? info] :as state}]
@ -88,7 +80,7 @@
(into [descriptor-blur] descs) (into [descriptor-blur] descs)
descs))) descs)))
(defn cool-preview (defn view
[] []
(let [state (reagent/atom {:blur? false (let [state (reagent/atom {:blur? false
:customization-color :blue :customization-color :blue
@ -103,30 +95,16 @@
:unread-count 5})] :unread-count 5})]
(fn [] (fn []
(let [customization-color (colors/custom-color-by-theme (:customization-color @state) 50 60)] (let [customization-color (colors/custom-color-by-theme (:customization-color @state) 50 60)]
[rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} [preview/preview-container {:state state :descriptor (descriptors @state)}
[rn/view {:style {:margin-bottom 20}} [quo/community-list-item
[preview/customizer state (descriptors @state)] (merge @state
[rn/view {:style {:margin-vertical 30 :align-items :center}} {:container-style {:width 335}
[quo/community-list-item :logo (resources/get-mock-image :status-logo)
(merge @state :tokens (:tokens data/community)
{:container-style {:width 335} :customization-color customization-color
:logo (resources/get-mock-image :status-logo) :on-press #(js/alert "List item pressed")
:tokens (:tokens data/community) :on-long-press #(js/alert "Long pressed item")
:customization-color customization-color :on-press-info #(js/alert "Info pressed")
:on-press #(js/alert "List item pressed") :members (when (:members? @state)
:on-long-press #(js/alert "Long pressed item") {:members-count (:members-count @state)
:on-press-info #(js/alert "Info pressed") :active-count (:active-count @state)})})]]))))
:members (when (:members? @state)
{:members-count (:members-count @state)
:active-count (:active-count @state)})})]]]]))))
(defn preview
[]
[rn/view
{:style {:background-color (colors/theme-colors colors/neutral-5 colors/neutral-95)
:flex 1}}
[rn/flat-list
{:style {:flex 1}
:keyboard-should-persist-taps :always
:header [cool-preview]
:key-fn str}]])

View File

@ -2,9 +2,9 @@
(:refer-clojure :exclude [filter]) (:refer-clojure :exclude [filter])
(:require (:require
[quo2.core :as quo] [quo2.core :as quo]
[quo2.foundations.colors :as colors]
[reagent.core :as reagent] [reagent.core :as reagent]
[react-native.core :as rn] [react-native.core :as rn]
[status-im2.contexts.quo-preview.style :as style]
[status-im2.common.theme.core :as theme] [status-im2.common.theme.core :as theme]
[status-im2.contexts.quo-preview.animated-header-list.animated-header-list :as animated-header-list] [status-im2.contexts.quo-preview.animated-header-list.animated-header-list :as animated-header-list]
[status-im2.contexts.quo-preview.avatars.account-avatar :as account-avatar] [status-im2.contexts.quo-preview.avatars.account-avatar :as account-avatar]
@ -120,344 +120,233 @@
(def screens-categories (def screens-categories
{:foundations [{:name :shadows {:foundations [{:name :shadows
:options {:topBar {:visible true}}
:component shadows/preview-shadows}] :component shadows/preview-shadows}]
:animated-list [{:name :animated-header-list :animated-list [{:name :animated-header-list
:options {:topBar {:visible false}}
:component animated-header-list/mock-screen}] :component animated-header-list/mock-screen}]
:avatar [{:name :group-avatar :avatar [{:name :group-avatar
:options {:topBar {:visible true}}
:component group-avatar/preview-group-avatar} :component group-avatar/preview-group-avatar}
{:name :icon-avatar {:name :icon-avatar
:options {:topBar {:visible true}}
:component icon-avatar/preview-icon-avatar} :component icon-avatar/preview-icon-avatar}
{:name :user-avatar {:name :user-avatar
:options {:topBar {:visible true}}
:component user-avatar/preview-user-avatar} :component user-avatar/preview-user-avatar}
{:name :wallet-user-avatar {:name :wallet-user-avatar
:options {:topBar {:visible true}}
:component wallet-user-avatar/preview-wallet-user-avatar} :component wallet-user-avatar/preview-wallet-user-avatar}
{:name :channel-avatar {:name :channel-avatar
:options {:topBar {:visible true}}
:component channel-avatar/preview-channel-avatar} :component channel-avatar/preview-channel-avatar}
{:name :account-avatar {:name :account-avatar
:options {:topBar {:visible true}}
:component account-avatar/preview-account-avatar}] :component account-avatar/preview-account-avatar}]
:banner [{:name :banner :banner [{:name :banner
:options {:topBar {:visible true}}
:component banner/preview-banner}] :component banner/preview-banner}]
:buttons [{:name :button :buttons [{:name :button
:options {:topBar {:visible true}}
:component button/preview-button} :component button/preview-button}
{:name :composer-button {:name :composer-button
:options {:topBar {:visible true}}
:component composer-button/preview-composer-button} :component composer-button/preview-composer-button}
{:name :dynamic-button {:name :dynamic-button
:options {:topBar {:visible true}}
:component dynamic-button/preview-dynamic-button} :component dynamic-button/preview-dynamic-button}
{:name :slide-button {:name :slide-button
:options {:topBar {:visible true}}
:component slide-button/preview-slide-button} :component slide-button/preview-slide-button}
{:name :predictive-keyboard {:name :predictive-keyboard
:options {:topBar {:visible true}}
:component predictive-keyboard/preview-predictive-keyboard}] :component predictive-keyboard/preview-predictive-keyboard}]
:browser [{:name :browser-input :browser [{:name :browser-input
:options {:topBar {:visible false}}
:component browser-input/preview-browser-input}] :component browser-input/preview-browser-input}]
:calendar [{:name :calendar :calendar [{:name :calendar
:options {:topBar {:visible true}}
:component calendar/preview-calendar} :component calendar/preview-calendar}
{:name :calendar-day {:name :calendar-day
:options {:topBar {:visible true}}
:component calendar-day/preview-calendar-day} :component calendar-day/preview-calendar-day}
{:name :calendar-year {:name :calendar-year
:options {:topBar {:visible true}}
:component calendar-year/preview-calendar-year}] :component calendar-year/preview-calendar-year}]
:code [{:name :snippet :code [{:name :snippet
:options {:topBar {:visible true}}
:component code-snippet/preview-code-snippet}] :component code-snippet/preview-code-snippet}]
:colors [{:name :color-picker :colors [{:name :color-picker
:options {:topBar {:visible true}} :component color-picker/view}]
:component color-picker/preview-color-picker}]
:community [{:name :community-card-view :community [{:name :community-card-view
:options {:topBar {:visible true}}
:component community-card/preview-community-card} :component community-card/preview-community-card}
{:name :community-membership-list-view {:name :community-membership-list-view
:options {:topBar {:visible true}}
:component community-membership-list-view/preview-community-list-view} :component community-membership-list-view/preview-community-list-view}
{:name :discover-card {:name :discover-card
:options {:topBar {:visible true}}
:component discover-card/preview-discoverd-card} :component discover-card/preview-discoverd-card}
{:name :token-gating {:name :token-gating
:options {:insets {:bottom? true} :options {:insets {:bottom? true}}
:topBar {:visible true}}
:component token-gating/preview-token-gating} :component token-gating/preview-token-gating}
{:name :channel-actions {:name :channel-actions
:options {:insets {:bottom? true} :options {:insets {:bottom? true}}
:topBar {:visible true}}
:component channel-actions/preview-channel-actions}] :component channel-actions/preview-channel-actions}]
:counter [{:name :counter :counter [{:name :counter
:options {:topBar {:visible true}}
:component counter/preview-counter} :component counter/preview-counter}
{:name :step {:name :step
:options {:topBar {:visible true}}
:component step/preview-step}] :component step/preview-step}]
:dividers [{:name :divider-label :dividers [{:name :divider-label
:options {:topBar {:visible true}} :component divider-label/view}
:component divider-label/preview-divider-label}
{:name :new-messages {:name :new-messages
:options {:topBar {:visible true}}
:component new-messages/preview-new-messages} :component new-messages/preview-new-messages}
{:name :divider-date {:name :divider-date
:options {:topBar {:visible true}}
:component divider-date/preview-divider-date} :component divider-date/preview-divider-date}
{:name :strength-divider {:name :strength-divider
:options {:topBar {:visible true}}
:component strength-divider/preview-strength-divider}] :component strength-divider/preview-strength-divider}]
:drawers [{:name :action-drawers :drawers [{:name :action-drawers
:options {:topBar {:visible true}}
:component action-drawers/preview-action-drawers} :component action-drawers/preview-action-drawers}
{:name :documentation-drawer {:name :documentation-drawer
:options {:topBar {:visible true}}
:component documenation-drawers/preview-documenation-drawers} :component documenation-drawers/preview-documenation-drawers}
{:name :drawer-buttons {:name :drawer-buttons
:options {:topBar {:visible true}}
:component drawer-buttons/preview-drawer-buttons} :component drawer-buttons/preview-drawer-buttons}
{:name :permission-drawers {:name :permission-drawers
:options {:topBar {:visible true}}
:component permission-drawers/preview-permission-drawers}] :component permission-drawers/preview-permission-drawers}]
:dropdowns [{:name :dropdown :dropdowns [{:name :dropdown
:options {:topBar {:visible true}}
:component dropdown/preview-dropdown}] :component dropdown/preview-dropdown}]
:empty-state [{:name :empty-state :empty-state [{:name :empty-state
:options {:topBar {:visible true}}
:component empty-state/preview-empty-state}] :component empty-state/preview-empty-state}]
:gradient [{:name :gradient-cover :gradient [{:name :gradient-cover
:options {:topBar {:visible true}}
:component gradient-cover/preview-gradient-cover}] :component gradient-cover/preview-gradient-cover}]
:graph [{:name :wallet-graph :graph [{:name :wallet-graph
:options {:topBar {:visible true}}
:component wallet-graph/preview-wallet-graph}] :component wallet-graph/preview-wallet-graph}]
:info [{:name :info-message :info [{:name :info-message
:options {:topBar {:visible true}}
:component info-message/preview-info-message} :component info-message/preview-info-message}
{:name :information-box {:name :information-box
:options {:topBar {:visible true}}
:component information-box/preview-information-box}] :component information-box/preview-information-box}]
:inputs [{:name :input :inputs [{:name :input
:options {:topBar {:visible true}}
:component input/preview-input} :component input/preview-input}
{:name :locked-input {:name :locked-input
:options {:topBar {:visible true}}
:component locked-input/preview-locked-input} :component locked-input/preview-locked-input}
{:name :profile-input {:name :profile-input
:options {:topBar {:visible true}}
:component profile-input/preview-profile-input} :component profile-input/preview-profile-input}
{:name :recovery-phrase-input {:name :recovery-phrase-input
:options {:topBar {:visible true}}
:component recovery-phrase-input/preview-recovery-phrase-input} :component recovery-phrase-input/preview-recovery-phrase-input}
{:name :search-input {:name :search-input
:options {:topBar {:visible true}}
:component search-input/preview-search-input} :component search-input/preview-search-input}
{:name :title-input {:name :title-input
:options {:topBar {:visible true}}
:component title-input/preview-title-input}] :component title-input/preview-title-input}]
:numbered-keyboard [{:name :keyboard-key :numbered-keyboard [{:name :keyboard-key
:options {:insets {:top? true} :options {:insets {:top? true}}
:topBar {:visible true}}
:component keyboard-key/preview-keyboard-key} :component keyboard-key/preview-keyboard-key}
{:name :numbered-keyboard {:name :numbered-keyboard
:options {:insets {:top? true} :options {:insets {:top? true}}
:topBar {:visible true}}
:component numbered-keyboard/preview-numbered-keyboard}] :component numbered-keyboard/preview-numbered-keyboard}]
:links [{:name :url-preview :links [{:name :url-preview
:options {:insets {:top? true} :options {:insets {:top? true}}
:topBar {:visible true}} :component url-preview/view}
:component url-preview/preview}
{:name :url-preview-list {:name :url-preview-list
:options {:insets {:top? true} :options {:insets {:top? true}}
:topBar {:visible true}} :component url-preview-list/view}
:component url-preview-list/preview}
{:name :link-preview {:name :link-preview
:options {:insets {:top? true} :options {:insets {:top? true}}
:topBar {:visible true}} :component link-preview/view}]
:component link-preview/preview}]
:list-items [{:name :account-list-card :list-items [{:name :account-list-card
:options {:topBar {:visible true}}
:component account-list-card/preview} :component account-list-card/preview}
{:name :channel {:name :channel
:options {:topBar {:visible true}}
:component channel/preview-channel} :component channel/preview-channel}
{:name :community-list {:name :community-list
:options {:insets {:top? true} :options {:insets {:top? true}}
:topBar {:visible true}} :component community-list/view}
:component community-list/preview}
{:name :preview-lists {:name :preview-lists
:options {:topBar {:visible true}}
:component preview-lists/preview-preview-lists} :component preview-lists/preview-preview-lists}
{:name :user-list {:name :user-list
:options {:topBar {:visible true}}
:component user-list/preview-user-list} :component user-list/preview-user-list}
{:name :token-value {:name :token-value
:options {:topBar {:visible true}}
:component token-value/preview}] :component token-value/preview}]
:loaders [{:name :skeleton :loaders [{:name :skeleton
:options {:topBar {:visible true}}
:component skeleton/preview-skeleton}] :component skeleton/preview-skeleton}]
:markdown [{:name :texts :markdown [{:name :texts
:options {:topBar {:visible true}}
:component text/preview-text} :component text/preview-text}
{:name :markdown-list {:name :markdown-list
:options {:topBar {:visible true}}
:component markdown-list/preview-markdown-list}] :component markdown-list/preview-markdown-list}]
:messages [{:name :gap :messages [{:name :gap
:options {:topBar {:visible true}}
:component messages-gap/preview-messages-gap} :component messages-gap/preview-messages-gap}
{:name :system-messages {:name :system-messages
:options {:topBar {:visible true}}
:component system-message/preview-system-message} :component system-message/preview-system-message}
{:name :author {:name :author
:options {:topBar {:visible true}}
:component messages-author/preview-author}] :component messages-author/preview-author}]
:navigation [{:name :bottom-nav-tab :navigation [{:name :bottom-nav-tab
:options {:topBar {:visible true}}
:component bottom-nav-tab/preview-bottom-nav-tab} :component bottom-nav-tab/preview-bottom-nav-tab}
{:name :top-nav {:name :top-nav
:options {:topBar {:visible true}}
:component top-nav/preview-top-nav} :component top-nav/preview-top-nav}
{:name :page-nav {:name :page-nav
:options {:topBar {:visible true}}
:component page-nav/preview-page-nav} :component page-nav/preview-page-nav}
{:name :floating-shell-button {:name :floating-shell-button
:options {:topBar {:visible true}}
:component floating-shell-button/preview-floating-shell-button}] :component floating-shell-button/preview-floating-shell-button}]
:notifications [{:name :activity-logs :notifications [{:name :activity-logs
:options {:topBar {:visible true}}
:component activity-logs/preview-activity-logs} :component activity-logs/preview-activity-logs}
{:name :activity-logs-photos {:name :activity-logs-photos
:options {:topBar {:visible true}}
:component activity-logs-photos/preview-activity-logs-photos} :component activity-logs-photos/preview-activity-logs-photos}
{:name :toast {:name :toast
:options {:topBar {:visible true}}
:component toast/preview-toasts} :component toast/preview-toasts}
{:name :notification {:name :notification
:options {:topBar {:visible true}}
:component notification/preview-notification}] :component notification/preview-notification}]
:onboarding [{:name :small-option-card :onboarding [{:name :small-option-card
:options {:topBar {:visible true}}
:component small-option-card/preview-small-option-card}] :component small-option-card/preview-small-option-card}]
:password [{:name :tips :password [{:name :tips
:options {:topBar {:visible true}}
:component tips/preview-tips}] :component tips/preview-tips}]
:profile [{:name :profile-card :profile [{:name :profile-card
:options {:topBar {:visible true}}
:component profile-card/preview-profile-card} :component profile-card/preview-profile-card}
{:name :collectible {:name :collectible
:options {:topBar {:visible true}}
:component collectible/preview-collectible} :component collectible/preview-collectible}
{:name :select-profile {:name :select-profile
:options {:topBar {:visible true}}
:component select-profile/preview-select-profile}] :component select-profile/preview-select-profile}]
:reactions [{:name :react :reactions [{:name :react
:options {:topBar {:visible true}}
:component react/preview-react}] :component react/preview-react}]
:record-audio [{:name :record-audio :record-audio [{:name :record-audio
:options {:topBar {:visible true}}
:component record-audio/preview-record-audio}] :component record-audio/preview-record-audio}]
:switcher [{:name :switcher-cards :switcher [{:name :switcher-cards
:options {:topBar {:visible true}}
:component switcher-cards/preview-switcher-cards}] :component switcher-cards/preview-switcher-cards}]
:selectors [{:name :disclaimer :selectors [{:name :disclaimer
:options {:topBar {:visible true}}
:component disclaimer/preview-disclaimer} :component disclaimer/preview-disclaimer}
{:name :filter {:name :filter
:options {:topBar {:visible true}}
:component filter/preview} :component filter/preview}
{:name :selectors {:name :selectors
:options {:topBar {:visible true}}
:component selectors/preview-selectors} :component selectors/preview-selectors}
{:name :select-reactions {:name :select-reactions
:options {:topBar {:visible true}}
:component selector-reactions/preview}] :component selector-reactions/preview}]
:settings [{:name :privacy-option :settings [{:name :privacy-option
:options {:topBar {:visible true}}
:component privacy-option/preview-options} :component privacy-option/preview-options}
{:name :accounts {:name :accounts
:options {:topBar {:visible true}}
:component accounts/preview-accounts} :component accounts/preview-accounts}
{:name :settings-list {:name :settings-list
:options {:topBar {:visible true}}
:component settings-list/preview-settings-list} :component settings-list/preview-settings-list}
{:name :reorder-item {:name :reorder-item
:options {:topBar {:visible true}}
:component reorder-item/preview-reorder-item} :component reorder-item/preview-reorder-item}
{:name :category {:name :category
:options {:topBar {:visible true}}
:component category/preview}] :component category/preview}]
:share [{:name :qr-code :share [{:name :qr-code
:options {:topBar {:visible true}}
:component qr-code/preview-qr-code} :component qr-code/preview-qr-code}
{:name :share-qr-code {:name :share-qr-code
:options {:topBar {:visible true}}
:component share-qr-code/preview-share-qr-code}] :component share-qr-code/preview-share-qr-code}]
:tabs [{:name :segmented :tabs [{:name :segmented
:options {:topBar {:visible true}}
:component segmented/preview-segmented} :component segmented/preview-segmented}
{:name :tabs {:name :tabs
:options {:topBar {:visible true}}
:component tabs/preview-tabs} :component tabs/preview-tabs}
{:name :account-selector {:name :account-selector
:options {:topBar {:visible true}}
:component account-selector/preview-this}] :component account-selector/preview-this}]
:tags [{:name :context-tags :tags [{:name :context-tags
:options {:topBar {:visible true}}
:component context-tags/preview-context-tags} :component context-tags/preview-context-tags}
{:name :tags {:name :tags
:options {:topBar {:visible true}}
:component tags/preview-tags} :component tags/preview-tags}
{:name :permission-tag {:name :permission-tag
:options {:topBar {:visible true}}
:component permission-tag/preview-permission-tag} :component permission-tag/preview-permission-tag}
{:name :status-tags {:name :status-tags
:options {:topBar {:visible true}}
:component status-tags/preview-status-tags} :component status-tags/preview-status-tags}
{:name :token-tag {:name :token-tag
:options {:topBar {:visible true}}
:component token-tag/preview-token-tag}] :component token-tag/preview-token-tag}]
:text-combinations [{:name :title :text-combinations [{:name :title
:options {:topBar {:visible true}}
:component title/preview-title}] :component title/preview-title}]
:wallet [{:name :account-card :wallet [{:name :account-card
:options {:topBar {:visible true}}
:component account-card/preview-account-card} :component account-card/preview-account-card}
{:name :account-overview {:name :account-overview
:options {:topBar {:visible true}}
:component account-overview/preview-account-overview} :component account-overview/preview-account-overview}
{:name :network-amount {:name :network-amount
:options {:topBar {:visible true}}
:component network-amount/preview} :component network-amount/preview}
{:name :network-bridge {:name :network-bridge
:options {:topBar {:visible true}}
:component network-bridge/preview} :component network-bridge/preview}
{:name :progress-bar {:name :progress-bar
:options {:topBar {:visible true}}
:component progress-bar/preview} :component progress-bar/preview}
{:name :summary-info {:name :summary-info
:options {:topBar {:visible true}}
:component summary-info/preview} :component summary-info/preview}
{:name :token-input {:name :token-input
:options {:topBar {:visible true}}
:component token-input/preview} :component token-input/preview}
{:name :wallet-overview {:name :wallet-overview
:options {:topBar {:visible true}}
:component wallet-overview/preview-wallet-overview}] :component wallet-overview/preview-wallet-overview}]
:keycard [{:name :keycard-component :keycard [{:name :keycard-component
:options {:topBar {:visible true}}
:component keycard/preview-keycard}]}) :component keycard/preview-keycard}]})
(def screens (flatten (map val screens-categories))) (defn- navigation-bar
(defn navigation-bar
[] []
(let [logged-in? (rf/sub [:multiaccount/logged-in?]) (let [logged-in? (rf/sub [:multiaccount/logged-in?])
has-profiles? (boolean (rf/sub [:profile/profiles-overview])) has-profiles? (boolean (rf/sub [:profile/profiles-overview]))
@ -477,48 +366,51 @@
(theme/set-theme :dark) (theme/set-theme :dark)
(rf/dispatch [:init-root root]))))}}])) (rf/dispatch [:init-root root]))))}}]))
(defn theme-switcher (defn- theme-switcher
[] []
[rn/view [rn/view {:style style/theme-switcher}
{:style {:flex-direction :row
:justify-content :space-between
:padding-horizontal 24
:padding-vertical 12}}
[quo/button {:on-press #(theme/set-theme :light)} "Set light theme"] [quo/button {:on-press #(theme/set-theme :light)} "Set light theme"]
[quo/button {:on-press #(theme/set-theme :dark)} "Set dark theme"]]) [quo/button {:on-press #(theme/set-theme :dark)} "Set dark theme"]])
(defn category-view (defn- category-view
[] []
(let [open? (reagent/atom false)] (let [open? (reagent/atom false)
on-change #(swap! open? not)]
(fn [category] (fn [category]
[rn/view {:style {:margin-vertical 8}} [rn/view {:style {:margin-vertical 8}}
[quo/dropdown {:selected @open? :on-change #(swap! open? not) :type :grey} [quo/dropdown
(clojure.core/name (key category))] {:selected @open?
:on-change on-change
:type :grey}
(name (key category))]
(when @open? (when @open?
(for [{:keys [name]} (val category)] (for [{category-name :name} (val category)]
^{:key name} ^{:key category-name}
[quo/button [quo/button
{:type :outline {:type :outline
:container-style {:margin-vertical 8} :container-style {:margin-vertical 8}
:on-press #(rf/dispatch [:navigate-to name])} :on-press #(rf/dispatch [:navigate-to category-name])}
(clojure.core/name name)]))]))) (name category-name)]))])))
(defn main-screen (defn- main-screen
[] []
(fn [] [:<>
[:<> [navigation-bar]
[navigation-bar] [theme-switcher]
[theme-switcher] [rn/scroll-view {:style (style/main)}
[rn/scroll-view (for [category (sort screens-categories)]
{:flex 1 ^{:key (first category)}
:padding-bottom 8 [category-view category])]])
:padding-horizontal 16
:background-color (colors/theme-colors colors/white colors/neutral-90)} (def screens
[rn/view (->> screens-categories
(map (fn [category] (map val)
^{:key (get category 0)} flatten
[category-view category]) (map (fn [subcategory]
(sort screens-categories))]]])) (update-in subcategory
[:options :topBar]
merge
{:visible true})))))
(def main-screens (def main-screens
[{:name :quo2-preview [{:name :quo2-preview

View File

@ -1,216 +1,178 @@
(ns status-im2.contexts.quo-preview.preview (ns status-im2.contexts.quo-preview.preview
(:require [clojure.string :as string] (:require [camel-snake-kebab.core :as camel-snake-kebab]
[clojure.string :as string]
[quo2.core :as quo]
[quo2.foundations.colors :as colors] [quo2.foundations.colors :as colors]
[quo2.theme :as theme] [quo2.theme :as quo.theme]
[react-native.blur :as blur] [react-native.blur :as blur]
[react-native.core :as rn] [react-native.core :as rn]
[reagent.core :as reagent] [reagent.core :as reagent]
[status-im2.common.resources :as resources] [status-im2.common.resources :as resources]
[status-im2.contexts.quo-preview.style :as style]
utils.number) utils.number)
(:require-macros status-im2.contexts.quo-preview.preview)) (:require-macros status-im2.contexts.quo-preview.preview))
(def container (defn- label-view
{:flex-direction :row
:padding-vertical 8
:flex 1
:align-items :center})
(defn touchable-style
[]
{:flex 1
:align-items :center
:justify-content :center
:padding-horizontal 16
:height 44})
(defn select-style
[]
{:flex 1
:flex-direction :row
:align-items :center
:padding-horizontal 16
:height 44
:border-radius 4
:background-color colors/neutral-20
:border-width 1
:border-color colors/neutral-100})
(defn select-option-style
[selected]
(merge (select-style)
{:margin-vertical 8
:justify-content :center}
(if selected
{:background-color colors/primary-50-opa-30}
{:background-color (colors/theme-colors colors/neutral-20 colors/white)})))
(def label-style
{:flex 0.4
:padding-right 8})
(defn label-view
[_ label] [_ label]
[rn/view {:style label-style} [rn/view {:style style/label-container}
[rn/text [rn/text {:style (style/label)}
(when-let [label-color (colors/theme-colors colors/neutral-100 colors/white)]
{:style {:color label-color}})
label]]) label]])
(defn modal-container (defn- humanize
[] [k]
{:flex 1 ;; We explicitly convert `k` to string because sometimes it's a number and
:justify-content :center ;; Clojure would throw an exception.
:padding-horizontal 24 (-> (if (keyword? k) k (str k))
:background-color "rgba(0,0,0,0.4)"}) camel-snake-kebab/->kebab-case-keyword
name
(string/replace "-" " ")
string/capitalize))
(defn modal-view (defn- key->boolean-label
[] [k]
{:padding-horizontal 16 (let [label (humanize k)]
:padding-vertical 8 (if (string/ends-with? label "?")
:border-radius 8 label
:flex-direction :column (str label "?"))))
:margin-vertical 100
:background-color (colors/theme-colors colors/neutral-20 colors/white)})
(defn customizer-boolean (defn- key->text-label
[k]
(str (humanize k) ":"))
(defn- customizer-boolean
[{:keys [label state] :as args}] [{:keys [label state] :as args}]
(let [state* (reagent/cursor state [(:key args)])] (let [label (or label (key->boolean-label (:key args)))
[rn/view {:style container} field-value (reagent/cursor state [(:key args)])
active? @field-value]
[rn/view {:style style/field-row}
[label-view state label] [label-view state label]
[rn/view [rn/view {:style (style/boolean-container)}
{:style {:flex-direction :row [rn/pressable
:flex 0.6 {:style (style/boolean-button {:active? active? :left? true})
:border-radius 4 :on-press #(reset! field-value true)}
:background-color (colors/theme-colors colors/neutral-20 colors/white) [rn/text {:style (style/field-text active?)}
:border-width 1
:border-color (colors/theme-colors colors/neutral-100 colors/white)}}
[rn/touchable-opacity
{:style (merge (touchable-style) {:background-color (when @state* colors/primary-50-opa-30)})
:on-press #(reset! state* true)}
[rn/text
"True"]] "True"]]
[rn/view [rn/pressable
{:width 1 {:style (style/boolean-button {:active? (not active?) :left? false})
:margin-vertical 4 :on-press #(reset! field-value false)}
:background-color (colors/theme-colors colors/neutral-20 colors/white)}] [rn/text {:style (style/field-text (not active?))}
[rn/touchable-opacity
{:style (merge (touchable-style)
{:background-color (when (not @state*) colors/primary-50-opa-30)})
:on-press #(reset! state* false)}
[rn/text {}
"False"]]]])) "False"]]]]))
(defn customizer-text (defn- customizer-text
[{:keys [label state limit suffix] :as args}] [{:keys [label state limit suffix] :as args}]
(let [state* (reagent/cursor state [(:key args)])] (let [label (or label (key->text-label (:key args)))
[rn/view {:style container} field-value (reagent/cursor state [(:key args)])]
[rn/view {:style style/field-row}
[label-view state label] [label-view state label]
[rn/view {:style {:flex 0.6}} [rn/view {:style style/field-column}
[rn/text-input [rn/text-input
(merge (merge
{:value @state* {:value @field-value
:show-cancel false :show-cancel false
:style {:border-radius 4 :style (style/field-container false)
:border-width 1 :keyboard-appearance (quo.theme/theme-value :light :dark)
:color (colors/theme-colors colors/neutral-100 colors/white) :on-change-text (fn [text]
:border-color (colors/theme-colors colors/neutral-100 colors/white)} (reset! field-value (if (and suffix
:keyboard-appearance (theme/theme-value :light :dark) (> (count text) (count @field-value)))
:on-change-text #(do (str (string/replace text suffix "") suffix)
(reset! state* (if (and suffix (> (count %) (count @state*))) text))
(str (string/replace % suffix "") suffix) (reagent/flush))}
%))
(reagent/flush))}
(when limit (when limit
{:max-length limit}))]]])) {:max-length limit}))]]]))
(defn customizer-number (defn- customizer-number
[{:keys [label state default] :as args}] [{:keys [label state default] :as args}]
(let [state* (reagent/cursor state [(:key args)])] (let [label (or label (key->text-label (:key args)))
[rn/view {:style container} field-value (reagent/cursor state [(:key args)])]
[rn/view {:style style/field-row}
[label-view state label] [label-view state label]
[rn/view {:style {:flex 0.6}} [rn/view {:style style/field-column}
[rn/text-input [rn/text-input
(merge (merge
{:value (str @state*) {:value (str @field-value)
:show-cancel false :show-cancel false
:style {:border-radius 4 :style (style/field-container false)
:border-width 1 :keyboard-appearance (quo.theme/theme-value :light :dark)
:color (colors/theme-colors colors/neutral-100 colors/white) :on-change-text (fn [text]
:border-color (colors/theme-colors colors/neutral-100 colors/white)} (reset! field-value (utils.number/parse-int text default))
:keyboard-appearance (theme/theme-value :light :dark)
:on-change-text (fn [v]
(reset! state* (utils.number/parse-int v default))
(reagent/flush))})]]])) (reagent/flush))})]]]))
(defn value-for-key (defn- find-selected-option
[id v] [id v]
(:value (first (filter #(= (:key %) id) v)))) (first (filter #(= (:key %) id) v)))
(defn customizer-select (defn- customizer-select-modal
[{:keys [open options field-value]}]
[rn/modal
{:visible @open
:on-request-close #(reset! open false)
:status-bar-translucent true
:transparent true
:animation :slide}
[rn/view {:style (style/modal-overlay)}
[rn/view {:style (style/modal-container)}
[rn/scroll-view {:shows-vertical-scroll-indicator false}
(doall
(for [{k :key v :value} options
:let [v (or v (humanize k))]]
^{:key k}
[rn/pressable
{:style (style/select-option (= @field-value k))
:on-press (fn []
(reset! open false)
(reset! field-value k))}
[rn/text {:style (style/field-text (= @field-value k))}
v]]))]
[rn/view {:style (style/footer)}
[rn/pressable
{:style (style/select-button)
:on-press (fn []
(reset! field-value nil)
(reset! open false))}
[rn/text {:style (style/field-text false)}
"Clear"]]
[rn/view {:style {:width 16}}]
[rn/touchable-opacity
{:style (style/select-button)
:on-press #(reset! open false)}
[rn/text {:style (style/field-text false)}
"Close"]]]]]])
(defn- customizer-select-button
[{:keys [open selected-key]}]
[rn/pressable
{:style (style/select-container)
:on-press #(reset! open true)}
[rn/text
{:style (style/field-select)
:number-of-lines 1}
(if selected-key
(humanize selected-key)
"Select option")]
[rn/view
[quo/icon :i/chevron-right]]])
(defn- customizer-select
[] []
(let [open (reagent/atom nil)] (let [open (reagent/atom nil)]
(fn [{:keys [label state options] :as args}] (fn [{:keys [label state options] :as args}]
(let [state* (reagent/cursor state [(:key args)]) (let [label (or label (key->text-label (:key args)))
selected (value-for-key @state* options)] field-value (reagent/cursor state [(:key args)])
[rn/view {:style container} selected-key (:key (find-selected-option @field-value options))]
[rn/view {:style style/field-row}
[label-view state label] [label-view state label]
[rn/view {:style {:flex 0.6}} [rn/view {:style style/field-column}
[rn/modal [customizer-select-modal
{:visible @open {:open open
:on-request-close #(reset! open false) :options options
:statusBarTranslucent true :field-value field-value}]
:transparent true [customizer-select-button {:open open :selected-key selected-key}]]]))))
:animation :slide}
[rn/view {:style (modal-container)}
[rn/view {:style (modal-view)}
[rn/scroll-view
(doall
(for [{k :key v :value} options]
^{:key k}
[rn/touchable-opacity
{:style (select-option-style (= @state* k))
:on-press #(do
(reset! open false)
(reset! state* k))}
[rn/text {:color (if (= @state* k) :link :secondary)}
v]]))]
[rn/view
{:flex-direction :row
:padding-top 20
:margin-top 10
:border-top-width 1
:border-top-color (colors/theme-colors colors/neutral-100 colors/white)}
[rn/touchable-opacity
{:style (select-option-style false)
:on-press #(do
(reset! state* nil)
(reset! open false))}
[rn/text "Clear"]]
[rn/view {:width 16}]
[rn/touchable-opacity
{:style (select-option-style false)
:on-press #(reset! open false)}
[rn/text "Close"]]]]]]
[rn/touchable-opacity
{:style (select-style)
:on-press #(reset! open true)}
(if selected
[rn/text {:color :link} selected]
[rn/text "Select option"])
[rn/view
{:position :absolute
:right 16
:top 0
:bottom 0
:justify-content :center}
[rn/text "↓"]]]]]))))
(defn customizer (defn customizer
[state descriptors] [state descriptors]
[rn/view [rn/view
{:style {:flex 1} {:style {:flex-shrink 1
:padding-horizontal 16} :padding-horizontal 20}}
(doall (doall
(for [desc descriptors (for [desc descriptors
:let [descriptor (merge desc {:state state})]] :let [descriptor (merge desc {:state state})]]
@ -237,19 +199,6 @@
{:key k :value (string/capitalize (name k))})))} {:key k :value (string/capitalize (name k))})))}
opts))) opts)))
(comment
[{:label "Show error:"
:key :error
:type :boolean}
{:label "Label:"
:key :label
:type :text}
{:label "Type:"
:key :type
:type :select
:options [{:key :primary :value "Primary"}
{:key :secondary :value "Secondary"}]}])
(defn blur-view (defn blur-view
[{:keys [show-blur-background? image height blur-view-props style]} children] [{:keys [show-blur-background? image height blur-view-props style]} children]
[rn/view [rn/view
@ -262,8 +211,7 @@
:overflow :hidden}} :overflow :hidden}}
[rn/image [rn/image
{:source (or image (resources/get-mock-image :community-cover)) {:source (or image (resources/get-mock-image :community-cover))
:style {:height "100%" :style {:height "100%" :width "100%"}}]
:width "100%"}}]
[blur/view [blur/view
(merge {:style {:position :absolute (merge {:style {:position :absolute
:top 0 :top 0
@ -271,9 +219,7 @@
:left 0 :left 0
:right 0} :right 0}
:blur-amount 10 :blur-amount 10
:overlay-color (colors/theme-colors :overlay-color (colors/theme-colors colors/white-opa-70 colors/neutral-80-opa-80)}
colors/white-opa-70
colors/neutral-80-opa-80)}
blur-view-props)]]) blur-view-props)]])
[rn/view [rn/view
{:style (merge {:position :absolute {:style (merge {:position :absolute
@ -281,3 +227,33 @@
:padding-horizontal 16} :padding-horizontal 16}
style)} style)}
children]]) children]])
(defn preview-container
[{:keys [state descriptor blur?
component-container-style
blur-container-style blur-view-props blur-height show-blur-background?]
:or {blur-height 200}}
component]
[rn/scroll-view
{:style (style/panel-basic)
:shows-vertical-scroll-indicator false}
[rn/pressable {:on-press rn/dismiss-keyboard!}
[rn/view {:style style/customizer-container}
[customizer state descriptor]]
[rn/view
(merge {:style style/component-container}
component-container-style)
(if blur?
[blur-view
{:show-blur-background? show-blur-background?
:height blur-height
:style (merge {:width "100%"
:flex-grow 1}
(when-not show-blur-background?
{:padding-horizontal 0
:top 0})
blur-container-style)
:blur-view-props (merge {:blur-type (quo.theme/get-theme)}
blur-view-props)}
component]
component)]]])

View File

@ -0,0 +1,179 @@
(ns status-im2.contexts.quo-preview.style
(:require [quo2.foundations.colors :as colors]
[quo2.foundations.typography :as typography]))
;;;; Form fields
(def field-border-radius 12)
(def field-flex-percentage 0.6)
(def text-default typography/paragraph-1)
(defn field-active-bg-color
[]
(colors/theme-colors colors/primary-50 colors/primary-60))
(defn field-default-color
[]
(colors/theme-colors colors/neutral-100 colors/white))
(defn field-default-bg-color
[]
(colors/theme-colors colors/neutral-20 colors/neutral-80))
(defn field-default-border-color
[]
(colors/theme-colors colors/neutral-30 colors/neutral-70))
(def field-row
{:flex-direction :row
:padding-vertical 6
:align-items :center})
(def field-column
{:flex field-flex-percentage})
(defn field-container
[active?]
(merge text-default
{:color (if active?
(colors/theme-colors colors/white colors/white-opa-95)
(colors/theme-colors colors/neutral-100 colors/white))
:border-width 1
:border-color (field-default-border-color)
:border-radius field-border-radius
:padding-vertical 9
:padding-horizontal 12}))
(defn field-text
[active?]
(merge text-default
{:color (if active?
(colors/theme-colors colors/white colors/white-opa-95)
(field-default-color))}))
(def customizer-container
{:flex-shrink 1
:padding-top 12})
(defn select-container
[]
(merge (field-container false)
{:flex-direction :row
:align-items :center
:border-radius field-border-radius
:background-color (field-default-bg-color)
:border-width 1
:border-color (field-default-border-color)}))
(defn field-select
[]
(merge text-default
{:flex-grow 1
:color (field-default-color)}))
(defn select-option
[selected?]
(merge (field-container selected?)
{:justify-content :center
:flex 1
:margin-vertical 4}
(if selected?
{:border-color (field-active-bg-color)
:background-color (field-active-bg-color)}
{:background-color (field-default-bg-color)})))
(defn select-button
[]
(merge (select-option false) {:align-items :center}))
(def label-container
{:flex (- 1 field-flex-percentage)
:padding-right 8})
(defn label
[]
(merge text-default
typography/font-medium
{:color (field-default-color)}))
(defn boolean-container
[]
{:flex-direction :row
:flex field-flex-percentage
:border-radius field-border-radius})
(defn boolean-button
[{:keys [active? left?]}]
(cond-> {:flex 1
:align-items :center
:justify-content :center
:padding-vertical 9
:padding-horizontal 12
:border-color (if active?
(field-active-bg-color)
(field-default-border-color))
:border-top-width 1
:border-bottom-width 1
:background-color (if active?
(field-active-bg-color)
(field-default-bg-color))}
left?
(assoc :border-top-left-radius field-border-radius
:border-bottom-left-radius field-border-radius
:border-left-width 1)
(not left?)
(assoc :border-top-right-radius field-border-radius
:border-bottom-right-radius field-border-radius
:border-right-width 1)))
;;;; Modal
(defn modal-overlay
[]
{:flex 1
:justify-content :center
:padding-horizontal 24
:background-color (colors/theme-colors colors/neutral-80-opa-60 colors/neutral-80-opa-80)})
(defn modal-container
[]
{:padding-horizontal 16
:padding-vertical 8
:border-radius 12
:margin-vertical 100
:background-color (colors/theme-colors colors/white colors/neutral-95)})
(defn footer
[]
{:flex-direction :row
:padding-top 10
:margin-top 10
:border-top-width 1
:border-top-color (colors/theme-colors colors/neutral-10 colors/neutral-80)})
;;;; Misc
(defn panel-basic
[]
{:background-color (colors/theme-colors colors/white colors/neutral-95)
:flex 1})
(def component-container
{:flex-grow 1
:min-height 200
:padding-vertical 20
:padding-horizontal 20})
(defn main
[]
{:flex 1
:padding-bottom 8
:padding-horizontal 16
:background-color (colors/theme-colors colors/white colors/neutral-90)})
(def theme-switcher
{:flex-direction :row
:justify-content :space-between
:padding-horizontal 24
:padding-vertical 12})