mirror of
https://github.com/penpot/penpot.git
synced 2025-05-30 00:36:13 +02:00
✨ Optimize profile setup flow for better user experience (#6223)
* ✨ Optimize profile setup flow for better user experience * 📎 Remove extra onboarding step * 📎 Code review * 📎 Update changelog --------- Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
parent
aae81b8a04
commit
86a498fc29
15 changed files with 364 additions and 422 deletions
|
@ -167,7 +167,6 @@
|
|||
(and (contains? cf/flags :onboarding)
|
||||
(not (:onboarding-viewed props))
|
||||
(not (contains? props :onboarding-team-id))
|
||||
(contains? props :newsletter-updates)
|
||||
(:is-default team))
|
||||
|
||||
show-release-modal?
|
||||
|
@ -233,7 +232,7 @@
|
|||
[:& onboarding-newsletter]
|
||||
|
||||
show-team-modal?
|
||||
[:& onboarding-team-modal {:go-to-team? true}]
|
||||
[:& onboarding-team-modal {:go-to-team true}]
|
||||
|
||||
show-release-modal?
|
||||
[:& release-notes-modal {:version (:main cf/version)}])
|
||||
|
@ -259,11 +258,8 @@
|
|||
show-question-modal?
|
||||
[:& questions-modal]
|
||||
|
||||
show-newsletter-modal?
|
||||
[:& onboarding-newsletter]
|
||||
|
||||
show-team-modal?
|
||||
[:& onboarding-team-modal {:go-to-team? false}]
|
||||
[:& onboarding-team-modal {:go-to-team false}]
|
||||
|
||||
show-release-modal?
|
||||
[:& release-notes-modal {:version (:main cf/version)}]))
|
||||
|
|
|
@ -23,9 +23,11 @@
|
|||
{::mf/props :obj}
|
||||
[{:keys [route]}]
|
||||
(let [section (dm/get-in route [:data :name])
|
||||
show-login-icon (and
|
||||
(not= section :auth-register-validate)
|
||||
(not= section :auth-register-success))
|
||||
is-register (or
|
||||
(= section :auth-register)
|
||||
(= section :auth-register-validate)
|
||||
(= section :register-validate-page)
|
||||
(= section :auth-register-success))
|
||||
params (:query-params route)
|
||||
error (:error params)]
|
||||
|
||||
|
@ -36,10 +38,11 @@
|
|||
(when error
|
||||
(st/emit! (da/show-redirect-error error))))
|
||||
|
||||
[:main {:class (stl/css :auth-section)}
|
||||
(when show-login-icon
|
||||
[:h1 {:class (stl/css :logo-container)}
|
||||
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]])
|
||||
[:main {:class (stl/css-case
|
||||
:auth-section true
|
||||
:register is-register)}
|
||||
[:h1 {:class (stl/css :logo-container)}
|
||||
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]]
|
||||
[:div {:class (stl/css :login-illustration)}
|
||||
i/login-illustration]
|
||||
|
||||
|
@ -49,12 +52,12 @@
|
|||
:auth-register
|
||||
[:& register-page {:params params}]
|
||||
|
||||
:auth-register-validate
|
||||
[:& register-validate-page {:params params}]
|
||||
|
||||
:auth-register-success
|
||||
[:& register-success-page {:params params}]
|
||||
|
||||
:auth-register-validate
|
||||
[:& register-validate-page {:params params}]
|
||||
|
||||
:auth-login
|
||||
[:& login-page {:params params}]
|
||||
|
||||
|
|
|
@ -22,6 +22,16 @@
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.register {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.login-illustration {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
[app.main.ui.auth.login :as login]
|
||||
[app.main.ui.components.forms :as fm]
|
||||
[app.main.ui.components.link :as lk]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.storage :as storage]
|
||||
[beicon.v2.core :as rx]
|
||||
|
@ -26,11 +25,48 @@
|
|||
|
||||
;; --- PAGE: Register
|
||||
|
||||
(mf/defc newsletter-options*
|
||||
{::mf/private true}
|
||||
[]
|
||||
(let [updates-label
|
||||
(mf/html
|
||||
[:> i18n/tr-html*
|
||||
{:tag-name "div"
|
||||
:content (tr "onboarding-v2.newsletter.updates")}])]
|
||||
[:div {:class (stl/css :fields-row :input-visible :newsletter-option-wrapper)}
|
||||
[:& fm/input {:name :accept-newsletter-updates
|
||||
:type "checkbox"
|
||||
:default-checked false
|
||||
:label updates-label}]]))
|
||||
|
||||
(mf/defc terms-and-privacy
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[]
|
||||
(let [terms-label
|
||||
(mf/html
|
||||
[:> i18n/tr-html*
|
||||
{:tag-name "div"
|
||||
:content (tr "auth.terms-and-privacy-agreement"
|
||||
cf/terms-of-service-uri
|
||||
cf/privacy-policy-uri)}])]
|
||||
|
||||
[:div {:class (stl/css :fields-row :input-visible :accept-terms-and-privacy-wrapper)}
|
||||
[:& fm/input {:name :accept-terms-and-privacy
|
||||
:class (stl/css :checkbox-terms-and-privacy)
|
||||
:type "checkbox"
|
||||
:default-checked false
|
||||
:label terms-label}]]))
|
||||
|
||||
(def ^:private schema:register-form
|
||||
[:map {:title "RegisterForm"}
|
||||
[:password ::sm/password]
|
||||
[:fullname [::sm/text {:max 250}]]
|
||||
[:email ::sm/email]
|
||||
[:invitation-token {:optional true} ::sm/text]])
|
||||
[:accept-terms-and-privacy {:optional (not (contains? cf/flags :terms-and-privacy-checkbox))}
|
||||
[:and :boolean [:= true]]]
|
||||
[:accept-newsletter-updates {:optional true} :boolean]
|
||||
[:token {:optional true} ::sm/text]])
|
||||
|
||||
(mf/defc register-form
|
||||
{::mf/props :obj}
|
||||
|
@ -65,23 +101,59 @@
|
|||
|
||||
(st/emit! (ntf/error (tr "errors.generic")))))))
|
||||
|
||||
on-success
|
||||
(mf/use-fn
|
||||
(mf/deps on-success-callback)
|
||||
(fn [params]
|
||||
(if (fn? on-success-callback)
|
||||
(on-success-callback (:email params))
|
||||
|
||||
(cond
|
||||
(some? (:token params))
|
||||
(let [token (:token params)]
|
||||
(st/emit! (rt/nav :auth-verify-token {:token token})))
|
||||
|
||||
(:is-active params)
|
||||
(st/emit! (da/login-from-register))
|
||||
|
||||
:else
|
||||
(do
|
||||
(swap! storage/user assoc ::email (:email params))
|
||||
(st/emit! (rt/nav :auth-register-success)))))))
|
||||
|
||||
on-register-profile
|
||||
(mf/use-fn
|
||||
(mf/deps on-success on-error)
|
||||
(fn [form]
|
||||
(reset! submitted? true)
|
||||
(let [create-welcome-file?
|
||||
(cf/external-feature-flag "onboarding-03" "test")
|
||||
|
||||
params
|
||||
(cond-> form
|
||||
create-welcome-file? (assoc :create-welcome-file true))]
|
||||
(->> (rp/cmd! :register-profile params)
|
||||
(rx/subs! on-success on-error #(reset! submitted? false))))))
|
||||
|
||||
on-submit
|
||||
(mf/use-fn
|
||||
(mf/deps on-success-callback)
|
||||
(fn [form _event]
|
||||
(reset! submitted? true)
|
||||
(let [cdata (:clean-data @form)
|
||||
on-success (fn [data]
|
||||
(if (fn? on-success-callback)
|
||||
(on-success-callback data)
|
||||
(st/emit! (rt/nav :auth-register-validate data))))]
|
||||
|
||||
(let [cdata (:clean-data @form)]
|
||||
(->> (rp/cmd! :prepare-register-profile cdata)
|
||||
(rx/map #(merge % params))
|
||||
(rx/map #(merge % cdata))
|
||||
(rx/finalize #(reset! submitted? false))
|
||||
(rx/subs! on-success (partial on-error form))))))]
|
||||
(rx/subs! on-register-profile)))))]
|
||||
|
||||
[:& fm/form {:on-submit on-submit :form form}
|
||||
[:div {:class (stl/css :fields-row)}
|
||||
|
||||
[:& fm/input {:name :fullname
|
||||
:label (tr "auth.fullname")
|
||||
:type "text"
|
||||
:show-success? true
|
||||
:class (stl/css :form-field)}]]
|
||||
[:div {:class (stl/css :fields-row)}
|
||||
[:& fm/input {:type "text"
|
||||
:name :email
|
||||
|
@ -97,6 +169,11 @@
|
|||
:type "password"
|
||||
:class (stl/css :form-field)}]]
|
||||
|
||||
(when (contains? cf/flags :terms-and-privacy-checkbox)
|
||||
[:& terms-and-privacy])
|
||||
|
||||
[:> newsletter-options*]
|
||||
|
||||
[:> fm/submit-button*
|
||||
{:label (tr "auth.register-submit")
|
||||
:disabled @submitted?
|
||||
|
@ -120,8 +197,6 @@
|
|||
[:div {:class (stl/css :auth-form-wrapper :register-form)}
|
||||
[:h1 {:class (stl/css :auth-title)
|
||||
:data-testid "registration-title"} (tr "auth.register-title")]
|
||||
[:p {:class (stl/css :auth-tagline)}
|
||||
(tr "auth.register-tagline")]
|
||||
|
||||
(when (contains? cf/flags :demo-warning)
|
||||
[:& login/demo-warning])
|
||||
|
@ -144,26 +219,41 @@
|
|||
:class (stl/css :demo-account-link)}
|
||||
(tr "auth.create-demo-account")]]])]])
|
||||
|
||||
;; --- PAGE: register validation
|
||||
;; --- PAGE: register success page
|
||||
|
||||
(mf/defc terms-and-privacy
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
(mf/defc register-success-page
|
||||
{::mf/props :obj}
|
||||
[{:keys [params]}]
|
||||
(let [email (or (:email params) (::email storage/user))]
|
||||
[:div {:class (stl/css :auth-form-wrapper :register-success)}
|
||||
[:div {:class (stl/css :auth-title-wrapper)}
|
||||
[:h2 {:class (stl/css :auth-title)}
|
||||
(tr "auth.check-mail")]
|
||||
[:div {:class (stl/css :notification-text)} (tr "auth.verification-email-sent")]]
|
||||
[:div {:class (stl/css :notification-text-email)} email]]))
|
||||
|
||||
|
||||
(mf/defc terms-register
|
||||
[]
|
||||
(let [terms-label
|
||||
(mf/html
|
||||
[:> i18n/tr-html*
|
||||
{:tag-name "div"
|
||||
:content (tr "auth.terms-and-privacy-agreement"
|
||||
cf/terms-of-service-uri
|
||||
cf/privacy-policy-uri)}])]
|
||||
(let [show-all? (and cf/terms-of-service-uri cf/privacy-policy-uri)
|
||||
show-terms? (some? cf/terms-of-service-uri)
|
||||
show-privacy? (some? cf/privacy-policy-uri)]
|
||||
|
||||
[:div {:class (stl/css :fields-row :input-visible :accept-terms-and-privacy-wrapper)}
|
||||
[:& fm/input {:name :accept-terms-and-privacy
|
||||
:class (stl/css :checkbox-terms-and-privacy)
|
||||
:type "checkbox"
|
||||
:default-checked false
|
||||
:label terms-label}]]))
|
||||
(when show-all?
|
||||
[:div {:class (stl/css :terms-register)}
|
||||
(when show-terms?
|
||||
[:a {:href cf/terms-of-service-uri :target "_blank" :class (stl/css :auth-link)}
|
||||
(tr "auth.terms-of-service")])
|
||||
|
||||
(when show-all?
|
||||
[:span {:class (stl/css :and-text)}
|
||||
(dm/str " " (tr "labels.and") " ")])
|
||||
|
||||
(when show-privacy?
|
||||
[:a {:href cf/privacy-policy-uri :target "_blank" :class (stl/css :auth-link)}
|
||||
(tr "auth.privacy-policy")])])))
|
||||
|
||||
;; --- PAGE: register validation
|
||||
|
||||
(def ^:private schema:register-validate-form
|
||||
[:map {:title "RegisterValidateForm"}
|
||||
|
@ -245,9 +335,9 @@
|
|||
(mf/defc register-validate-page
|
||||
{::mf/props :obj}
|
||||
[{:keys [params]}]
|
||||
[:div {:class (stl/css :auth-form-wrapper)}
|
||||
[:h1 {:class (stl/css :logo-container)}
|
||||
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]]
|
||||
[:div {:class (stl/css :auth-form-wrapper :register-form)}
|
||||
|
||||
|
||||
[:div {:class (stl/css :auth-title-wrapper)}
|
||||
[:h2 {:class (stl/css :auth-title)
|
||||
:data-testid "register-title"} (tr "auth.register-account-title")]
|
||||
|
@ -260,40 +350,3 @@
|
|||
[:& lk/link {:action #(st/emit! (rt/nav :auth-register {}))
|
||||
:class (stl/css :go-back-link)}
|
||||
(tr "labels.go-back")]]]])
|
||||
|
||||
(mf/defc register-success-page
|
||||
{::mf/props :obj}
|
||||
[{:keys [params]}]
|
||||
(let [email (or (:email params) (::email storage/user))]
|
||||
[:div {:class (stl/css :auth-form-wrapper :register-success)}
|
||||
(when-not (:hide-logo params)
|
||||
[:h1 {:class (stl/css :logo-container)}
|
||||
[:a {:href "#/" :title "Penpot" :class (stl/css :logo-btn)} i/logo]])
|
||||
[:div {:class (stl/css :auth-title-wrapper)}
|
||||
[:h2 {:class (stl/css :auth-title)}
|
||||
(tr "auth.check-mail")]
|
||||
[:div {:class (stl/css :notification-text)} (tr "auth.verification-email-sent")]]
|
||||
[:div {:class (stl/css :notification-text-email)} email]
|
||||
[:div {:class (stl/css :notification-text)} (tr "auth.check-your-email")]]))
|
||||
|
||||
|
||||
(mf/defc terms-register
|
||||
[]
|
||||
(let [show-all? (and cf/terms-of-service-uri cf/privacy-policy-uri)
|
||||
show-terms? (some? cf/terms-of-service-uri)
|
||||
show-privacy? (some? cf/privacy-policy-uri)]
|
||||
|
||||
(when show-all?
|
||||
[:div {:class (stl/css :terms-register)}
|
||||
(when show-terms?
|
||||
[:a {:href cf/terms-of-service-uri :target "_blank" :class (stl/css :auth-link)}
|
||||
(tr "auth.terms-of-service")])
|
||||
|
||||
(when show-all?
|
||||
[:span {:class (stl/css :and-text)}
|
||||
(dm/str " " (tr "labels.and") " ")])
|
||||
|
||||
(when show-privacy?
|
||||
[:a {:href cf/privacy-policy-uri :target "_blank" :class (stl/css :auth-link)}
|
||||
(tr "auth.privacy-policy")])])))
|
||||
|
||||
|
|
|
@ -444,6 +444,8 @@
|
|||
error (get-in @form [:errors input-name])
|
||||
focus? (mf/use-state false)
|
||||
|
||||
auto-focus? (get props :auto-focus? false)
|
||||
|
||||
items (mf/use-state
|
||||
(fn []
|
||||
(let [initial (get-in @form [:data input-name])]
|
||||
|
@ -562,7 +564,7 @@
|
|||
[:input {:id (name input-name)
|
||||
:class in-klass
|
||||
:type "text"
|
||||
:auto-focus true
|
||||
:auto-focus auto-focus?
|
||||
:on-focus on-focus
|
||||
:on-blur on-blur
|
||||
:on-key-down on-key-down
|
||||
|
|
|
@ -293,7 +293,6 @@
|
|||
border-radius: $br-8;
|
||||
color: var(--input-foreground-color-active);
|
||||
background-color: var(--input-background-color);
|
||||
border: $s-1 solid var(--input-border-color-active);
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: $s-1 solid var(--input-border-color-focus);
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
[:& fm/form {:form form
|
||||
:on-submit on-next*
|
||||
:class (dm/str class " " (stl/css :form-wrapper))}
|
||||
[:div {:class (stl/css :paginator)} (str/ffmt "%/5" step)]
|
||||
|
||||
children
|
||||
|
||||
|
@ -51,7 +50,7 @@
|
|||
(tr "labels.previous")])
|
||||
|
||||
[:> fm/submit-button*
|
||||
{:label (if (< step 5)
|
||||
{:label (if (< step 4)
|
||||
(tr "labels.next")
|
||||
(tr "labels.start"))
|
||||
:class (stl/css :next-button)}]]]))
|
||||
|
@ -60,47 +59,41 @@
|
|||
[:and
|
||||
|
||||
[:map {:title "QuestionsFormStep1"}
|
||||
[:planning ::sm/text]
|
||||
[:expected-use [:enum "work" "education" "personal"]]
|
||||
[:planning-other {:optional true}
|
||||
[::sm/text {:max 512}]]]
|
||||
[:role
|
||||
[:enum "ux" "developer" "student-teacher" "designer" "marketing" "manager" "other"]]
|
||||
[:role-other {:optional true} [::sm/text {:max 512}]]]
|
||||
|
||||
[:fn {:error/field :planning-other}
|
||||
(fn [{:keys [planning planning-other]}]
|
||||
(or (not= planning "other")
|
||||
(and (= planning "other")
|
||||
(not (str/blank? planning-other)))))]])
|
||||
[:fn {:error/field :role-other}
|
||||
(fn [{:keys [role role-other]}]
|
||||
(or (not= role "other")
|
||||
(and (= role "other")
|
||||
(not (str/blank? role-other)))))]])
|
||||
|
||||
(mf/defc step-1
|
||||
{::mf/props :obj}
|
||||
[{:keys [on-next form]}]
|
||||
[{:keys [on-next form show-step-3]}]
|
||||
(let [use-options
|
||||
(mf/with-memo []
|
||||
(shuffle [{:label (tr "onboarding.questions.use.work") :value "work"}
|
||||
{:label (tr "onboarding.questions.use.education") :value "education"}
|
||||
{:label (tr "onboarding.questions.use.personal") :value "personal"}]))
|
||||
|
||||
planning-options
|
||||
role-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "labels.select-option")
|
||||
:value "" :key "questions:what-brings-you-here"
|
||||
:disabled true}
|
||||
{:label (tr "onboarding.questions.reasons.exploring")
|
||||
:value "discover-more-about-penpot"
|
||||
:key "discover-more-about-penpot"}
|
||||
{:label (tr "onboarding.questions.reasons.fit")
|
||||
:value "test-penpot-to-see-if-its-a-fit-for-team"
|
||||
:key "test-penpot-to-see-if-its-a-fit-for-team"}
|
||||
{:label (tr "onboarding.questions.reasons.alternative")
|
||||
:value "alternative-to-figma"
|
||||
:key "alternative-to-figma"}
|
||||
{:label (tr "onboarding.questions.reasons.testing")
|
||||
:value "try-out-before-using-penpot-on-premise"
|
||||
:key "try-out-before-using-penpot-on-premise"}])
|
||||
(-> (shuffle [{:label (tr "labels.select-option") :value "" :key "role" :disabled true}
|
||||
{:label (tr "labels.product-design") :value "ux" :key "ux"}
|
||||
{:label (tr "labels.developer") :value "developer" :key "developer"}
|
||||
{:label (tr "labels.student-teacher") :value "student-teacher" :key "student"}
|
||||
{:label (tr "labels.graphic-design") :value "designer" :key "design"}
|
||||
{:label (tr "labels.marketing") :value "marketing" :key "marketing"}
|
||||
{:label (tr "labels.product-management") :value "manager" :key "manager"}])
|
||||
(conj {:label (tr "labels.other-short") :value "other"})))
|
||||
|
||||
current-planning
|
||||
(dm/get-in @form [:data :planning])]
|
||||
|
||||
current-role
|
||||
(dm/get-in @form [:data :role])]
|
||||
|
||||
|
||||
[:& step-container {:form form
|
||||
:step 1
|
||||
|
@ -108,6 +101,8 @@
|
|||
:on-next on-next
|
||||
:class (stl/css :step-1)}
|
||||
|
||||
[:div {:class (stl/css :paginator)} (str/ffmt "1/%" (if @show-step-3 4 3))]
|
||||
|
||||
[:img {:class (stl/css :header-image)
|
||||
:src "images/form/use-for-1.png"
|
||||
:alt (tr "onboarding.questions.lets-get-started")}]
|
||||
|
@ -124,18 +119,14 @@
|
|||
:name :expected-use
|
||||
:class (stl/css :radio-btns)}]
|
||||
|
||||
[:h3 {:class (stl/css :modal-subtitle)}
|
||||
(tr "onboarding.questions.step1.question2")]
|
||||
[:h3 {:class (stl/css :modal-subtitle)} (tr "onboarding.questions.step3.question1")]
|
||||
[:& fm/select {:options role-options
|
||||
:select-class (stl/css :select-class)
|
||||
:default ""
|
||||
:name :role}]
|
||||
|
||||
[:& fm/select
|
||||
{:options planning-options
|
||||
:select-class (stl/css :select-class)
|
||||
:default ""
|
||||
:name :planning
|
||||
:dropdown-class (stl/css :question-dropdown)}]
|
||||
|
||||
(when (= current-planning "other")
|
||||
[:& fm/input {:name :planning-other
|
||||
(when (= current-role "other")
|
||||
[:& fm/input {:name :role-other
|
||||
:class (stl/css :input-spacing)
|
||||
:placeholder (tr "labels.other")
|
||||
:show-error false
|
||||
|
@ -159,7 +150,7 @@
|
|||
|
||||
(mf/defc step-2
|
||||
{::mf/props :obj}
|
||||
[{:keys [on-next on-prev form]}]
|
||||
[{:keys [on-next on-prev form show-step-3]}]
|
||||
(let [design-tool-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "labels.figma") :img-width "48px" :img-height "60px"
|
||||
|
@ -192,6 +183,9 @@
|
|||
:on-prev on-prev
|
||||
:class (stl/css :step-2)}
|
||||
|
||||
[:div {:class (stl/css :paginator)} (str/ffmt "2/%" (if @show-step-3 4 3))]
|
||||
|
||||
|
||||
[:h1 {:class (stl/css :modal-title)}
|
||||
(tr "onboarding.questions.step2.title")]
|
||||
[:div {:class (stl/css :radio-wrapper)}
|
||||
|
@ -216,51 +210,22 @@
|
|||
[:map {:title "QuestionsFormStep3"}
|
||||
[:team-size
|
||||
[:enum "more-than-50" "31-50" "11-30" "2-10" "freelancer" "personal-project"]]
|
||||
[:role
|
||||
[:enum "ux" "developer" "student-teacher" "designer" "marketing" "manager" "other"]]
|
||||
[:responsability
|
||||
[:enum "team-leader" "team-member" "freelancer" "ceo-founder" "director" "other"]]
|
||||
|
||||
[:role-other {:optional true} [::sm/text {:max 512}]]
|
||||
[:responsability-other {:optional true} [::sm/text {:max 512}]]]
|
||||
[:planning ::sm/text]
|
||||
|
||||
[:fn {:error/field :role-other}
|
||||
(fn [{:keys [role role-other]}]
|
||||
(or (not= role "other")
|
||||
(and (= role "other")
|
||||
(not (str/blank? role-other)))))]
|
||||
[:planning-other {:optional true}
|
||||
[::sm/text {:max 512}]]]
|
||||
|
||||
[:fn {:error/field :responsability-other}
|
||||
(fn [{:keys [responsability responsability-other]}]
|
||||
(or (not= responsability "other")
|
||||
(and (= responsability "other")
|
||||
(not (str/blank? responsability-other)))))]])
|
||||
[:fn {:error/field :planning-other}
|
||||
(fn [{:keys [planning planning-other]}]
|
||||
(or (not= planning "other")
|
||||
(and (= planning "other")
|
||||
(not (str/blank? planning-other)))))]])
|
||||
|
||||
(mf/defc step-3
|
||||
{::mf/props :obj}
|
||||
[{:keys [on-next on-prev form]}]
|
||||
(let [role-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "labels.select-option") :value "" :key "role" :disabled true}
|
||||
{:label (tr "labels.product-design") :value "ux" :key "ux"}
|
||||
{:label (tr "labels.developer") :value "developer" :key "developer"}
|
||||
{:label (tr "labels.student-teacher") :value "student-teacher" :key "student"}
|
||||
{:label (tr "labels.graphic-design") :value "designer" :key "design"}
|
||||
{:label (tr "labels.marketing") :value "marketing" :key "marketing"}
|
||||
{:label (tr "labels.product-management") :value "manager" :key "manager"}])
|
||||
(conj {:label (tr "labels.other-short") :value "other"})))
|
||||
|
||||
responsability-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "labels.select-option") :value "" :key "responsability" :disabled true}
|
||||
{:label (tr "labels.team-leader") :value "team-leader"}
|
||||
{:label (tr "labels.team-member") :value "team-member"}
|
||||
{:label (tr "labels.freelancer") :value "freelancer"}
|
||||
{:label (tr "labels.founder") :value "ceo-founder"}
|
||||
{:label (tr "labels.director") :value "director"}])
|
||||
(conj {:label (tr "labels.other-short") :value "other"})))
|
||||
|
||||
team-size-options
|
||||
[{:keys [on-next on-prev form show-step-3]}]
|
||||
(let [team-size-options
|
||||
(mf/with-memo []
|
||||
[{:label (tr "labels.select-option") :value "" :key "team-size" :disabled true}
|
||||
{:label (tr "onboarding.questions.team-size.more-than-50") :value "more-than-50" :key "more-than-50"}
|
||||
|
@ -270,11 +235,27 @@
|
|||
{:label (tr "onboarding.questions.team-size.freelancer") :value "freelancer" :key "freelancer"}
|
||||
{:label (tr "onboarding.questions.team-size.personal-project") :value "personal-project" :key "personal-project"}])
|
||||
|
||||
current-role
|
||||
(dm/get-in @form [:data :role])
|
||||
planning-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "labels.select-option")
|
||||
:value "" :key "questions:what-brings-you-here"
|
||||
:disabled true}
|
||||
{:label (tr "onboarding.questions.reasons.exploring")
|
||||
:value "discover-more-about-penpot"
|
||||
:key "discover-more-about-penpot"}
|
||||
{:label (tr "onboarding.questions.reasons.fit")
|
||||
:value "test-penpot-to-see-if-its-a-fit-for-team"
|
||||
:key "test-penpot-to-see-if-its-a-fit-for-team"}
|
||||
{:label (tr "onboarding.questions.reasons.alternative")
|
||||
:value "alternative-to-figma"
|
||||
:key "alternative-to-figma"}
|
||||
{:label (tr "onboarding.questions.reasons.testing")
|
||||
:value "try-out-before-using-penpot-on-premise"
|
||||
:key "try-out-before-using-penpot-on-premise"}])
|
||||
(conj {:label (tr "labels.other-short") :value "other"})))
|
||||
|
||||
current-responsability
|
||||
(dm/get-in @form [:data :responsability])]
|
||||
current-planning
|
||||
(dm/get-in @form [:data :planning])]
|
||||
|
||||
[:& step-container {:form form
|
||||
:step 3
|
||||
|
@ -283,35 +264,27 @@
|
|||
:on-prev on-prev
|
||||
:class (stl/css :step-3)}
|
||||
|
||||
[:div {:class (stl/css :paginator)} (str/ffmt "3/%" (if @show-step-3 4 3))]
|
||||
|
||||
[:h1 {:class (stl/css :modal-title)}
|
||||
(tr "onboarding.questions.step3.title")]
|
||||
[:div {:class (stl/css :modal-question)}
|
||||
[:h3 {:class (stl/css :modal-subtitle)} (tr "onboarding.questions.step3.question1")]
|
||||
[:& fm/select {:options role-options
|
||||
:select-class (stl/css :select-class)
|
||||
:default ""
|
||||
:name :role}]
|
||||
[:h3 {:class (stl/css :modal-subtitle)}
|
||||
(tr "onboarding.questions.step1.question2")]
|
||||
|
||||
(when (= current-role "other")
|
||||
[:& fm/input {:name :role-other
|
||||
:class (stl/css :input-spacing)
|
||||
:placeholder (tr "labels.other")
|
||||
:show-error false
|
||||
:label ""}])]
|
||||
[:& fm/select
|
||||
{:options planning-options
|
||||
:select-class (stl/css :select-class)
|
||||
:default ""
|
||||
:name :planning
|
||||
:dropdown-class (stl/css :question-dropdown)}]]
|
||||
|
||||
[:div {:class (stl/css :modal-question)}
|
||||
[:h3 {:class (stl/css :modal-subtitle)} (tr "onboarding.questions.step3.question2")]
|
||||
[:& fm/select {:options responsability-options
|
||||
:select-class (stl/css :select-class)
|
||||
:default ""
|
||||
:name :responsability}]
|
||||
|
||||
(when (= current-responsability "other")
|
||||
[:& fm/input {:name :responsability-other
|
||||
:class (stl/css :input-spacing)
|
||||
:placeholder (tr "labels.other")
|
||||
:show-error false
|
||||
:label ""}])]
|
||||
(when (= current-planning "other")
|
||||
[:& fm/input {:name :planning-other
|
||||
:class (stl/css :input-spacing)
|
||||
:placeholder (tr "labels.other")
|
||||
:show-error false
|
||||
:label ""}])
|
||||
|
||||
[:div {:class (stl/css :modal-question)}
|
||||
[:h3 {:class (stl/css :modal-subtitle)} (tr "onboarding.questions.step3.question3")]
|
||||
|
@ -335,7 +308,7 @@
|
|||
|
||||
(mf/defc step-4
|
||||
{::mf/props :obj}
|
||||
[{:keys [on-next on-prev form]}]
|
||||
[{:keys [on-next on-prev form show-step-3]}]
|
||||
(let [start-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "onboarding.questions.start-with.ui")
|
||||
|
@ -367,6 +340,8 @@
|
|||
:on-prev on-prev
|
||||
:class (stl/css :step-4)}
|
||||
|
||||
[:div {:class (stl/css :paginator)} (str/ffmt "%/%" (if @show-step-3 4 3) (if @show-step-3 4 3))]
|
||||
|
||||
[:h1 {:class (stl/css :modal-title)} (tr "onboarding.questions.step4.title")]
|
||||
[:div {:class (stl/css :radio-wrapper)}
|
||||
[:& fm/image-radio-buttons {:options start-options
|
||||
|
@ -382,67 +357,14 @@
|
|||
:show-error false
|
||||
:placeholder (tr "labels.other")}])]]))
|
||||
|
||||
(def ^:private schema:questions-form-5
|
||||
[:and
|
||||
[:map {:title "QuestionsFormStep5"}
|
||||
[:referer
|
||||
[:enum "youtube" "event" "search" "social" "article" "other"]]
|
||||
[:referer-other {:optional true} [::sm/text {:max 512}]]]
|
||||
|
||||
[:fn {:error/field :referer-other}
|
||||
(fn [{:keys [referer referer-other]}]
|
||||
(or (not= referer "other")
|
||||
(and (= referer "other")
|
||||
(not (str/blank? referer-other)))))]])
|
||||
|
||||
(mf/defc step-5
|
||||
{::mf/props :obj}
|
||||
[{:keys [on-next on-prev form]}]
|
||||
(let [referer-options
|
||||
(mf/with-memo []
|
||||
(-> (shuffle [{:label (tr "labels.youtube") :value "youtube"}
|
||||
{:label (tr "labels.event") :value "event"}
|
||||
{:label (tr "onboarding.questions.referer.search") :value "search"}
|
||||
{:label (tr "onboarding.questions.referer.social") :value "social"}
|
||||
{:label (tr "onboarding.questions.referer.article") :value "article"}])
|
||||
(conj {:label (tr "labels.other-short") :value "other"})))
|
||||
|
||||
current-referer
|
||||
(dm/get-in @form [:data :referer])
|
||||
|
||||
on-referer-change
|
||||
(mf/use-fn
|
||||
(mf/deps current-referer)
|
||||
(fn []
|
||||
(when (not= current-referer "other")
|
||||
(swap! form d/dissoc-in [:data :referer-other])
|
||||
(swap! form d/dissoc-in [:errors :referer-other]))))]
|
||||
|
||||
[:& step-container {:form form
|
||||
:step 5
|
||||
:label "questions:referer"
|
||||
:on-next on-next
|
||||
:on-prev on-prev
|
||||
:class (stl/css :step-5)}
|
||||
|
||||
[:h1 {:class (stl/css :modal-title)} (tr "onboarding.questions.step5.title")]
|
||||
[:div {:class (stl/css :radio-wrapper)}
|
||||
[:& fm/radio-buttons {:options referer-options
|
||||
:class (stl/css :radio-btns)
|
||||
:name :referer
|
||||
:on-change on-referer-change}]
|
||||
(when (= current-referer "other")
|
||||
[:& fm/input {:name :referer-other
|
||||
:class (stl/css :input-spacing)
|
||||
:label ""
|
||||
:show-error false
|
||||
:placeholder (tr "labels.other")}])]]))
|
||||
|
||||
(mf/defc questions-modal
|
||||
[]
|
||||
(let [container (mf/use-ref)
|
||||
step (mf/use-state 1)
|
||||
clean-data (mf/use-state {})
|
||||
show-step-3 (mf/use-state false)
|
||||
|
||||
;; Forms are initialized here because we can go back and forth between the steps
|
||||
;; and we want to keep the filled info
|
||||
|
@ -462,13 +384,13 @@
|
|||
:initial {}
|
||||
:schema schema:questions-form-4)
|
||||
|
||||
step-5-form (fm/use-form
|
||||
:initial {}
|
||||
:schema schema:questions-form-5)
|
||||
|
||||
on-next
|
||||
(mf/use-fn
|
||||
(fn [form]
|
||||
(when (:expected-use (:clean-data @form))
|
||||
(if (= (:expected-use (:clean-data @form)) "work")
|
||||
(reset! show-step-3 true)
|
||||
(reset! show-step-3 false)))
|
||||
(swap! step inc)
|
||||
(swap! clean-data merge (:clean-data @form))))
|
||||
|
||||
|
@ -491,8 +413,10 @@
|
|||
:ref container}
|
||||
|
||||
(case @step
|
||||
1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form}]
|
||||
2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form}]
|
||||
3 [:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form}]
|
||||
4 [:& step-4 {:on-next on-next :on-prev on-prev :form step-4-form}]
|
||||
5 [:& step-5 {:on-next on-submit :on-prev on-prev :form step-5-form}])]]))
|
||||
1 [:& step-1 {:on-next on-next :on-prev on-prev :form step-1-form :show-step-3 show-step-3}]
|
||||
2 [:& step-2 {:on-next on-next :on-prev on-prev :form step-2-form :show-step-3 show-step-3}]
|
||||
3 (if @show-step-3
|
||||
[:& step-3 {:on-next on-next :on-prev on-prev :form step-3-form :show-step-3 show-step-3}]
|
||||
[:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form :show-step-3 show-step-3}])
|
||||
(when @show-step-3
|
||||
4 [:& step-4 {:on-next on-submit :on-prev on-prev :form step-4-form :show-step-3 show-step-3}]))]]))
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.onboarding.team-choice
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.schema :as sm]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
|
@ -26,8 +25,6 @@
|
|||
::mf/private true}
|
||||
[]
|
||||
[:div {:class (stl/css :modal-left)}
|
||||
[:h1 {:class (stl/css :modal-title)}
|
||||
(tr "onboarding-v2.welcome.title")]
|
||||
[:h2 {:class (stl/css :modal-subtitle)}
|
||||
(tr "onboarding.team-modal.team-definition")]
|
||||
[:p {:class (stl/css :modal-text)}
|
||||
|
@ -54,27 +51,30 @@
|
|||
[:p {:class (stl/css :modal-desc)}
|
||||
(tr "onboarding.team-modal.create-team-feature-5")]]]])
|
||||
|
||||
(def ^:private schema:invite-form
|
||||
[:map {:title "InviteForm"}
|
||||
[:role :keyword]
|
||||
[:emails {:optional true} [::sm/set ::sm/email]]])
|
||||
|
||||
(defn- get-available-roles
|
||||
[]
|
||||
[{:value "viewer" :label (tr "labels.viewer")}
|
||||
{:value "editor" :label (tr "labels.editor")}
|
||||
{:value "admin" :label (tr "labels.admin")}])
|
||||
|
||||
(mf/defc team-form-step-2
|
||||
{::mf/props :obj}
|
||||
[{:keys [name on-back go-to-team?]}]
|
||||
(let [initial (mf/with-memo []
|
||||
{:role "editor" :name name})
|
||||
(def ^:private schema:team-form
|
||||
[:map {:title "TeamForm"}
|
||||
[:name [::sm/text {:max 250}]]
|
||||
[:role :keyword]
|
||||
[:emails {:optional true} [::sm/set ::sm/email]]])
|
||||
|
||||
form (fm/use-form :schema schema:invite-form
|
||||
:initial initial)
|
||||
(mf/defc team-form
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [go-to-team]}]
|
||||
(let [initial (mf/with-memo []
|
||||
{:role "editor"})
|
||||
|
||||
form (fm/use-form :schema schema:team-form
|
||||
:initial initial)
|
||||
|
||||
roles (mf/use-memo get-available-roles)
|
||||
|
||||
error* (mf/use-state nil)
|
||||
|
||||
on-success
|
||||
|
@ -83,7 +83,8 @@
|
|||
(let [team-id (:id response)]
|
||||
(st/emit! (du/update-profile-props {:onboarding-team-id team-id
|
||||
:onboarding-viewed true})
|
||||
(when go-to-team?
|
||||
(println go-to-team)
|
||||
(when go-to-team
|
||||
(dcm/go-to-dashboard-recent :team-id team-id))))))
|
||||
|
||||
on-error
|
||||
|
@ -145,81 +146,14 @@
|
|||
(ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-finish"})))))
|
||||
|
||||
on-submit
|
||||
on-submit*
|
||||
(mf/use-fn
|
||||
(fn [form]
|
||||
(let [params (:clean-data @form)
|
||||
emails (:emails params)]
|
||||
(if (> (count emails) 0)
|
||||
(on-invite-now params)
|
||||
(on-invite-later params)))))]
|
||||
|
||||
[:*
|
||||
[:div {:class (stl/css :modal-right-invitations)}
|
||||
[:h2 {:class (stl/css :modal-subtitle)} (tr "onboarding.choice.team-up.invite-members")]
|
||||
[:p {:class (stl/css :modal-text)} (tr "onboarding.choice.team-up.invite-members-info")]
|
||||
[:& fm/form {:form form
|
||||
:class (stl/css :modal-form-invitations)
|
||||
:on-submit on-submit}
|
||||
|
||||
(when-let [content (deref error*)]
|
||||
[:& context-notification {:content content :level :error}])
|
||||
|
||||
[:div {:class (stl/css :role-select)}
|
||||
[:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")]
|
||||
[:& fm/select {:name :role :options roles}]]
|
||||
|
||||
[:div {:class (stl/css :invitation-row)}
|
||||
[:& fm/multi-input {:type "email"
|
||||
:name :emails
|
||||
:auto-focus? true
|
||||
:trim true
|
||||
:valid-item-fn sm/parse-email
|
||||
:caution-item-fn #{}
|
||||
:label (tr "modals.invite-member.emails")
|
||||
;; :on-submit on-submit
|
||||
}]]
|
||||
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
[:button {:class (stl/css :back-button)
|
||||
:on-click on-back}
|
||||
(tr "labels.back")]
|
||||
|
||||
(let [params (:clean-data @form)
|
||||
emails (:emails params)]
|
||||
[:> fm/submit-button*
|
||||
{:class (stl/css :accept-button)
|
||||
:label (if (> (count emails) 0)
|
||||
(tr "onboarding.choice.team-up.create-team-and-invite")
|
||||
(tr "onboarding.choice.team-up.create-team-without-invite"))}])]
|
||||
|
||||
[:div {:class (stl/css :modal-hint)}
|
||||
"(" (tr "onboarding.choice.team-up.create-team-and-send-invites-description") ")"]]]
|
||||
|
||||
|
||||
[:div {:class (stl/css :paginator)} "2/2"]]))
|
||||
|
||||
(def ^:private schema:team-form
|
||||
[:map {:title "TeamForm"}
|
||||
[:name [::sm/text {:max 250}]]])
|
||||
|
||||
(mf/defc team-form-step-1
|
||||
{::mf/props :obj
|
||||
::mf/private true}
|
||||
[{:keys [on-submit]}]
|
||||
(let [form (fm/use-form :schema schema:team-form
|
||||
:initial {})
|
||||
|
||||
on-submit*
|
||||
(mf/use-fn
|
||||
(fn [form]
|
||||
(let [name (dm/get-in @form [:clean-data :name])]
|
||||
|
||||
(st/emit! (ptk/data-event ::ev/event
|
||||
{::ev/name "onboarding-step"
|
||||
:label "team:choice-team-name"
|
||||
:step 7}))
|
||||
(on-submit name))))
|
||||
(on-invite-later params)))))
|
||||
|
||||
on-skip
|
||||
(mf/use-fn
|
||||
|
@ -234,24 +168,56 @@
|
|||
[:*
|
||||
[:div {:class (stl/css :modal-right)}
|
||||
[:div {:class (stl/css :first-block)}
|
||||
[:h2 {:class (stl/css :modal-subtitle)}
|
||||
(tr "onboarding.team-modal.create-team")]
|
||||
[:p {:class (stl/css :modal-text)}
|
||||
(tr "onboarding.choice.team-up.create-team-desc")]
|
||||
[:& fm/form {:form form
|
||||
:class (stl/css :modal-form)
|
||||
:on-submit on-submit*}
|
||||
[:h2 {:class (stl/css :modal-subtitle)}
|
||||
(tr "onboarding.team-modal.create-team")]
|
||||
[:p {:class (stl/css :modal-text)}
|
||||
(tr "onboarding.choice.team-up.create-team-desc")]
|
||||
|
||||
|
||||
[:& fm/input {:type "text"
|
||||
:class (stl/css :team-name-input)
|
||||
:name :name
|
||||
:auto-focus? true
|
||||
:placeholder "Team name"
|
||||
:label (tr "onboarding.choice.team-up.create-team-placeholder")}]
|
||||
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
[:> fm/submit-button*
|
||||
{:class (stl/css :accept-button)
|
||||
:label (tr "onboarding.choice.team-up.continue-creating-team")}]]]]
|
||||
[:h2 {:class (stl/css :modal-subtitle :invite-subtitle)} (tr "onboarding.choice.team-up.invite-members")]
|
||||
[:p {:class (stl/css :modal-text)} (tr "onboarding.choice.team-up.invite-members-info")]
|
||||
|
||||
(when-let [content (deref error*)]
|
||||
[:& context-notification {:content content :level :error}])
|
||||
|
||||
[:div {:class (stl/css :role-select)}
|
||||
[:p {:class (stl/css :role-title)} (tr "onboarding.choice.team-up.roles")]
|
||||
[:& fm/select {:name :role :options roles}]]
|
||||
|
||||
[:div {:class (stl/css :invitation-row)}
|
||||
[:& fm/multi-input {:type "email"
|
||||
:name :emails
|
||||
:trim true
|
||||
:valid-item-fn sm/parse-email
|
||||
:caution-item-fn #{}
|
||||
:label (tr "modals.invite-member.emails")}]]
|
||||
|
||||
|
||||
(let [params (:clean-data @form)
|
||||
emails (:emails params)]
|
||||
[:*
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
|
||||
[:> fm/submit-button*
|
||||
{:class (stl/css :accept-button)
|
||||
:label (if (> (count emails) 0)
|
||||
(tr "onboarding.choice.team-up.create-team-and-invite")
|
||||
(tr "onboarding.choice.team-up.create-team-without-invite"))}]]
|
||||
|
||||
(when (= (count emails) 0)
|
||||
[:> :div {:class (stl/css :modal-hint)}
|
||||
"(" (tr "onboarding.choice.team-up.create-team-and-send-invites-description") ")"])])]]
|
||||
|
||||
[:div {:class (stl/css :second-block)}
|
||||
[:h2 {:class (stl/css :modal-subtitle)}
|
||||
(tr "onboarding.choice.team-up.start-without-a-team")]
|
||||
|
@ -261,34 +227,20 @@
|
|||
[:div {:class (stl/css :action-buttons)}
|
||||
[:button {:class (stl/css :accept-button)
|
||||
:on-click on-skip}
|
||||
(tr "onboarding.choice.team-up.continue-without-a-team")]]]]
|
||||
|
||||
[:div {:class (stl/css :paginator)} "1/2"]]))
|
||||
(tr "onboarding.choice.team-up.continue-without-a-team")]]]]]))
|
||||
|
||||
(mf/defc onboarding-team-modal
|
||||
{::mf/props :obj}
|
||||
[{:keys [go-to-team?]}]
|
||||
(let [name* (mf/use-state nil)
|
||||
name (deref name*)
|
||||
[{:keys [go-to-team]}]
|
||||
|
||||
on-submit
|
||||
(mf/use-fn
|
||||
(fn [tname]
|
||||
(swap! name* (constantly tname))))
|
||||
[:div {:class (stl/css-case
|
||||
:modal-overlay true)}
|
||||
|
||||
|
||||
on-back
|
||||
(mf/use-fn
|
||||
(fn []
|
||||
(swap! name* (constantly nil))))]
|
||||
|
||||
[:div {:class (stl/css-case
|
||||
:modal-overlay true)}
|
||||
|
||||
[:div.animated.fadeIn {:class (stl/css :modal-container)}
|
||||
[:& left-sidebar]
|
||||
[:div {:class (stl/css :separator)}]
|
||||
(if name
|
||||
[:& team-form-step-2 {:name name :on-back on-back :go-to-team? go-to-team?}]
|
||||
[:& team-form-step-1 {:on-submit on-submit}])]]))
|
||||
[:div.animated.fadeIn {:class (stl/css :modal-container)}
|
||||
[:h1 {:class (stl/css :modal-title)}
|
||||
(tr "onboarding-v2.welcome.title")]
|
||||
[:div {:class (stl/css :modal-sections)}
|
||||
[:& left-sidebar]
|
||||
[:div {:class (stl/css :separator)}]
|
||||
[:& team-form {:go-to-team go-to-team}]]]])
|
||||
|
||||
|
|
|
@ -12,17 +12,26 @@
|
|||
|
||||
.modal-container {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr $s-32 1fr;
|
||||
gap: $s-24;
|
||||
width: $s-908;
|
||||
height: $s-632;
|
||||
max-height: $s-800;
|
||||
height: 100%;
|
||||
padding-inline: $s-100;
|
||||
padding-block-start: $s-40;
|
||||
padding-block-end: $s-72;
|
||||
padding-block-end: $s-40;
|
||||
border-radius: $br-8;
|
||||
background-color: var(--modal-background-color);
|
||||
border: $s-2 solid var(--modal-border-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $s-24;
|
||||
}
|
||||
|
||||
.modal-sections {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr $s-32 1fr;
|
||||
gap: $s-24;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.paginator {
|
||||
|
@ -41,14 +50,12 @@
|
|||
grid-template-columns: 1fr;
|
||||
grid-template-rows: $s-32 auto auto 1fr;
|
||||
gap: $s-16;
|
||||
max-height: $s-512;
|
||||
padding-block-start: $s-44;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
@include bigTitleTipography;
|
||||
color: var(--modal-title-foreground-color);
|
||||
margin-bottom: $s-8;
|
||||
}
|
||||
|
||||
.modal-subtitle {
|
||||
|
@ -56,6 +63,10 @@
|
|||
color: var(--modal-title-foreground-color);
|
||||
}
|
||||
|
||||
.invite-subtitle {
|
||||
padding-top: $s-16;
|
||||
}
|
||||
|
||||
.modal-text {
|
||||
@include bodyLargeTypography;
|
||||
color: var(--modal-text-foreground-color);
|
||||
|
@ -107,9 +118,8 @@
|
|||
// SEPARATOR
|
||||
.separator {
|
||||
width: $s-8;
|
||||
height: $s-420;
|
||||
height: 100%;
|
||||
border-radius: $br-8;
|
||||
margin-block-start: $s-92;
|
||||
opacity: 42%;
|
||||
background-color: var(--modal-separator-backogrund-color);
|
||||
}
|
||||
|
@ -120,8 +130,12 @@
|
|||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr auto;
|
||||
gap: $s-24;
|
||||
max-height: $s-512;
|
||||
margin-block-start: $s-92;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.first-block {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.first-block,
|
||||
|
@ -162,7 +176,6 @@
|
|||
grid-template-rows: auto auto 1fr;
|
||||
gap: $s-16;
|
||||
max-height: $s-512;
|
||||
margin-block-start: $s-92;
|
||||
}
|
||||
|
||||
.modal-form-invitations {
|
||||
|
|
|
@ -162,7 +162,7 @@
|
|||
|
||||
:register-validate
|
||||
[:div {:class (stl/css :form-container)}
|
||||
[:& register/register-validate-form
|
||||
[:& register/register-form
|
||||
{:params {:token @register-token}
|
||||
:on-success-callback register-email-sent}]
|
||||
[:div {:class (stl/css :links)}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
[app.main.store :as st]
|
||||
[app.main.ui.auth.login :refer [login-methods]]
|
||||
[app.main.ui.auth.recovery-request :refer [recovery-request-page]]
|
||||
[app.main.ui.auth.register :refer [register-methods register-validate-form register-success-page terms-register]]
|
||||
[app.main.ui.auth.register :refer [register-methods register-success-page terms-register register-validate-form]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue