diff --git a/src/status_im2/contexts/quo_preview/colors/color_picker.cljs b/src/status_im2/contexts/quo_preview/colors/color_picker.cljs index 28619974e1..c41782bb6a 100644 --- a/src/status_im2/contexts/quo_preview/colors/color_picker.cljs +++ b/src/status_im2/contexts/quo_preview/colors/color_picker.cljs @@ -1,48 +1,26 @@ (ns status-im2.contexts.quo-preview.colors.color-picker (:require [quo2.core :as quo] - [quo2.foundations.colors :as colors] - [react-native.blur :as blur] - [react-native.core :as rn] [reagent.core :as reagent] [status-im2.contexts.quo-preview.preview :as preview])) (def descriptor - [{:label "Color:" - :key :color + [{:key :selected :type :select :options (map (fn [color] (let [k (get color :name)] {:key k :value k})) (quo/picker-colors))} - {:label "Blur?" - :key :blur - :type :boolean}]) + {:key :blur? + :type :boolean}]) -(defn cool-preview +(defn view [] - (let [state (reagent/atom {:color "orange" :blur false}) - blur (reagent/cursor state [:blur]) - color (reagent/cursor state [:color])] + (let [state (reagent/atom {:selected :orange + :blur? false})] (fn [] - [rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} - [rn/view {:padding-bottom 150} - [preview/customizer state descriptor] - [(if @blur blur/view :<>) - [rn/view {:padding-vertical 60 :align-items :center} - [quo/color-picker - {: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}]]) + [preview/preview-container + {:state state + :descriptor descriptor + :blur? (:blur? @state) + :show-blur-background? true} + [quo/color-picker (assoc @state :on-change #(swap! state assoc :selected %))]]))) diff --git a/src/status_im2/contexts/quo_preview/dividers/divider_label.cljs b/src/status_im2/contexts/quo_preview/dividers/divider_label.cljs index 1db8bd8cfe..cc492bc33d 100644 --- a/src/status_im2/contexts/quo_preview/dividers/divider_label.cljs +++ b/src/status_im2/contexts/quo_preview/dividers/divider_label.cljs @@ -1,54 +1,29 @@ (ns status-im2.contexts.quo-preview.dividers.divider-label - (:require [quo2.components.dividers.divider-label :as divider-label] - [quo2.foundations.colors :as colors] - [react-native.core :as rn] + (:require [quo2.core :as quo] [reagent.core :as reagent] [status-im2.contexts.quo-preview.preview :as preview])) (def descriptor - [{:label "Label:" - :key :label - :type :text} - {:label "Chevron position:" - :key :chevron-position + [{:type :text :key :label} + {:type :text :key :counter-value} + {:type :boolean :key :increase-padding-top?} + {:type :boolean :key :blur?} + {:key :chevron-position :type :select - :options [{:key :left - :value "Left"} - {: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}]) + :options [{:key :left} + {:key :right}]}]) -(defn cool-preview +(defn view [] - (let [state (reagent/atom {:label "Welcome" + (let [state (reagent/atom {:blur? false :chevron-position :left - :counter-value 0 + :counter-value "0" :increase-padding-top? true - :blur? false})] + :label "Welcome"})] (fn [] - [rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} - [rn/view {:padding-bottom 150} - [preview/customizer state descriptor] - [rn/view {:padding-vertical 60} - [divider-label/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}]]) + [preview/preview-container + {:state state + :descriptor descriptor + :blur? (:blur? @state) + :show-blur-background? true} + [quo/divider-label @state]]))) diff --git a/src/status_im2/contexts/quo_preview/links/link_preview.cljs b/src/status_im2/contexts/quo_preview/links/link_preview.cljs index 79bca73eab..1f6f1932db 100644 --- a/src/status_im2/contexts/quo_preview/links/link_preview.cljs +++ b/src/status_im2/contexts/quo_preview/links/link_preview.cljs @@ -1,100 +1,56 @@ (ns status-im2.contexts.quo-preview.links.link-preview - (:require [clojure.string :as string] - [quo2.core :as quo] - [quo2.foundations.colors :as colors] - [react-native.core :as rn] + (:require [quo2.core :as quo] [reagent.core :as reagent] [status-im2.common.resources :as resources] - [status-im2.contexts.quo-preview.preview :as preview] - utils.number)) + [status-im2.contexts.quo-preview.preview :as preview])) (def descriptor - [{:label "Title" - :key :title - :type :text} - {:label "Description" - :key :description - :type :text} - {:label "Link" - :key :link - :type :text} - {:label "Container width" - :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 :text :key :title} + {:type :text :key :description} + {:type :text :key :link} + {:type :number :key :width} + {:type :boolean :key :with-logo?} + {:type :boolean :key :with-description?} + {:type :boolean :key :with-thumbnail?} + {:type :text :key :disabled-text} + {:type :boolean :key :enabled?} + {:key :thumbnail :type :select - :options (mapv (fn [k] - {:key k - :value (string/capitalize (name k))}) + :options (mapv (fn [k] {:key k}) (keys resources/mock-images))} - {:label "Thumbnail size" - :key :thumbnail-size + {:key :thumbnail-size :type :select - :options [{:key :normal - :value :normal} - {:key :large - :value :large}]}]) + :options [{:key :normal} + {:key :large}]}]) -(defn cool-preview +(defn view [] (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" :thumbnail :collectible - :width "295" - :with-logo? true - :with-thumbnail? true - :with-description? true - :enabled? true :thumbnail-size :normal - :disabled-text "Enable Preview"})] + :title "Rarible - NFT Marketplace" + :width 295 + :with-description? true + :with-logo? true + :with-thumbnail? true})] (fn [] - (let [width (utils.number/parse-int (:width @state) 295) - thumbnail (get resources/mock-images (:thumbnail @state))] - [rn/view {:style {:margin-bottom 20}} - [preview/customizer state descriptor] - [rn/view - {:style {:align-items :center - :margin-top 20}} - [quo/link-preview - {:logo (when (:with-logo? @state) - (resources/get-mock-image :status-logo)) - :title (:title @state) - :description (when (:with-description? @state) - (:description @state)) - :enabled? (:enabled? @state) - :on-enable #(js/alert "Button pressed") - :disabled-text (:disabled-text @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}]]) + (let [thumbnail (get resources/mock-images (:thumbnail @state))] + [preview/preview-container {:state state :descriptor descriptor} + [quo/link-preview + {:logo (when (:with-logo? @state) + (resources/get-mock-image :status-logo)) + :title (:title @state) + :description (when (:with-description? @state) + (:description @state)) + :enabled? (:enabled? @state) + :on-enable #(js/alert "Button pressed") + :disabled-text (:disabled-text @state) + :link (:link @state) + :thumbnail (when (:with-thumbnail? @state) + thumbnail) + :thumbnail-size (:thumbnail-size @state) + :container-style {:width (:width @state)}}]])))) diff --git a/src/status_im2/contexts/quo_preview/links/url_preview.cljs b/src/status_im2/contexts/quo_preview/links/url_preview.cljs index 876b34fa82..27833f9a32 100644 --- a/src/status_im2/contexts/quo_preview/links/url_preview.cljs +++ b/src/status_im2/contexts/quo_preview/links/url_preview.cljs @@ -1,30 +1,18 @@ (ns status-im2.contexts.quo-preview.links.url-preview (:require [quo2.core :as quo] - [quo2.foundations.colors :as colors] - [react-native.core :as rn] [reagent.core :as reagent] [status-im2.common.resources :as resources] [status-im2.contexts.quo-preview.preview :as preview])) (def descriptor - [{:label "Title" - :key :title - :type :text} - {:label "Body" - :key :body - :type :text} - {:label "With logo?" - :key :with-logo? - :type :boolean} - {:label "Loading?" - :key :loading? - :type :boolean} - {:label "Loading message" - :key :loading-message - :type :text}]) + [{:type :text :key :title} + {:type :text :key :body} + {:type :boolean :key :with-logo?} + {:type :boolean :key :loading?} + {:type :text :key :loading-message}]) -(defn cool-preview +(defn view [] (let [state (reagent/atom {:title "Status - Private, Secure Communication" @@ -33,29 +21,12 @@ :loading? false :loading-message "Generating preview"})] (fn [] - [rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} - [rn/view {:style {:padding-bottom 150}} - [preview/customizer state descriptor] - [rn/view - {:style {:align-items :center - :padding-horizontal 16 - :margin-top 50}} - [quo/url-preview - {:title (:title @state) - :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}]]) + [preview/preview-container {:state state :descriptor descriptor} + [quo/url-preview + {:title (:title @state) + :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")}]]))) diff --git a/src/status_im2/contexts/quo_preview/links/url_preview_list.cljs b/src/status_im2/contexts/quo_preview/links/url_preview_list.cljs index e191e6a4f7..4e00554ce5 100644 --- a/src/status_im2/contexts/quo_preview/links/url_preview_list.cljs +++ b/src/status_im2/contexts/quo_preview/links/url_preview_list.cljs @@ -1,50 +1,34 @@ (ns status-im2.contexts.quo-preview.links.url-preview-list (:require [quo2.core :as quo] - [quo2.foundations.colors :as colors] [react-native.core :as rn] [reagent.core :as reagent] [status-im2.common.resources :as resources] - [status-im2.contexts.quo-preview.preview :as preview] - utils.number)) + [status-im2.contexts.quo-preview.preview :as preview])) (def descriptor - [{:label "Number of previews" - :key :previews-length - :type :text}]) + [{:type :number :key :previews-length}]) -(defn cool-preview +(defn view [] - (let [state (reagent/atom {:previews-length "3"})] + (let [state (reagent/atom {:previews-length 3}) + padding 20] (fn [] - (let [previews-length (min 6 (utils.number/parse-int (:previews-length @state))) - padding 20] - [rn/view {:style {:padding-bottom 150}} - [preview/customizer state descriptor] - [rn/view - {:style {:align-items :center - :margin-top 50}} - [quo/url-preview-list - {:horizontal-spacing padding - :preview-width (- (:width (rn/get-window)) - (* 2 padding)) - :on-clear #(js/alert "Clear button pressed") - :key-fn :url - :data (for [index (range previews-length) - :let [index (inc index)]] - {:title (str "Title " index) - :body (str "status.im." index) - :logo (resources/get-mock-image :status-logo) - :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}]]) + [preview/preview-container + {:state state + :descriptor descriptor + :component-container-style {:padding-horizontal 0}} + [quo/url-preview-list + {:horizontal-spacing padding + :preview-width (- (:width (rn/get-window)) + (* 2 padding)) + :on-clear #(js/alert "Clear button pressed") + :key-fn :url + :data (for [index (range (:previews-length @state)) + :let [index (inc index)]] + {:title (str "Title " index) + :body (str "status.im." index) + :logo (resources/get-mock-image + :status-logo) + :loading? false + :url (str "status.im." index)})}]]))) diff --git a/src/status_im2/contexts/quo_preview/list_items/community_list.cljs b/src/status_im2/contexts/quo_preview/list_items/community_list.cljs index f29b7b8c10..f103bd679d 100644 --- a/src/status_im2/contexts/quo_preview/list_items/community_list.cljs +++ b/src/status_im2/contexts/quo_preview/list_items/community_list.cljs @@ -2,39 +2,33 @@ (:require [quo2.core :as quo] [quo2.foundations.colors :as colors] [quo2.theme :as quo.theme] - [react-native.core :as rn] [reagent.core :as reagent] [status-im2.common.resources :as resources] [status-im2.contexts.quo-preview.community.data :as data] [status-im2.contexts.quo-preview.preview :as preview])) (def descriptor-type - {:label "Type:" + {:type :select :key :type - :type :select - :options [{:key :discover :value "Discover"} - {:key :engage :value "Engage"} - {:key :share :value "Share"}]}) + :options [{:key :discover} + {:key :engage} + {:key :share}]}) (def descriptor-locked - {:label "Locked?" :key :locked? :type :boolean}) + {:type :boolean :key :locked?}) (def descriptor-unread-count - {:label "Unread count:" :key :unread-count :type :number}) + {:type :number :key :unread-count}) (def descriptor-title - {:label "Title:" :key :title :type :text}) + {:type :text :key :title}) (def descriptor-blur - {:label "Blur?" :key :blur? :type :boolean}) + {:type :boolean :key :blur?}) (def descriptor-member-stats - [{:label "Total member count:" - :key :members-count - :type :number} - {:label "Active member count:" - :key :active-count - :type :number}]) + [{:type :number :key :members-count} + {:type :number :key :active-count}]) (def descriptors-base [descriptor-type @@ -43,29 +37,27 @@ (def descriptors-type-discover (conj descriptors-base - {:label "Info:" + {:type :select :key :info - :type :select - :options [{:key :token-gated :value "Token gated"} - {:key :default :value "Default"}]} + :options [{:key :token-gated} + {:key :default}]} {:label "Member stats?" - :key :members? - :type :boolean})) + :type :boolean + :key :members?})) (def descriptors-type-engage (conj descriptors-base - {:label "Info:" + {:type :select :key :info - :type :select - :options [{:key :notification :value "Notification"} - {:key :mention :value "Mention"} - {:key :muted :value "Muted"} - {:key :token-gated :value "Token gated"} - {:key :navigation :value "Navigation"} - {:key :default :value "Default"}]})) + :options [{:key :notification} + {:key :mention} + {:key :muted} + {:key :token-gated} + {:key :navigation} + {:key :default}]})) (def descriptors-type-share - (conj descriptors-base {:label "Subtitle:" :key :subtitle :type :text})) + (conj descriptors-base {:type :text :key :subtitle})) (defn descriptors [{:keys [members? info] :as state}] @@ -88,7 +80,7 @@ (into [descriptor-blur] descs) descs))) -(defn cool-preview +(defn view [] (let [state (reagent/atom {:blur? false :customization-color :blue @@ -103,30 +95,16 @@ :unread-count 5})] (fn [] (let [customization-color (colors/custom-color-by-theme (:customization-color @state) 50 60)] - [rn/touchable-without-feedback {:on-press rn/dismiss-keyboard!} - [rn/view {:style {:margin-bottom 20}} - [preview/customizer state (descriptors @state)] - [rn/view {:style {:margin-vertical 30 :align-items :center}} - [quo/community-list-item - (merge @state - {:container-style {:width 335} - :logo (resources/get-mock-image :status-logo) - :tokens (:tokens data/community) - :customization-color customization-color - :on-press #(js/alert "List item pressed") - :on-long-press #(js/alert "Long pressed item") - :on-press-info #(js/alert "Info pressed") - :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}]]) + [preview/preview-container {:state state :descriptor (descriptors @state)} + [quo/community-list-item + (merge @state + {:container-style {:width 335} + :logo (resources/get-mock-image :status-logo) + :tokens (:tokens data/community) + :customization-color customization-color + :on-press #(js/alert "List item pressed") + :on-long-press #(js/alert "Long pressed item") + :on-press-info #(js/alert "Info pressed") + :members (when (:members? @state) + {:members-count (:members-count @state) + :active-count (:active-count @state)})})]])))) diff --git a/src/status_im2/contexts/quo_preview/main.cljs b/src/status_im2/contexts/quo_preview/main.cljs index a664e743fd..948078207e 100644 --- a/src/status_im2/contexts/quo_preview/main.cljs +++ b/src/status_im2/contexts/quo_preview/main.cljs @@ -2,9 +2,9 @@ (:refer-clojure :exclude [filter]) (:require [quo2.core :as quo] - [quo2.foundations.colors :as colors] [reagent.core :as reagent] [react-native.core :as rn] + [status-im2.contexts.quo-preview.style :as style] [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.avatars.account-avatar :as account-avatar] @@ -120,344 +120,233 @@ (def screens-categories {:foundations [{:name :shadows - :options {:topBar {:visible true}} :component shadows/preview-shadows}] :animated-list [{:name :animated-header-list - :options {:topBar {:visible false}} :component animated-header-list/mock-screen}] :avatar [{:name :group-avatar - :options {:topBar {:visible true}} :component group-avatar/preview-group-avatar} {:name :icon-avatar - :options {:topBar {:visible true}} :component icon-avatar/preview-icon-avatar} {:name :user-avatar - :options {:topBar {:visible true}} :component user-avatar/preview-user-avatar} {:name :wallet-user-avatar - :options {:topBar {:visible true}} :component wallet-user-avatar/preview-wallet-user-avatar} {:name :channel-avatar - :options {:topBar {:visible true}} :component channel-avatar/preview-channel-avatar} {:name :account-avatar - :options {:topBar {:visible true}} :component account-avatar/preview-account-avatar}] :banner [{:name :banner - :options {:topBar {:visible true}} :component banner/preview-banner}] :buttons [{:name :button - :options {:topBar {:visible true}} :component button/preview-button} {:name :composer-button - :options {:topBar {:visible true}} :component composer-button/preview-composer-button} {:name :dynamic-button - :options {:topBar {:visible true}} :component dynamic-button/preview-dynamic-button} {:name :slide-button - :options {:topBar {:visible true}} :component slide-button/preview-slide-button} {:name :predictive-keyboard - :options {:topBar {:visible true}} :component predictive-keyboard/preview-predictive-keyboard}] :browser [{:name :browser-input - :options {:topBar {:visible false}} :component browser-input/preview-browser-input}] :calendar [{:name :calendar - :options {:topBar {:visible true}} :component calendar/preview-calendar} {:name :calendar-day - :options {:topBar {:visible true}} :component calendar-day/preview-calendar-day} {:name :calendar-year - :options {:topBar {:visible true}} :component calendar-year/preview-calendar-year}] :code [{:name :snippet - :options {:topBar {:visible true}} :component code-snippet/preview-code-snippet}] :colors [{:name :color-picker - :options {:topBar {:visible true}} - :component color-picker/preview-color-picker}] + :component color-picker/view}] :community [{:name :community-card-view - :options {:topBar {:visible true}} :component community-card/preview-community-card} {:name :community-membership-list-view - :options {:topBar {:visible true}} :component community-membership-list-view/preview-community-list-view} {:name :discover-card - :options {:topBar {:visible true}} :component discover-card/preview-discoverd-card} {:name :token-gating - :options {:insets {:bottom? true} - :topBar {:visible true}} + :options {:insets {:bottom? true}} :component token-gating/preview-token-gating} {:name :channel-actions - :options {:insets {:bottom? true} - :topBar {:visible true}} + :options {:insets {:bottom? true}} :component channel-actions/preview-channel-actions}] :counter [{:name :counter - :options {:topBar {:visible true}} :component counter/preview-counter} {:name :step - :options {:topBar {:visible true}} :component step/preview-step}] :dividers [{:name :divider-label - :options {:topBar {:visible true}} - :component divider-label/preview-divider-label} + :component divider-label/view} {:name :new-messages - :options {:topBar {:visible true}} :component new-messages/preview-new-messages} {:name :divider-date - :options {:topBar {:visible true}} :component divider-date/preview-divider-date} {:name :strength-divider - :options {:topBar {:visible true}} :component strength-divider/preview-strength-divider}] :drawers [{:name :action-drawers - :options {:topBar {:visible true}} :component action-drawers/preview-action-drawers} {:name :documentation-drawer - :options {:topBar {:visible true}} :component documenation-drawers/preview-documenation-drawers} {:name :drawer-buttons - :options {:topBar {:visible true}} :component drawer-buttons/preview-drawer-buttons} {:name :permission-drawers - :options {:topBar {:visible true}} :component permission-drawers/preview-permission-drawers}] :dropdowns [{:name :dropdown - :options {:topBar {:visible true}} :component dropdown/preview-dropdown}] :empty-state [{:name :empty-state - :options {:topBar {:visible true}} :component empty-state/preview-empty-state}] :gradient [{:name :gradient-cover - :options {:topBar {:visible true}} :component gradient-cover/preview-gradient-cover}] :graph [{:name :wallet-graph - :options {:topBar {:visible true}} :component wallet-graph/preview-wallet-graph}] :info [{:name :info-message - :options {:topBar {:visible true}} :component info-message/preview-info-message} {:name :information-box - :options {:topBar {:visible true}} :component information-box/preview-information-box}] :inputs [{:name :input - :options {:topBar {:visible true}} :component input/preview-input} {:name :locked-input - :options {:topBar {:visible true}} :component locked-input/preview-locked-input} {:name :profile-input - :options {:topBar {:visible true}} :component profile-input/preview-profile-input} {:name :recovery-phrase-input - :options {:topBar {:visible true}} :component recovery-phrase-input/preview-recovery-phrase-input} {:name :search-input - :options {:topBar {:visible true}} :component search-input/preview-search-input} {:name :title-input - :options {:topBar {:visible true}} :component title-input/preview-title-input}] :numbered-keyboard [{:name :keyboard-key - :options {:insets {:top? true} - :topBar {:visible true}} + :options {:insets {:top? true}} :component keyboard-key/preview-keyboard-key} {:name :numbered-keyboard - :options {:insets {:top? true} - :topBar {:visible true}} + :options {:insets {:top? true}} :component numbered-keyboard/preview-numbered-keyboard}] :links [{:name :url-preview - :options {:insets {:top? true} - :topBar {:visible true}} - :component url-preview/preview} + :options {:insets {:top? true}} + :component url-preview/view} {:name :url-preview-list - :options {:insets {:top? true} - :topBar {:visible true}} - :component url-preview-list/preview} + :options {:insets {:top? true}} + :component url-preview-list/view} {:name :link-preview - :options {:insets {:top? true} - :topBar {:visible true}} - :component link-preview/preview}] + :options {:insets {:top? true}} + :component link-preview/view}] :list-items [{:name :account-list-card - :options {:topBar {:visible true}} :component account-list-card/preview} {:name :channel - :options {:topBar {:visible true}} :component channel/preview-channel} {:name :community-list - :options {:insets {:top? true} - :topBar {:visible true}} - :component community-list/preview} + :options {:insets {:top? true}} + :component community-list/view} {:name :preview-lists - :options {:topBar {:visible true}} :component preview-lists/preview-preview-lists} {:name :user-list - :options {:topBar {:visible true}} :component user-list/preview-user-list} {:name :token-value - :options {:topBar {:visible true}} :component token-value/preview}] :loaders [{:name :skeleton - :options {:topBar {:visible true}} :component skeleton/preview-skeleton}] :markdown [{:name :texts - :options {:topBar {:visible true}} :component text/preview-text} {:name :markdown-list - :options {:topBar {:visible true}} :component markdown-list/preview-markdown-list}] :messages [{:name :gap - :options {:topBar {:visible true}} :component messages-gap/preview-messages-gap} {:name :system-messages - :options {:topBar {:visible true}} :component system-message/preview-system-message} {:name :author - :options {:topBar {:visible true}} :component messages-author/preview-author}] :navigation [{:name :bottom-nav-tab - :options {:topBar {:visible true}} :component bottom-nav-tab/preview-bottom-nav-tab} {:name :top-nav - :options {:topBar {:visible true}} :component top-nav/preview-top-nav} {:name :page-nav - :options {:topBar {:visible true}} :component page-nav/preview-page-nav} {:name :floating-shell-button - :options {:topBar {:visible true}} :component floating-shell-button/preview-floating-shell-button}] :notifications [{:name :activity-logs - :options {:topBar {:visible true}} :component activity-logs/preview-activity-logs} {:name :activity-logs-photos - :options {:topBar {:visible true}} :component activity-logs-photos/preview-activity-logs-photos} {:name :toast - :options {:topBar {:visible true}} :component toast/preview-toasts} {:name :notification - :options {:topBar {:visible true}} :component notification/preview-notification}] :onboarding [{:name :small-option-card - :options {:topBar {:visible true}} :component small-option-card/preview-small-option-card}] :password [{:name :tips - :options {:topBar {:visible true}} :component tips/preview-tips}] :profile [{:name :profile-card - :options {:topBar {:visible true}} :component profile-card/preview-profile-card} {:name :collectible - :options {:topBar {:visible true}} :component collectible/preview-collectible} {:name :select-profile - :options {:topBar {:visible true}} :component select-profile/preview-select-profile}] :reactions [{:name :react - :options {:topBar {:visible true}} :component react/preview-react}] :record-audio [{:name :record-audio - :options {:topBar {:visible true}} :component record-audio/preview-record-audio}] :switcher [{:name :switcher-cards - :options {:topBar {:visible true}} :component switcher-cards/preview-switcher-cards}] :selectors [{:name :disclaimer - :options {:topBar {:visible true}} :component disclaimer/preview-disclaimer} {:name :filter - :options {:topBar {:visible true}} :component filter/preview} {:name :selectors - :options {:topBar {:visible true}} :component selectors/preview-selectors} {:name :select-reactions - :options {:topBar {:visible true}} :component selector-reactions/preview}] :settings [{:name :privacy-option - :options {:topBar {:visible true}} :component privacy-option/preview-options} {:name :accounts - :options {:topBar {:visible true}} :component accounts/preview-accounts} {:name :settings-list - :options {:topBar {:visible true}} :component settings-list/preview-settings-list} {:name :reorder-item - :options {:topBar {:visible true}} :component reorder-item/preview-reorder-item} {:name :category - :options {:topBar {:visible true}} :component category/preview}] :share [{:name :qr-code - :options {:topBar {:visible true}} :component qr-code/preview-qr-code} {:name :share-qr-code - :options {:topBar {:visible true}} :component share-qr-code/preview-share-qr-code}] :tabs [{:name :segmented - :options {:topBar {:visible true}} :component segmented/preview-segmented} {:name :tabs - :options {:topBar {:visible true}} :component tabs/preview-tabs} {:name :account-selector - :options {:topBar {:visible true}} :component account-selector/preview-this}] :tags [{:name :context-tags - :options {:topBar {:visible true}} :component context-tags/preview-context-tags} {:name :tags - :options {:topBar {:visible true}} :component tags/preview-tags} {:name :permission-tag - :options {:topBar {:visible true}} :component permission-tag/preview-permission-tag} {:name :status-tags - :options {:topBar {:visible true}} :component status-tags/preview-status-tags} {:name :token-tag - :options {:topBar {:visible true}} :component token-tag/preview-token-tag}] :text-combinations [{:name :title - :options {:topBar {:visible true}} :component title/preview-title}] :wallet [{:name :account-card - :options {:topBar {:visible true}} :component account-card/preview-account-card} {:name :account-overview - :options {:topBar {:visible true}} :component account-overview/preview-account-overview} {:name :network-amount - :options {:topBar {:visible true}} :component network-amount/preview} {:name :network-bridge - :options {:topBar {:visible true}} :component network-bridge/preview} {:name :progress-bar - :options {:topBar {:visible true}} :component progress-bar/preview} {:name :summary-info - :options {:topBar {:visible true}} :component summary-info/preview} {:name :token-input - :options {:topBar {:visible true}} :component token-input/preview} {:name :wallet-overview - :options {:topBar {:visible true}} :component wallet-overview/preview-wallet-overview}] :keycard [{:name :keycard-component - :options {:topBar {:visible true}} :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?]) has-profiles? (boolean (rf/sub [:profile/profiles-overview])) @@ -477,48 +366,51 @@ (theme/set-theme :dark) (rf/dispatch [:init-root root]))))}}])) -(defn theme-switcher +(defn- theme-switcher [] - [rn/view - {:style {:flex-direction :row - :justify-content :space-between - :padding-horizontal 24 - :padding-vertical 12}} + [rn/view {:style style/theme-switcher} [quo/button {:on-press #(theme/set-theme :light)} "Set light 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] [rn/view {:style {:margin-vertical 8}} - [quo/dropdown {:selected @open? :on-change #(swap! open? not) :type :grey} - (clojure.core/name (key category))] + [quo/dropdown + {:selected @open? + :on-change on-change + :type :grey} + (name (key category))] (when @open? - (for [{:keys [name]} (val category)] - ^{:key name} + (for [{category-name :name} (val category)] + ^{:key category-name} [quo/button {:type :outline :container-style {:margin-vertical 8} - :on-press #(rf/dispatch [:navigate-to name])} - (clojure.core/name name)]))]))) + :on-press #(rf/dispatch [:navigate-to category-name])} + (name category-name)]))]))) -(defn main-screen +(defn- main-screen [] - (fn [] - [:<> - [navigation-bar] - [theme-switcher] - [rn/scroll-view - {:flex 1 - :padding-bottom 8 - :padding-horizontal 16 - :background-color (colors/theme-colors colors/white colors/neutral-90)} - [rn/view - (map (fn [category] - ^{:key (get category 0)} - [category-view category]) - (sort screens-categories))]]])) + [:<> + [navigation-bar] + [theme-switcher] + [rn/scroll-view {:style (style/main)} + (for [category (sort screens-categories)] + ^{:key (first category)} + [category-view category])]]) + +(def screens + (->> screens-categories + (map val) + flatten + (map (fn [subcategory] + (update-in subcategory + [:options :topBar] + merge + {:visible true}))))) (def main-screens [{:name :quo2-preview diff --git a/src/status_im2/contexts/quo_preview/preview.cljs b/src/status_im2/contexts/quo_preview/preview.cljs index 5bd40231a2..050159f27f 100644 --- a/src/status_im2/contexts/quo_preview/preview.cljs +++ b/src/status_im2/contexts/quo_preview/preview.cljs @@ -1,216 +1,178 @@ (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.theme :as theme] + [quo2.theme :as quo.theme] [react-native.blur :as blur] [react-native.core :as rn] [reagent.core :as reagent] [status-im2.common.resources :as resources] + [status-im2.contexts.quo-preview.style :as style] utils.number) (:require-macros status-im2.contexts.quo-preview.preview)) -(def container - {: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 +(defn- label-view [_ label] - [rn/view {:style label-style} - [rn/text - (when-let [label-color (colors/theme-colors colors/neutral-100 colors/white)] - {:style {:color label-color}}) + [rn/view {:style style/label-container} + [rn/text {:style (style/label)} label]]) -(defn modal-container - [] - {:flex 1 - :justify-content :center - :padding-horizontal 24 - :background-color "rgba(0,0,0,0.4)"}) +(defn- humanize + [k] + ;; We explicitly convert `k` to string because sometimes it's a number and + ;; Clojure would throw an exception. + (-> (if (keyword? k) k (str k)) + camel-snake-kebab/->kebab-case-keyword + name + (string/replace "-" " ") + string/capitalize)) -(defn modal-view - [] - {:padding-horizontal 16 - :padding-vertical 8 - :border-radius 8 - :flex-direction :column - :margin-vertical 100 - :background-color (colors/theme-colors colors/neutral-20 colors/white)}) +(defn- key->boolean-label + [k] + (let [label (humanize k)] + (if (string/ends-with? label "?") + label + (str label "?")))) -(defn customizer-boolean +(defn- key->text-label + [k] + (str (humanize k) ":")) + +(defn- customizer-boolean [{:keys [label state] :as args}] - (let [state* (reagent/cursor state [(:key args)])] - [rn/view {:style container} + (let [label (or label (key->boolean-label (:key args))) + field-value (reagent/cursor state [(:key args)]) + active? @field-value] + [rn/view {:style style/field-row} [label-view state label] - [rn/view - {:style {:flex-direction :row - :flex 0.6 - :border-radius 4 - :background-color (colors/theme-colors colors/neutral-20 colors/white) - :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 + [rn/view {:style (style/boolean-container)} + [rn/pressable + {:style (style/boolean-button {:active? active? :left? true}) + :on-press #(reset! field-value true)} + [rn/text {:style (style/field-text active?)} "True"]] - [rn/view - {:width 1 - :margin-vertical 4 - :background-color (colors/theme-colors colors/neutral-20 colors/white)}] - [rn/touchable-opacity - {:style (merge (touchable-style) - {:background-color (when (not @state*) colors/primary-50-opa-30)}) - :on-press #(reset! state* false)} - [rn/text {} + [rn/pressable + {:style (style/boolean-button {:active? (not active?) :left? false}) + :on-press #(reset! field-value false)} + [rn/text {:style (style/field-text (not active?))} "False"]]]])) -(defn customizer-text +(defn- customizer-text [{:keys [label state limit suffix] :as args}] - (let [state* (reagent/cursor state [(:key args)])] - [rn/view {:style container} + (let [label (or label (key->text-label (:key args))) + field-value (reagent/cursor state [(:key args)])] + [rn/view {:style style/field-row} [label-view state label] - [rn/view {:style {:flex 0.6}} + [rn/view {:style style/field-column} [rn/text-input (merge - {:value @state* + {:value @field-value :show-cancel false - :style {:border-radius 4 - :border-width 1 - :color (colors/theme-colors colors/neutral-100 colors/white) - :border-color (colors/theme-colors colors/neutral-100 colors/white)} - :keyboard-appearance (theme/theme-value :light :dark) - :on-change-text #(do - (reset! state* (if (and suffix (> (count %) (count @state*))) - (str (string/replace % suffix "") suffix) - %)) - (reagent/flush))} + :style (style/field-container false) + :keyboard-appearance (quo.theme/theme-value :light :dark) + :on-change-text (fn [text] + (reset! field-value (if (and suffix + (> (count text) (count @field-value))) + (str (string/replace text suffix "") suffix) + text)) + (reagent/flush))} (when limit {:max-length limit}))]]])) -(defn customizer-number +(defn- customizer-number [{:keys [label state default] :as args}] - (let [state* (reagent/cursor state [(:key args)])] - [rn/view {:style container} + (let [label (or label (key->text-label (:key args))) + field-value (reagent/cursor state [(:key args)])] + [rn/view {:style style/field-row} [label-view state label] - [rn/view {:style {:flex 0.6}} + [rn/view {:style style/field-column} [rn/text-input (merge - {:value (str @state*) + {:value (str @field-value) :show-cancel false - :style {:border-radius 4 - :border-width 1 - :color (colors/theme-colors colors/neutral-100 colors/white) - :border-color (colors/theme-colors colors/neutral-100 colors/white)} - :keyboard-appearance (theme/theme-value :light :dark) - :on-change-text (fn [v] - (reset! state* (utils.number/parse-int v default)) + :style (style/field-container false) + :keyboard-appearance (quo.theme/theme-value :light :dark) + :on-change-text (fn [text] + (reset! field-value (utils.number/parse-int text default)) (reagent/flush))})]]])) -(defn value-for-key +(defn- find-selected-option [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)] (fn [{:keys [label state options] :as args}] - (let [state* (reagent/cursor state [(:key args)]) - selected (value-for-key @state* options)] - [rn/view {:style container} + (let [label (or label (key->text-label (:key args))) + field-value (reagent/cursor state [(:key args)]) + selected-key (:key (find-selected-option @field-value options))] + [rn/view {:style style/field-row} [label-view state label] - [rn/view {:style {:flex 0.6}} - [rn/modal - {:visible @open - :on-request-close #(reset! open false) - :statusBarTranslucent true - :transparent true - :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 "↓"]]]]])))) + [rn/view {:style style/field-column} + [customizer-select-modal + {:open open + :options options + :field-value field-value}] + [customizer-select-button {:open open :selected-key selected-key}]]])))) (defn customizer [state descriptors] [rn/view - {:style {:flex 1} - :padding-horizontal 16} + {:style {:flex-shrink 1 + :padding-horizontal 20}} (doall (for [desc descriptors :let [descriptor (merge desc {:state state})]] @@ -237,19 +199,6 @@ {:key k :value (string/capitalize (name k))})))} 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 [{:keys [show-blur-background? image height blur-view-props style]} children] [rn/view @@ -262,8 +211,7 @@ :overflow :hidden}} [rn/image {:source (or image (resources/get-mock-image :community-cover)) - :style {:height "100%" - :width "100%"}}] + :style {:height "100%" :width "100%"}}] [blur/view (merge {:style {:position :absolute :top 0 @@ -271,9 +219,7 @@ :left 0 :right 0} :blur-amount 10 - :overlay-color (colors/theme-colors - colors/white-opa-70 - colors/neutral-80-opa-80)} + :overlay-color (colors/theme-colors colors/white-opa-70 colors/neutral-80-opa-80)} blur-view-props)]]) [rn/view {:style (merge {:position :absolute @@ -281,3 +227,33 @@ :padding-horizontal 16} style)} 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)]]]) diff --git a/src/status_im2/contexts/quo_preview/style.cljs b/src/status_im2/contexts/quo_preview/style.cljs new file mode 100644 index 0000000000..8eca15d3e7 --- /dev/null +++ b/src/status_im2/contexts/quo_preview/style.cljs @@ -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})