diff --git a/common/src/app/common/flags.cljc b/common/src/app/common/flags.cljc
index bd3afed236..ee86f729ab 100644
--- a/common/src/app/common/flags.cljc
+++ b/common/src/app/common/flags.cljc
@@ -13,6 +13,7 @@
"A common flags that affects both: backend and frontend."
[:enable-registration
:enable-login-with-password
+ :enable-login-illustration
:enable-feature-styles-v2])
(defn parse
diff --git a/frontend/gulpfile.js b/frontend/gulpfile.js
index e232a4db1c..7ced3ba604 100644
--- a/frontend/gulpfile.js
+++ b/frontend/gulpfile.js
@@ -29,12 +29,13 @@ paths.resources = "./resources/";
paths.output = "./resources/public/";
paths.dist = "./target/dist/";
-const touchSourceOnStyleChange = false;
-
/***********************************************
* Marked Extensions
***********************************************/
+// Name of Penpot's top level package
+const ROOT_NAME = "app";
+
const renderer = {
link(href, title, text) {
return `${text}`;
@@ -223,7 +224,18 @@ gulp.task("scss:modules", function () {
.pipe(
gulpPostcss([
modules({
- generateScopedName: "[folder]_[name]_[local]_[hash:base64:5]",
+ getJSON: function (cssFileName, json, outputFileName) {
+ // We do nothing because we don't want the generated JSON files
+ },
+ // Calculates the whole css-module selector name.
+ // Should be the same as the one in the file `/src/app/main/style.clj`
+ generateScopedName: function (selector, filename, css) {
+ const dir = path.dirname(filename);
+ const name = path.basename(filename, ".css");
+ const parts = dir.split("/");
+ const rootIdx = parts.findIndex(s => s === ROOT_NAME);
+ return parts.slice(rootIdx + 1).join("_") + "_" + name + "__" + selector;
+ },
}),
autoprefixer(),
]),
@@ -350,13 +362,6 @@ gulp.task("dev:dirs", async function (next) {
gulp.task("watch:main", function () {
const watchTask = gulp.watch("src/**/**.scss", gulp.series("scss"));
- if (touchSourceOnStyleChange) {
- watchTask.on("change", function (path) {
- // Replace ".scss" for ".cljs" to refresh the file
- gulp.src(path.replace(".scss", ".cljs")).pipe(touch());
- });
- }
-
gulp.watch(paths.resources + "styles/**/**.scss", gulp.series("scss"));
gulp.watch(paths.resources + "images/**/*", gulp.series("copy:assets:images"));
diff --git a/frontend/resources/images/icons/login-illustration.svg b/frontend/resources/images/icons/login-illustration.svg
new file mode 100644
index 0000000000..21b0c18adb
--- /dev/null
+++ b/frontend/resources/images/icons/login-illustration.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/resources/styles/common/refactor/color-defs.scss b/frontend/resources/styles/common/refactor/color-defs.scss
index b1c0a2b0f9..17da351a1e 100644
--- a/frontend/resources/styles/common/refactor/color-defs.scss
+++ b/frontend/resources/styles/common/refactor/color-defs.scss
@@ -4,6 +4,8 @@
//
// Copyright (c) KALEIDOS INC
+@use "sass:color" as color;
+
:root {
// DARK
--dark-gray-1: #1d1f20;
@@ -46,4 +48,21 @@
//GENERIC
--color-canvas: #e8e9ea;
+
+ // SOCIAL LOGIN BUTTONS
+ --google-login-background: #4285f4;
+ --google-login-background-hover: #{color.adjust(#4285f4, $lightness: -15%)};
+ --google-login-foreground: var(--white);
+
+ --github-login-background: #4c4c4c;
+ --github-login-background-hover: #{color.adjust(#4c4c4c, $lightness: -15%)};
+ --github-login-foreground: var(--white);
+
+ --oidc-login-background: #b3b3b3;
+ --oidc-login-background-hover: #{color.adjust(#b3b3b3, $lightness: -15%)};
+ --oidc-login-foreground: var(--white);
+
+ --gitlab-login-background: #fc6d26;
+ --gitlab-login-background-hover: #{color.adjust(#fc6d26, $lightness: -15%)};
+ --gitlab-login-foreground: var(--white);
}
diff --git a/frontend/resources/styles/common/refactor/design-tokens.scss b/frontend/resources/styles/common/refactor/design-tokens.scss
index ff35b96355..c68d1d650c 100644
--- a/frontend/resources/styles/common/refactor/design-tokens.scss
+++ b/frontend/resources/styles/common/refactor/design-tokens.scss
@@ -151,6 +151,7 @@
--input-foreground-color-disabled: var(--color-foreground-secondary);
--input-border-color-disabled: var(--color-background-quaternary);
--input-border-color-error: var(--error-color);
+ --input-border-color-success: var(--color-accent-primary);
--input-details-color: var(--color-background-primary);
--input-checkbox-background-color-rest: var(--color-background-quaternary);
--input-checkbox-border-color-active: var(--color-background-quaternary);
diff --git a/frontend/resources/styles/common/refactor/spacing.scss b/frontend/resources/styles/common/refactor/spacing.scss
index c80afc3a32..807214c7f0 100644
--- a/frontend/resources/styles/common/refactor/spacing.scss
+++ b/frontend/resources/styles/common/refactor/spacing.scss
@@ -145,6 +145,7 @@ $s-580: #{0.25 * 145}rem;
$s-612: #{0.25 * 153}rem;
$s-640: #{0.25 * 160}rem;
$s-664: #{0.25 * 166}rem;
+$s-688: #{0.25 * 172}rem;
$s-712: #{0.25 * 178}rem;
$s-736: #{0.25 * 184}rem;
$s-800: #{0.25 * 200}rem;
diff --git a/frontend/resources/styles/common/refactor/themes/default-theme.scss b/frontend/resources/styles/common/refactor/themes/default-theme.scss
index cfbead3b81..f5d10bad96 100644
--- a/frontend/resources/styles/common/refactor/themes/default-theme.scss
+++ b/frontend/resources/styles/common/refactor/themes/default-theme.scss
@@ -4,6 +4,8 @@
//
// Copyright (c) KALEIDOS INC
+@use "sass:meta";
+
:root {
--color-background-primary: var(--dark-gray-1);
--color-background-secondary: var(--dark-gray-2);
@@ -25,4 +27,6 @@
--pending-color: var(--dark-pending-color);
--error-color: var(--dark-error-color);
--canvas-color: var(--color-canvas);
+
+ @include meta.load-css("hljs-dark-theme");
}
diff --git a/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss b/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss
new file mode 100644
index 0000000000..5ae417d47e
--- /dev/null
+++ b/frontend/resources/styles/common/refactor/themes/hljs-dark-theme.scss
@@ -0,0 +1,98 @@
+/**
+ * Panda Syntax Theme for Highlight.js
+ * Based on: https://github.com/tinkertrain/panda-syntax-vscode
+ * Author: Annmarie Switzer
+ */
+
+.hljs {
+ color: #e6e6e6;
+ background: #2a2c2d;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #bbbbbb;
+ font-style: italic;
+}
+
+.hljs-params {
+ color: #bbbbbb;
+}
+
+.hljs-punctuation,
+.hljs-attr {
+ color: #e6e6e6;
+}
+
+.hljs-selector-tag,
+.hljs-name,
+.hljs-meta {
+ color: #ff4b82;
+}
+
+.hljs-operator,
+.hljs-char.escape_ {
+ color: #b084eb;
+}
+
+.hljs-keyword,
+.hljs-deletion {
+ color: #ff75b5;
+}
+
+.hljs-regexp,
+.hljs-selector-pseudo,
+.hljs-selector-attr,
+.hljs-variable.language_ {
+ color: #ff9ac1;
+}
+
+.hljs-subst,
+.hljs-property,
+.hljs-code,
+.hljs-formula,
+.hljs-section,
+.hljs-title.function_ {
+ color: #45a9f9;
+}
+
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition,
+.hljs-selector-class,
+.hljs-title.class_,
+.hljs-title.class_.inherited__,
+.hljs-meta .hljs-string {
+ color: #19f9d8;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-number,
+.hljs-literal,
+.hljs-type,
+.hljs-link,
+.hljs-built_in,
+.hljs-title,
+.hljs-selector-id,
+.hljs-tag,
+.hljs-doctag,
+.hljs-attribute,
+.hljs-template-tag,
+.hljs-meta .hljs-keyword,
+.hljs-punctuation {
+ color: #ffb86c;
+}
diff --git a/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss b/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss
new file mode 100644
index 0000000000..615abdd13a
--- /dev/null
+++ b/frontend/resources/styles/common/refactor/themes/hljs-light-theme.scss
@@ -0,0 +1,94 @@
+/**
+ * Panda Syntax Theme for Highlight.js
+ * Based on: https://github.com/tinkertrain/panda-syntax-vscode
+ * Author: Annmarie Switzer
+ */
+
+.hljs {
+ color: #2a2c2d;
+ background: #e6e6e6;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #676b79;
+ font-style: italic;
+}
+
+.hljs-params {
+ color: #676b79;
+}
+
+.hljs-punctuation,
+.hljs-attr {
+ color: #2a2c2d;
+}
+
+.hljs-selector-tag,
+.hljs-name,
+.hljs-meta,
+.hljs-operator,
+.hljs-char.escape_ {
+ color: #c56200;
+}
+
+.hljs-keyword,
+.hljs-deletion {
+ color: #d92792;
+}
+
+.hljs-regexp,
+.hljs-selector-pseudo,
+.hljs-selector-attr,
+.hljs-variable.language_ {
+ color: #cc5e91;
+}
+
+.hljs-subst,
+.hljs-property,
+.hljs-code,
+.hljs-formula,
+.hljs-section,
+.hljs-title.function_ {
+ color: #3787c7;
+}
+
+.hljs-string,
+.hljs-symbol,
+.hljs-bullet,
+.hljs-addition,
+.hljs-selector-class,
+.hljs-title.class_,
+.hljs-title.class_.inherited__,
+.hljs-meta .hljs-string {
+ color: #0d7d6c;
+}
+
+.hljs-variable,
+.hljs-template-variable,
+.hljs-number,
+.hljs-literal,
+.hljs-type,
+.hljs-link,
+.hljs-built_in,
+.hljs-title,
+.hljs-selector-id,
+.hljs-tag,
+.hljs-doctag,
+.hljs-attribute,
+.hljs-template-tag,
+.hljs-meta .hljs-keyword {
+ color: #7641bb;
+}
diff --git a/frontend/resources/styles/common/refactor/themes/light-theme.scss b/frontend/resources/styles/common/refactor/themes/light-theme.scss
index 8c7698ddde..60c904f106 100644
--- a/frontend/resources/styles/common/refactor/themes/light-theme.scss
+++ b/frontend/resources/styles/common/refactor/themes/light-theme.scss
@@ -4,6 +4,8 @@
//
// Copyright (c) KALEIDOS INC
+@use "sass:meta";
+
.light {
--color-background-primary: var(--light-gray-1);
--color-background-secondary: var(--light-gray-2);
@@ -24,4 +26,6 @@
--pending-color: var(--light-pending-color);
--error-color: var(--light-error-color);
--canvas-color: var(--color-canvas);
+
+ @include meta.load-css("hljs-light-theme");
}
diff --git a/frontend/src/app/config.cljs b/frontend/src/app/config.cljs
index c9872a8b06..fbb5a2f191 100644
--- a/frontend/src/app/config.cljs
+++ b/frontend/src/app/config.cljs
@@ -100,8 +100,8 @@
(def browser (parse-browser))
(def platform (parse-platform))
-(def terms-of-service-uri (obj/get global "penpotTermsOfServiceURI" nil))
-(def privacy-policy-uri (obj/get global "penpotPrivacyPolicyURI" nil))
+(def terms-of-service-uri (obj/get global "penpotTermsOfServiceURI" "https://penpot.app/terms"))
+(def privacy-policy-uri (obj/get global "penpotPrivacyPolicyURI" "https://penpot.app/privacy"))
(defn- normalize-uri
[uri-str]
diff --git a/frontend/src/app/main/style.clj b/frontend/src/app/main/style.clj
index 4e275cdf79..5a64f57c98 100644
--- a/frontend/src/app/main/style.clj
+++ b/frontend/src/app/main/style.clj
@@ -11,9 +11,25 @@
[clojure.core :as c]
[clojure.data.json :as json]
[clojure.java.io :as io]
+ [cuerdas.core :as str]
[rumext.v2.util :as mfu]))
-(def ^:dynamic *css-data* nil)
+;; Should match with the `ROOT_NAME` constant in gulpfile.js
+(def ROOT-NAME "app")
+
+(def ^:dynamic *css-prefix* nil)
+
+(defn get-prefix
+ ;; Calculates the css-modules prefix given the filename
+ ;; should be the same as the calculation inside the `gulpfile.js`
+ [fname]
+ (let [file (io/file fname)
+ parts
+ (->> (str/split (.getParent file) #"/")
+ (drop-while #(not= % ROOT-NAME))
+ (rest)
+ (str/join "_"))]
+ (str parts "_" (subs (.getName file) 0 (- (count (.getName file)) 5)) "__")))
(def ^:private xform-css
(keep (fn [k]
@@ -22,9 +38,8 @@
(let [knm (name k)
kns (namespace k)]
(case kns
- "global" knm
- "old-css" (if (nil? *css-data*) knm "")
- (or (get *css-data* (keyword knm)) (str "_not_found_" knm))))
+ "global" knm
+ (str *css-prefix* knm)))
(string? k)
k))))
@@ -49,14 +64,13 @@
all classes with space in the same way as `css*`."
[& selectors]
(let [fname (-> *ns* meta :file)
- path (str (subs fname 0 (- (count fname) 4)) "css.json")
- data (read-json-file path)]
+ prefix (get-prefix fname)]
(if (symbol? (first selectors))
`(if ~(with-meta (first selectors) {:tag 'boolean})
- (css* ~@(binding [*css-data* data]
+ (css* ~@(binding [*css-prefix* prefix]
(into [] xform-css (rest selectors))))
(css* ~@(rest selectors)))
- `(css* ~@(binding [*css-data* data]
+ `(css* ~@(binding [*css-prefix* prefix]
(into [] xform-css selectors))))))
(defmacro styles
@@ -76,8 +90,7 @@
kns (namespace k)]
(case kns
"global" knm
- "old-css" (if (nil? *css-data*) knm "")
- (or (get *css-data* (keyword knm)) knm)))
+ (str *css-prefix* knm)))
(string? k)
k)]
@@ -95,7 +108,6 @@
;;
;; (stl/css-case new-css-system
;; :left-settings-bar true
-;; :old-css/settings-bar true
;; :global/two-row (<= size 300))
;;
;; The first argument to the `css-case` macro is optional an if you don't
@@ -118,17 +130,16 @@
(defmacro css-case
[& params]
(let [fname (-> *ns* meta :file)
- path (str (subs fname 0 (- (count fname) 4)) "css.json")
- data (read-json-file path)]
+ prefix (get-prefix fname)]
(if (symbol? (first params))
`(if ~(with-meta (first params) {:tag 'boolean})
- ~(binding [*css-data* data]
+ ~(binding [*css-prefix* prefix]
(-> (into [] xform-css-case (rest params))
(mfu/compile-concat :safe? false)))
~(-> (into [] xform-css-case (rest params))
(mfu/compile-concat :safe? false)))
- `~(binding [*css-data* data]
+ `~(binding [*css-prefix* prefix]
(-> (into [] xform-css-case params)
(mfu/compile-concat :safe? false))))))
diff --git a/frontend/src/app/main/ui/auth.cljs b/frontend/src/app/main/ui/auth.cljs
index 1ab5209d66..b770c5f1ea 100644
--- a/frontend/src/app/main/ui/auth.cljs
+++ b/frontend/src/app/main/ui/auth.cljs
@@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.auth
+ (:require-macros [app.main.style :as stl])
(:require
[app.config :as cf]
[app.main.ui.auth.login :refer [login-page]]
@@ -19,57 +20,99 @@
(mf/defc terms-login
[]
- (let [show-all? (and cf/terms-of-service-uri cf/privacy-policy-uri)
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ 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.terms-login
- (when show-terms?
- [:a {:href cf/terms-of-service-uri :target "_blank"} (tr "auth.terms-of-service")])
+ (if new-css-system
+ (when show-all?
+ [:div {:class (stl/css :terms-login)}
+ (when show-terms?
+ [:a {:href cf/terms-of-service-uri :target "_blank"} (tr "auth.terms-of-service")])
- (when show-all?
- [:span (tr "labels.and")])
+ (when show-all?
+ [:span (tr "labels.and")])
- (when show-privacy?
- [:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])])))
+ (when show-privacy?
+ [:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])])
+
+ (when show-all?
+ [:div.terms-login
+ (when show-terms?
+ [:a {:href cf/terms-of-service-uri :target "_blank"} (tr "auth.terms-of-service")])
+
+ (when show-all?
+ [:span (tr "labels.and")])
+
+ (when show-privacy?
+ [:a {:href cf/privacy-policy-uri :target "_blank"} (tr "auth.privacy-policy")])]))))
(mf/defc auth
[{:keys [route] :as props}]
- (let [section (get-in route [:data :name])
- params (:query-params route)]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ section (get-in route [:data :name])
+ params (:query-params route)
+ show-illustration? (contains? cf/flags :login-illustration)]
(mf/use-effect
#(dom/set-html-title (tr "title.default")))
- ;; FIXME: Temporary disabled new css system until we redesign the login with the new styles
- [:& (mf/provider ctx/new-css-system) {:value false}
- [:main.auth
- [:section.auth-sidebar
- [:a.logo {:href "#/"}
- [:span {:aria-hidden true} i/logo]
- [:span.hidden-name "Home"]]
- [:span.tagline (tr "auth.sidebar-tagline")]]
+ (if new-css-system
+ [:main {:class (stl/css-case :auth-section true
+ :no-illustration (not show-illustration?))}
+ (when show-illustration?
+ [:div {:class (stl/css :login-illustration)}
+ i/login-illustration])
+ [:section {:class (stl/css :auth-content)}
+ (case section
+ :auth-register
+ [:& register-page {:params params}]
- [:section.auth-content
- (case section
- :auth-register
- [:& register-page {:params params}]
+ :auth-register-validate
+ [:& register-validate-page {:params params}]
- :auth-register-validate
- [:& register-validate-page {:params params}]
+ :auth-register-success
+ [:& register-success-page {:params params}]
- :auth-register-success
- [:& register-success-page {:params params}]
+ :auth-login
+ [:& login-page {:params params}]
- :auth-login
- [:& login-page {:params params}]
+ :auth-recovery-request
+ [:& recovery-request-page]
- :auth-recovery-request
- [:& recovery-request-page]
+ :auth-recovery
+ [:& recovery-page {:params params}])
- :auth-recovery
- [:& recovery-page {:params params}])
+ (when (contains? #{:auth-login :auth-register} section)
+ [:& terms-login])]]
- [:& terms-login {}]]]]))
+ ;; OLD
+ [:main.auth
+ [:section.auth-sidebar
+ [:a.logo {:href "#/"}
+ [:span {:aria-hidden true} i/logo]
+ [:span.hidden-name "Home"]]
+ [:span.tagline (tr "auth.sidebar-tagline")]]
+ [:section.auth-content
+ (case section
+ :auth-register
+ [:& register-page {:params params}]
+
+ :auth-register-validate
+ [:& register-validate-page {:params params}]
+
+ :auth-register-success
+ [:& register-success-page {:params params}]
+
+ :auth-login
+ [:& login-page {:params params}]
+
+ :auth-recovery-request
+ [:& recovery-request-page]
+
+ :auth-recovery
+ [:& recovery-page {:params params}])
+
+ [:& terms-login {}]]])))
diff --git a/frontend/src/app/main/ui/auth.scss b/frontend/src/app/main/ui/auth.scss
new file mode 100644
index 0000000000..02758220ea
--- /dev/null
+++ b/frontend/src/app/main/ui/auth.scss
@@ -0,0 +1,74 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "common/refactor/common-refactor.scss" as *;
+
+.auth-section {
+ align-items: center;
+ background: $db-primary;
+ display: grid;
+ gap: $s-32;
+ grid-template-columns: repeat(3, 1fr);
+ height: 100%;
+ padding: $s-32;
+ width: 100%;
+
+ &.no-illustration {
+ display: flex;
+ justify-content: center;
+ }
+
+ @media (max-width: 992px) {
+ display: flex;
+ justify-content: center;
+ }
+
+ .login-illustration {
+ display: flex;
+ justify-content: center;
+ grid-column: 1 / 3;
+
+ svg {
+ width: $s-688;
+ fill: $df-primary;
+ height: auto;
+ }
+
+ @media (max-width: 992px) {
+ display: none;
+ }
+ }
+
+ .auth-content {
+ align-items: center;
+ display: flex;
+ height: fit-content;
+ justify-content: center;
+ max-width: $s-412;
+ padding-bottom: $s-8;
+ position: relative;
+ width: 100%;
+ }
+}
+
+.terms-login {
+ font-size: $fs-11;
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ display: flex;
+ gap: $s-4;
+ justify-content: center;
+
+ a {
+ font-weight: $fw700;
+ color: $df-secondary;
+ }
+ span {
+ border-bottom: $s-1 solid transparent;
+ color: $df-secondary;
+ }
+}
diff --git a/frontend/src/app/main/ui/auth/common.scss b/frontend/src/app/main/ui/auth/common.scss
new file mode 100644
index 0000000000..0bec2bf2d7
--- /dev/null
+++ b/frontend/src/app/main/ui/auth/common.scss
@@ -0,0 +1,154 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "common/refactor/common-refactor.scss" as *;
+
+.auth-form {
+ width: 100%;
+ padding-bottom: $s-16;
+
+ form {
+ display: flex;
+ flex-direction: column;
+ gap: $s-12;
+ margin-bottom: $s-24;
+ }
+}
+
+.separator {
+ border-color: $db-cuaternary;
+ margin: $s-24 0;
+}
+
+.auth-title {
+ @include bigTitleTipography;
+ color: $df-primary;
+}
+
+.auth-subtitle {
+ margin-top: $s-24;
+ font-size: $fs-14;
+ color: $df-secondary;
+}
+
+.form-field {
+ --input-width: 100%;
+ --input-height: #{$s-40};
+ --input-min-width: 100%;
+}
+
+.buttons-stack {
+ display: flex;
+ flex-direction: column;
+ gap: $s-8;
+
+ button,
+ :global(.btn-primary) {
+ @extend .button-primary;
+ font-size: $fs-11;
+ height: $s-40;
+ text-transform: uppercase;
+ width: 100%;
+ }
+}
+
+.link-entry {
+ display: flex;
+ flex-direction: column;
+ gap: $s-12;
+ padding: $s-24 0;
+ border-top: $s-1 solid $db-cuaternary;
+
+ span {
+ text-align: center;
+ font-size: $fs-14;
+ color: $df-secondary;
+ }
+ a {
+ @extend .button-secondary;
+ height: $s-40;
+ text-transform: uppercase;
+ font-size: $fs-11;
+ }
+}
+
+.forgot-password {
+ display: flex;
+ justify-content: flex-end;
+ a {
+ font-size: $fs-14;
+ color: $df-secondary;
+ font-weight: $fw400;
+ }
+}
+
+.submit-btn,
+.register-btn,
+.recover-btn {
+ @extend .button-primary;
+ font-size: $fs-11;
+ height: $s-40;
+ text-transform: uppercase;
+ width: 100%;
+}
+
+.login-btn {
+ border-radius: $br-8;
+ font-size: $fs-14;
+ display: flex;
+ align-items: center;
+ gap: $s-6;
+ width: 100%;
+
+ span {
+ padding-top: $s-2;
+ }
+
+ &:hover {
+ color: var(--white);
+ }
+}
+
+.auth-buttons {
+ display: flex;
+ gap: $s-8;
+}
+
+.btn-google-auth {
+ color: var(--google-login-foreground);
+ background-color: var(--google-login-background);
+ &:hover {
+ background: var(--google-login-background-hover);
+ }
+}
+
+.btn-github-auth {
+ color: var(--github-login-foreground);
+ background: var(--github-login-background);
+ &:hover {
+ background: var(--github-login-background-hover);
+ }
+}
+
+.btn-oidc-auth {
+ color: var(--oidc-login-foreground);
+ background: var(--oidc-login-background);
+ &:hover {
+ background: var(--oidc-login-background-hover);
+ }
+}
+
+.btn-gitlab-auth {
+ color: var(--gitlab-login-foreground);
+ background: var(--gitlab-login-background);
+ &:hover {
+ background: var(--gitlab-login-background-hover);
+ }
+}
+
+.banner {
+ margin: $s-16 0;
+}
diff --git a/frontend/src/app/main/ui/auth/login.cljs b/frontend/src/app/main/ui/auth/login.cljs
index fad0f9cefd..bc64bdf756 100644
--- a/frontend/src/app/main/ui/auth/login.cljs
+++ b/frontend/src/app/main/ui/auth/login.cljs
@@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.auth.login
+ (:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.logging :as log]
@@ -17,6 +18,7 @@
[app.main.ui.components.button-link :as bl]
[app.main.ui.components.forms :as fm]
[app.main.ui.components.link :as lk]
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.messages :as msgs]
[app.util.dom :as dom]
@@ -92,7 +94,8 @@
(mf/defc login-form
[{:keys [params on-success-callback] :as props}]
- (let [initial (mf/use-memo (mf/deps params) (constantly params))
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ initial (mf/use-memo (mf/deps params) (constantly params))
error (mf/use-state false)
form (fm/use-form :spec ::login-form
@@ -150,137 +153,269 @@
(login-with-ldap event (with-meta params
{:on-error on-error
:on-success on-success})))))]
- [:*
- (when-let [message @error]
- [:& msgs/inline-banner
- {:type :warning
- :content message
- :on-close #(reset! error nil)
- :data-test "login-banner"
- :role "alert"}])
+ (if new-css-system
+ [:*
+ (when-let [message @error]
+ [:& msgs/inline-banner
+ {:type :warning
+ :content message
+ :on-close #(reset! error nil)
+ :data-test "login-banner"
+ :role "alert"}])
- [:& fm/form {:on-submit on-submit :form form}
- [:div.fields-row
- [:& fm/input
- {:name :email
- :type "email"
- :help-icon i/at
- :label (tr "auth.email")}]]
+ [:& fm/form {:on-submit on-submit :form form}
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input
+ {:name :email
+ :type "email"
+ :label (tr "auth.email")
+ :class (stl/css :form-field)}]]
- [:div.fields-row
- [:& fm/input
- {:type "password"
- :name :password
- :help-icon i/eye
- :label (tr "auth.password")}]]
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input
+ {:type "password"
+ :name :password
+ :label (tr "auth.password")
+ :class (stl/css :form-field)}]]
- [:div.buttons-stack
- (when (or (contains? cf/flags :login)
- (contains? cf/flags :login-with-password))
- [:> fm/submit-button*
- {:label (tr "auth.login-submit")
- :data-test "login-submit"}])
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password))
+ [:div {:class (stl/css :fields-row :forgot-password)}
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
+ :data-test "forgot-password"}
+ (tr "auth.forgot-password")]])
- (when (contains? cf/flags :login-with-ldap)
- [:> fm/submit-button*
- {:label (tr "auth.login-with-ldap-submit")
- :on-click on-submit-ldap}])]]]))
+ [:div {:class (stl/css :buttons-stack)}
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password))
+ [:> fm/submit-button*
+ {:label (tr "auth.login-submit")
+ :data-test "login-submit"
+ :class (stl/css :login-button)}])
+
+ (when (contains? cf/flags :login-with-ldap)
+ [:> fm/submit-button*
+ {:label (tr "auth.login-with-ldap-submit")
+ :on-click on-submit-ldap}])]]]
+
+ ;; OLD
+ [:*
+ (when-let [message @error]
+ [:& msgs/inline-banner
+ {:type :warning
+ :content message
+ :on-close #(reset! error nil)
+ :data-test "login-banner"
+ :role "alert"}])
+
+ [:& fm/form {:on-submit on-submit :form form}
+ [:div.fields-row
+ [:& fm/input
+ {:name :email
+ :type "email"
+ :help-icon i/at
+ :label (tr "auth.email")
+ :class (stl/css :form-field)}]]
+
+ [:div.fields-row
+ [:& fm/input
+ {:type "password"
+ :name :password
+ :help-icon i/eye
+ :label (tr "auth.password")
+ :class (stl/css :form-field)}]]
+
+ [:div.buttons-stack
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password))
+ [:> fm/submit-button*
+ {:label (tr "auth.login-submit")
+ :data-test "login-submit"}])
+
+ (when (contains? cf/flags :login-with-ldap)
+ [:> fm/submit-button*
+ {:label (tr "auth.login-with-ldap-submit")
+ :on-click on-submit-ldap}])]]])))
(mf/defc login-buttons
[{:keys [params] :as props}]
- (let [login-with-google (mf/use-fn (mf/deps params) #(login-with-oidc % :google params))
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+
+ login-with-google (mf/use-fn (mf/deps params) #(login-with-oidc % :google params))
login-with-github (mf/use-fn (mf/deps params) #(login-with-oidc % :github params))
login-with-gitlab (mf/use-fn (mf/deps params) #(login-with-oidc % :gitlab params))
login-with-oidc (mf/use-fn (mf/deps params) #(login-with-oidc % :oidc params))]
- [:div.auth-buttons
- (when (contains? cf/flags :login-with-google)
- [:& bl/button-link {:on-click login-with-google
- :icon i/brand-google
- :label (tr "auth.login-with-google-submit")
- :class "btn-google-auth"}])
+ (if new-css-system
+ [:div {:class (stl/css :auth-buttons)}
+ (when (contains? cf/flags :login-with-google)
+ [:& bl/button-link {:on-click login-with-google
+ :icon i/brand-google
+ :label (tr "auth.login-with-google-submit")
+ :class (stl/css :login-btn :btn-google-auth)}])
- (when (contains? cf/flags :login-with-github)
- [:& bl/button-link {:on-click login-with-github
- :icon i/brand-github
- :label (tr "auth.login-with-github-submit")
- :class "btn-github-auth"}])
+ (when (contains? cf/flags :login-with-github)
+ [:& bl/button-link {:on-click login-with-github
+ :icon i/brand-github
+ :label (tr "auth.login-with-github-submit")
+ :class (stl/css :login-btn :btn-github-auth)}])
- (when (contains? cf/flags :login-with-gitlab)
- [:& bl/button-link {:on-click login-with-gitlab
- :icon i/brand-gitlab
- :label (tr "auth.login-with-gitlab-submit")
- :class "btn-gitlab-auth"}])
+ (when (contains? cf/flags :login-with-gitlab)
+ [:& bl/button-link {:on-click login-with-gitlab
+ :icon i/brand-gitlab
+ :label (tr "auth.login-with-gitlab-submit")
+ :class (stl/css :login-btn :btn-gitlab-auth)}])
- (when (contains? cf/flags :login-with-oidc)
- [:& bl/button-link {:on-click login-with-oidc
- :icon i/brand-openid
- :label (tr "auth.login-with-oidc-submit")
- :class "btn-github-auth"}])]))
+ (when (contains? cf/flags :login-with-oidc)
+ [:& bl/button-link {:on-click login-with-oidc
+ :icon i/brand-openid
+ :label (tr "auth.login-with-oidc-submit")
+ :class (stl/css :login-btn :btn-oidc-auth)}])]
+
+ [:div.auth-buttons
+ (when (contains? cf/flags :login-with-google)
+ [:& bl/button-link {:on-click login-with-google
+ :icon i/brand-google
+ :label (tr "auth.login-with-google-submit")
+ :class "btn-google-auth"}])
+
+ (when (contains? cf/flags :login-with-github)
+ [:& bl/button-link {:on-click login-with-github
+ :icon i/brand-github
+ :label (tr "auth.login-with-github-submit")
+ :class "btn-github-auth"}])
+
+ (when (contains? cf/flags :login-with-gitlab)
+ [:& bl/button-link {:on-click login-with-gitlab
+ :icon i/brand-gitlab
+ :label (tr "auth.login-with-gitlab-submit")
+ :class "btn-gitlab-auth"}])
+
+ (when (contains? cf/flags :login-with-oidc)
+ [:& bl/button-link {:on-click login-with-oidc
+ :icon i/brand-openid
+ :label (tr "auth.login-with-oidc-submit")
+ :class "btn-github-auth"}])])))
(mf/defc login-button-oidc
[{:keys [params] :as props}]
- (when (contains? cf/flags :login-with-oidc)
- [:div.link-entry.link-oidc
- [:a {:tab-index "0"
- :on-key-down (fn [event]
- (when (k/enter? event)
- (login-with-oidc event :oidc params)))
- :on-click #(login-with-oidc % :oidc params)}
- (tr "auth.login-with-oidc-submit")]]))
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ (when (contains? cf/flags :login-with-oidc)
+ [:div {:class (stl/css :link-entry :link-oidc)}
+ [:a {:tab-index "0"
+ :on-key-down (fn [event]
+ (when (k/enter? event)
+ (login-with-oidc event :oidc params)))
+ :on-click #(login-with-oidc % :oidc params)}
+ (tr "auth.login-with-oidc-submit")]])
+
+ (when (contains? cf/flags :login-with-oidc)
+ [:div.link-entry.link-oidc
+ [:a {:tab-index "0"
+ :on-key-down (fn [event]
+ (when (k/enter? event)
+ (login-with-oidc event :oidc params)))
+ :on-click #(login-with-oidc % :oidc params)}
+ (tr "auth.login-with-oidc-submit")]]))))
(mf/defc login-methods
[{:keys [params on-success-callback] :as props}]
- [:*
- (when show-alt-login-buttons?
- [:*
- [:span.separator
- [:span.line]
- [:span.text (tr "labels.continue-with")]
- [:span.line]]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:*
+ (when show-alt-login-buttons?
+ [:*
+ [:& login-buttons {:params params}]
- [:& login-buttons {:params params}]
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password)
+ (contains? cf/flags :login-with-ldap))
+ [:hr {:class (stl/css :separator)}])])
- (when (or (contains? cf/flags :login)
- (contains? cf/flags :login-with-password)
- (contains? cf/flags :login-with-ldap))
- [:span.separator
- [:span.line]
- [:span.text (tr "labels.or")]
- [:span.line]])])
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password)
+ (contains? cf/flags :login-with-ldap))
+ [:& login-form {:params params :on-success-callback on-success-callback}])]
- (when (or (contains? cf/flags :login)
- (contains? cf/flags :login-with-password)
- (contains? cf/flags :login-with-ldap))
- [:& login-form {:params params :on-success-callback on-success-callback}])])
+ ;; OLD
+ [:*
+ (when show-alt-login-buttons?
+ [:*
+ [:span.separator
+ [:span.line]
+ [:span.text (tr "labels.continue-with")]
+ [:span.line]]
+
+ [:& login-buttons {:params params}]
+
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password)
+ (contains? cf/flags :login-with-ldap))
+ [:span.separator
+ [:span.line]
+ [:span.text (tr "labels.or")]
+ [:span.line]])])
+
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password)
+ (contains? cf/flags :login-with-ldap))
+ [:& login-form {:params params :on-success-callback on-success-callback}])])))
(mf/defc login-page
[{:keys [params] :as props}]
- [:div.generic-form.login-form
- [:div.form-container
- [:h1 {:data-test "login-title"} (tr "auth.login-title")]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:div {:class (stl/css :auth-form)}
+ [:h1 {:class (stl/css :auth-title)
+ :data-test "login-title"} (tr "auth.login-title")]
- [:& login-methods {:params params}]
+ [:hr {:class (stl/css :separator)}]
- [:div.links
- (when (or (contains? cf/flags :login)
- (contains? cf/flags :login-with-password))
- [:div.link-entry
- [:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
- :data-test "forgot-password"}
- (tr "auth.forgot-password")]])
+ [:& login-methods {:params params}]
- (when (contains? cf/flags :registration)
- [:div.link-entry
- [:span (tr "auth.register") " "]
- [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
- :data-test "register-submit"}
- (tr "auth.register-submit")]])]
+ [:div {:class (stl/css :links)}
+ (when (contains? cf/flags :registration)
+ [:div {:class (stl/css :link-entry :register)}
+ [:span (tr "auth.register") " "]
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
+ :data-test "register-submit"}
+ (tr "auth.register-submit")]])]
+
+ (when (contains? cf/flags :demo-users)
+ [:div {:class (stl/css :link-entry :demo-account)}
+ [:span (tr "auth.create-demo-profile") " "]
+ [:& lk/link {:action #(st/emit! (du/create-demo-profile))
+ :data-test "demo-account-link"}
+ (tr "auth.create-demo-account")]])]
+
+ ;; OLD
+ [:div.generic-form.login-form
+ [:div.form-container
+ [:h1 {:data-test "login-title"} (tr "auth.login-title")]
+
+ [:& login-methods {:params params}]
+
+ [:div.links
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-password))
+ [:div.link-entry
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-recovery-request))
+ :data-test "forgot-password"}
+ (tr "auth.forgot-password")]])
+
+ (when (contains? cf/flags :registration)
+ [:div.link-entry
+ [:span (tr "auth.register") " "]
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} params))
+ :data-test "register-submit"}
+ (tr "auth.register-submit")]])]
+
+ (when (contains? cf/flags :demo-users)
+ [:div.links.demo
+ [:div.link-entry
+ [:span (tr "auth.create-demo-profile") " "]
+ [:& lk/link {:action #(st/emit! (du/create-demo-profile))
+ :data-test "demo-account-link"}
+ (tr "auth.create-demo-account")]]])]])))
- (when (contains? cf/flags :demo-users)
- [:div.links.demo
- [:div.link-entry
- [:span (tr "auth.create-demo-profile") " "]
- [:& lk/link {:action #(st/emit! (du/create-demo-profile))
- :data-test "demo-account-link"}
- (tr "auth.create-demo-account")]]])]])
diff --git a/frontend/src/app/main/ui/auth/login.scss b/frontend/src/app/main/ui/auth/login.scss
new file mode 100644
index 0000000000..b0002114f9
--- /dev/null
+++ b/frontend/src/app/main/ui/auth/login.scss
@@ -0,0 +1,7 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "./common.scss";
diff --git a/frontend/src/app/main/ui/auth/recovery.cljs b/frontend/src/app/main/ui/auth/recovery.cljs
index 99ba7fc40a..e8828c0031 100644
--- a/frontend/src/app/main/ui/auth/recovery.cljs
+++ b/frontend/src/app/main/ui/auth/recovery.cljs
@@ -5,12 +5,14 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.auth.recovery
+ (:require-macros [app.main.style :as stl])
(:require
[app.common.spec :as us]
[app.main.data.messages :as dm]
[app.main.data.users :as du]
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
+ [app.main.ui.context :as ctx]
[app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt]
[cljs.spec.alpha :as s]
@@ -55,38 +57,73 @@
(mf/defc recovery-form
[{:keys [params] :as props}]
- (let [form (fm/use-form :spec ::recovery-form
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ form (fm/use-form :spec ::recovery-form
:validators [password-equality
(fm/validate-not-empty :password-1 (tr "auth.password-not-empty"))
(fm/validate-not-empty :password-2 (tr "auth.password-not-empty"))]
:initial params)]
- [:& fm/form {:on-submit on-submit
- :form form}
- [:div.fields-row
- [:& fm/input {:type "password"
- :name :password-1
- :label (tr "auth.new-password")}]]
+ (if new-css-system
+ [:& fm/form {:on-submit on-submit :form form}
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input {:type "password"
+ :name :password-1
+ :show-success? true
+ :label (tr "auth.new-password")
+ :class (stl/css :form-field)}]]
- [:div.fields-row
- [:& fm/input {:type "password"
- :name :password-2
- :label (tr "auth.confirm-password")}]]
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input {:type "password"
+ :name :password-2
+ :show-success? true
+ :label (tr "auth.confirm-password")
+ :class (stl/css :form-field)}]]
- [:> fm/submit-button*
- {:label (tr "auth.recovery-submit")}]]))
+ [:> fm/submit-button*
+ {:label (tr "auth.recovery-submit")
+ :class (stl/css :submit-btn)}]]
+
+ ;; OLD
+ [:& fm/form {:on-submit on-submit
+ :form form}
+ [:div.fields-row
+ [:& fm/input {:type "password"
+ :name :password-1
+ :label (tr "auth.new-password")}]]
+
+ [:div.fields-row
+ [:& fm/input {:type "password"
+ :name :password-2
+ :label (tr "auth.confirm-password")}]]
+
+ [:> fm/submit-button*
+ {:label (tr "auth.recovery-submit")}]])))
;; --- Recovery Request Page
(mf/defc recovery-page
[{:keys [params] :as props}]
- [:section.generic-form
- [:div.form-container
- [:h1 "Forgot your password?"]
- [:div.subtitle "Please enter your new password"]
- [:& recovery-form {:params params}]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:div {:class (stl/css :auth-form)}
+ [:h1 {:class (stl/css :auth-title)} "Forgot your password?"]
+ [:div {:class (stl/css :auth-subtitle)} "Please enter your new password"]
+ [:hr {:class (stl/css :separator)}]
+ [:& recovery-form {:params params}]
- [:div.links
- [:div.link-entry
- [:a {:on-click #(st/emit! (rt/nav :auth-login))}
- (tr "profile.recovery.go-to-login")]]]]])
+ [:div {:class (stl/css :links)}
+ [:div {:class (stl/css :link-entry)}
+ [:a {:on-click #(st/emit! (rt/nav :auth-login))}
+ (tr "profile.recovery.go-to-login")]]]]
+ ;; TODO
+ [:section.generic-form
+ [:div.form-container
+ [:h1 "Forgot your password?"]
+ [:div.subtitle "Please enter your new password"]
+ [:& recovery-form {:params params}]
+
+ [:div.links
+ [:div.link-entry
+ [:a {:on-click #(st/emit! (rt/nav :auth-login))}
+ (tr "profile.recovery.go-to-login")]]]]])))
diff --git a/frontend/src/app/main/ui/auth/recovery.scss b/frontend/src/app/main/ui/auth/recovery.scss
new file mode 100644
index 0000000000..743034faad
--- /dev/null
+++ b/frontend/src/app/main/ui/auth/recovery.scss
@@ -0,0 +1,12 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "common/refactor/common-refactor.scss" as *;
+@use "./common.scss";
+
+.submit-btn {
+ margin-top: $s-16;
+}
diff --git a/frontend/src/app/main/ui/auth/recovery_request.cljs b/frontend/src/app/main/ui/auth/recovery_request.cljs
index d292a57e6f..04202336d5 100644
--- a/frontend/src/app/main/ui/auth/recovery_request.cljs
+++ b/frontend/src/app/main/ui/auth/recovery_request.cljs
@@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.auth.recovery-request
+ (:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.spec :as us]
@@ -13,6 +14,7 @@
[app.main.store :as st]
[app.main.ui.components.forms :as fm]
[app.main.ui.components.link :as lk]
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.util.i18n :as i18n :refer [tr]]
[app.util.router :as rt]
@@ -32,7 +34,8 @@
(mf/defc recovery-form
[{:keys [on-success-callback] :as props}]
- (let [form (fm/use-form :spec ::recovery-request-form
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ form (fm/use-form :spec ::recovery-request-form
:validators [handle-error-messages]
:initial {})
submitted (mf/use-state false)
@@ -74,32 +77,62 @@
(reset! form nil)
(st/emit! (du/request-profile-recovery params)))))]
- [:& fm/form {:on-submit on-submit
- :form form}
- [:div.fields-row
- [:& fm/input {:name :email
- :label (tr "auth.email")
- :help-icon i/at
- :type "text"}]]
+ (if new-css-system
+ [:& fm/form {:on-submit on-submit
+ :form form}
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input {:name :email
+ :label (tr "auth.email")
+ :type "text"
+ :class (stl/css :form-field)}]]
- [:> fm/submit-button*
- {:label (tr "auth.recovery-request-submit")
- :data-test "recovery-resquest-submit"}]]))
+ [:> fm/submit-button*
+ {:label (tr "auth.recovery-request-submit")
+ :data-test "recovery-resquest-submit"
+ :class (stl/css :recover-btn)}]]
+
+ ;; OLD
+ [:& fm/form {:on-submit on-submit
+ :form form}
+ [:div.fields-row
+ [:& fm/input {:name :email
+ :label (tr "auth.email")
+ :help-icon i/at
+ :type "text"}]]
+
+ [:> fm/submit-button*
+ {:label (tr "auth.recovery-request-submit")
+ :data-test "recovery-resquest-submit"}]])))
;; --- Recovery Request Page
(mf/defc recovery-request-page
[{:keys [params on-success-callback go-back-callback] :as props}]
- (let [default-go-back #(st/emit! (rt/nav :auth-login))
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ default-go-back #(st/emit! (rt/nav :auth-login))
go-back (or go-back-callback default-go-back)]
- [:section.generic-form
- [:div.form-container
- [:h1 (tr "auth.recovery-request-title")]
- [:div.subtitle (tr "auth.recovery-request-subtitle")]
- [:& recovery-form {:params params :on-success-callback on-success-callback}]
- [:div.links
- [:div.link-entry
+ (if new-css-system
+ [:div {:class (stl/css :auth-form)}
+ [:h1 {:class (stl/css :auth-title)} (tr "auth.recovery-request-title")]
+ [:div {:class (stl/css :auth-subtitle)} (tr "auth.recovery-request-subtitle")]
+ [:hr {:class (stl/css :separator)}]
+
+ [:& recovery-form {:params params :on-success-callback on-success-callback}]
+
+ [:div {:class (stl/css :link-entry)}
[:& lk/link {:action go-back
:data-test "go-back-link"}
- (tr "labels.go-back")]]]]]))
+ (tr "labels.go-back")]]]
+
+ ;; old
+ [:section.generic-form
+ [:div.form-container
+ [:h1 (tr "auth.recovery-request-title")]
+ [:div.subtitle (tr "auth.recovery-request-subtitle")]
+ [:& recovery-form {:params params :on-success-callback on-success-callback}]
+ [:div.links
+ [:div.link-entry
+ [:& lk/link {:action go-back
+ :data-test "go-back-link"}
+ (tr "labels.go-back")]]]]])))
diff --git a/frontend/src/app/main/ui/auth/recovery_request.scss b/frontend/src/app/main/ui/auth/recovery_request.scss
new file mode 100644
index 0000000000..e78e21b6de
--- /dev/null
+++ b/frontend/src/app/main/ui/auth/recovery_request.scss
@@ -0,0 +1,12 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "common/refactor/common-refactor.scss" as *;
+@use "./common.scss";
+
+.fields-row {
+ margin-bottom: $s-8;
+}
diff --git a/frontend/src/app/main/ui/auth/register.cljs b/frontend/src/app/main/ui/auth/register.cljs
index 43cf56e1f8..da8f5277ab 100644
--- a/frontend/src/app/main/ui/auth/register.cljs
+++ b/frontend/src/app/main/ui/auth/register.cljs
@@ -5,6 +5,7 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.auth.register
+ (:require-macros [app.main.style :as stl])
(:require
[app.common.data :as d]
[app.common.spec :as us]
@@ -16,9 +17,10 @@
[app.main.ui.auth.login :as login]
[app.main.ui.components.forms :as fm]
[app.main.ui.components.link :as lk]
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.messages :as msgs]
- [app.util.i18n :refer [tr]]
+ [app.util.i18n :refer [tr tr-html]]
[app.util.router :as rt]
[beicon.core :as rx]
[cljs.spec.alpha :as s]
@@ -26,9 +28,10 @@
(mf/defc demo-warning
[_]
- [:& msgs/inline-banner
- {:type :warning
- :content (tr "auth.demo-warning")}])
+ [:div {:class (stl/css :banner)}
+ [:& msgs/inline-banner
+ {:type :warning
+ :content (tr "auth.demo-warning")}]])
;; --- PAGE: Register
@@ -85,7 +88,8 @@
(mf/defc register-form
[{:keys [params on-success-callback] :as props}]
- (let [initial (mf/use-memo (mf/deps params) (constantly params))
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ initial (mf/use-memo (mf/deps params) (constantly params))
form (fm/use-form :spec ::register-form
:validators [validate
(fm/validate-not-empty :password (tr "auth.password-not-empty"))]
@@ -110,72 +114,133 @@
(partial handle-prepare-register-error form))))))]
- [:& fm/form {:on-submit on-submit
- :form form}
- [:div.fields-row
- [:& fm/input {:type "email"
- :name :email
- :help-icon i/at
- :label (tr "auth.email")
- :data-test "email-input"}]]
- [:div.fields-row
- [:& fm/input {:name :password
- :hint (tr "auth.password-length-hint")
- :label (tr "auth.password")
- :type "password"}]]
+ (if new-css-system
+ [:& fm/form {:on-submit on-submit :form form}
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input {:type "email"
+ :name :email
+ :label (tr "auth.email")
+ :data-test "email-input"
+ :show-success? true
+ :class (stl/css :form-field)}]]
+ [:div {:class (stl/css :fields-row)}
+ [:& fm/input {:name :password
+ :hint (tr "auth.password-length-hint")
+ :label (tr "auth.password")
+ :show-success? true
+ :type "password"
+ :class (stl/css :form-field)}]]
- [:> fm/submit-button*
- {:label (tr "auth.register-submit")
- :disabled @submitted?
- :data-test "register-form-submit"}]]))
+ [:> fm/submit-button*
+ {:label (tr "auth.register-submit")
+ :disabled @submitted?
+ :data-test "register-form-submit"
+ :class (stl/css :register-btn)}]]
+
+ ;; OLD
+ [:& fm/form {:on-submit on-submit
+ :form form}
+ [:div.fields-row
+ [:& fm/input {:type "email"
+ :name :email
+ :help-icon i/at
+ :label (tr "auth.email")
+ :data-test "email-input"}]]
+ [:div.fields-row
+ [:& fm/input {:name :password
+ :hint (tr "auth.password-length-hint")
+ :label (tr "auth.password")
+ :type "password"}]]
+
+ [:> fm/submit-button*
+ {:label (tr "auth.register-submit")
+ :disabled @submitted?
+ :data-test "register-form-submit"}]])))
(mf/defc register-methods
[{:keys [params on-success-callback] :as props}]
- [:*
- (when login/show-alt-login-buttons?
- [:*
- [:span.separator
- [:span.line]
- [:span.text (tr "labels.continue-with")]
- [:span.line]]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:*
+ (when login/show-alt-login-buttons?
+ [:*
+ [:hr {:class (stl/css :separator)}]
+ [:& login/login-buttons {:params params}]])
+ [:hr {:class (stl/css :separator)}]
+ [:& register-form {:params params :on-success-callback on-success-callback}]]
- [:& login/login-buttons {:params params}]
+ ;; OLD
+ [:*
+ (when login/show-alt-login-buttons?
+ [:*
+ [:span.separator
+ [:span.line]
+ [:span.text (tr "labels.continue-with")]
+ [:span.line]]
- (when (or (contains? cf/flags :login)
- (contains? cf/flags :login-with-ldap))
- [:span.separator
- [:span.line]
- [:span.text (tr "labels.or")]
- [:span.line]])])
+ [:& login/login-buttons {:params params}]
- [:& register-form {:params params :on-success-callback on-success-callback}]])
+ (when (or (contains? cf/flags :login)
+ (contains? cf/flags :login-with-ldap))
+ [:span.separator
+ [:span.line]
+ [:span.text (tr "labels.or")]
+ [:span.line]])])
+
+ [:& register-form {:params params :on-success-callback on-success-callback}]])))
(mf/defc register-page
[{:keys [params] :as props}]
- [:div.form-container
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:div {:class (stl/css :auth-form)}
+ [:h1 {:class (stl/css :auth-title)
+ :data-test "registration-title"} (tr "auth.register-title")]
+ [:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")]
- [:h1 {:data-test "registration-title"} (tr "auth.register-title")]
- [:div.subtitle (tr "auth.register-subtitle")]
+ (when (contains? cf/flags :demo-warning)
+ [:& demo-warning])
- (when (contains? cf/flags :demo-warning)
- [:& demo-warning])
+ [:& register-methods {:params params}]
- [:& register-methods {:params params}]
+ [:div {:class (stl/css :links)}
+ [:div {:class (stl/css :link-entry :account)}
+ [:span (tr "auth.already-have-account") " "]
- [:div.links
- [:div.link-entry
- [:span (tr "auth.already-have-account") " "]
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params))
+ :data-test "login-here-link"}
+ (tr "auth.login-here")]]
- [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params))
- :data-test "login-here-link"}
- (tr "auth.login-here")]]
+ (when (contains? cf/flags :demo-users)
+ [:div {:class (stl/css :link-entry :demo-users)}
+ [:span (tr "auth.create-demo-profile") " "]
+ [:& lk/link {:action #(st/emit! (du/create-demo-profile))}
+ (tr "auth.create-demo-account")]])]]
- (when (contains? cf/flags :demo-users)
- [:div.link-entry
- [:span (tr "auth.create-demo-profile") " "]
- [:& lk/link {:action #(st/emit! (du/create-demo-profile))}
- (tr "auth.create-demo-account")]])]])
+ ;; OLD
+ [:div.form-container
+ [:h1 {:data-test "registration-title"} (tr "auth.register-title")]
+ [:div.subtitle (tr "auth.register-subtitle")]
+
+ (when (contains? cf/flags :demo-warning)
+ [:& demo-warning])
+
+ [:& register-methods {:params params}]
+
+ [:div.links
+ [:div.link-entry
+ [:span (tr "auth.already-have-account") " "]
+
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-login {} params))
+ :data-test "login-here-link"}
+ (tr "auth.login-here")]]
+
+ (when (contains? cf/flags :demo-users)
+ [:div.link-entry
+ [:span (tr "auth.create-demo-profile") " "]
+ [:& lk/link {:action #(st/emit! (du/create-demo-profile))}
+ (tr "auth.create-demo-account")]])]])))
;; --- PAGE: register validation
@@ -219,7 +284,8 @@
(mf/defc register-validate-form
[{:keys [params on-success-callback] :as props}]
- (let [form (fm/use-form :spec ::register-validate-form
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ form (fm/use-form :spec ::register-validate-form
:validators [(fm/validate-not-empty :fullname (tr "auth.name.not-all-space"))
(fm/validate-length :fullname fm/max-length-allowed (tr "auth.name.too-long"))]
:initial params)
@@ -240,48 +306,103 @@
(rx/subs on-success
(partial handle-register-error form))))))]
- [:& fm/form {:on-submit on-submit
- :form form}
- [:div.fields-row
- [:& fm/input {:name :fullname
- :label (tr "auth.fullname")
- :type "text"}]]
+ (if new-css-system
+ [:& 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)}]]
- (when (contains? cf/flags :terms-and-privacy-checkbox)
- [:div.fields-row.input-visible.accept-terms-and-privacy-wrapper
- [:& fm/input {:name :accept-terms-and-privacy
- :class "check-primary"
- :type "checkbox"}
- [:span
- (tr "auth.terms-privacy-agreement")]]
- [:div.auth-links
- [:a {:href "https://penpot.app/terms" :target "_blank"} (tr "auth.terms-of-service")]
- [:span ",\u00A0"]
- [:a {:href "https://penpot.app/privacy" :target "_blank"} (tr "auth.privacy-policy")]]])
+ (when (contains? cf/flags :terms-and-privacy-checkbox)
+ (let [terms-label
+ (mf/html
+ [:& tr-html
+ {:tag-name "div"
+ :label "auth.terms-privacy-agreement-md"
+ :params [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 "check-primary"
+ :type "checkbox"
+ :label terms-label}]]))
- [:> fm/submit-button*
- {:label (tr "auth.register-submit")
- :disabled @submitted?}]]))
+ [:> fm/submit-button*
+ {:label (tr "auth.register-submit")
+ :disabled @submitted?
+ :class (stl/css :register-btn)}]]
+
+ ;; OLD
+ [:& fm/form {:on-submit on-submit
+ :form form}
+ [:div.fields-row
+ [:& fm/input {:name :fullname
+ :label (tr "auth.fullname")
+ :type "text"}]]
+
+ (when (contains? cf/flags :terms-and-privacy-checkbox)
+ [:div.fields-row.input-visible.accept-terms-and-privacy-wrapper
+ [:& fm/input {:name :accept-terms-and-privacy
+ :class "check-primary"
+ :type "checkbox"}
+ [:span
+ (tr "auth.terms-privacy-agreement")]]
+ [:div.auth-links
+ [:a {:href "https://penpot.app/terms" :target "_blank"} (tr "auth.terms-of-service")]
+ [:span ",\u00A0"]
+ [:a {:href "https://penpot.app/privacy" :target "_blank"} (tr "auth.privacy-policy")]]])
+
+ [:> fm/submit-button*
+ {:label (tr "auth.register-submit")
+ :disabled @submitted?}]])))
(mf/defc register-validate-page
[{:keys [params] :as props}]
- [:div.form-container
- [:h1 {:data-test "register-title"} (tr "auth.register-title")]
- [:div.subtitle (tr "auth.register-subtitle")]
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:div {:class (stl/css :auth-form)}
+ [:h1 {:class (stl/css :auth-title)
+ :data-test "register-title"} (tr "auth.register-title")]
+ [:div {:class (stl/css :auth-subtitle)} (tr "auth.register-subtitle")]
- [:& register-validate-form {:params params}]
+ [:hr {:class (stl/css :separator)}]
- [:div.links
- [:div.link-entry
- [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))}
- (tr "labels.go-back")]]]])
+ [:& register-validate-form {:params params}]
+
+ [:div {:class (stl/css :links)}
+ [:div {:class (stl/css :link-entry :go-back)}
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))}
+ (tr "labels.go-back")]]]]
+
+ ;; OLD
+ [:div.form-container
+ [:h1 {:data-test "register-title"} (tr "auth.register-title")]
+ [:div.subtitle (tr "auth.register-subtitle")]
+
+ [:& register-validate-form {:params params}]
+
+ [:div.links
+ [:div.link-entry
+ [:& lk/link {:action #(st/emit! (rt/nav :auth-register {} {}))}
+ (tr "labels.go-back")]]]])))
(mf/defc register-success-page
[{:keys [params] :as props}]
- [:div.form-container
- [:div.notification-icon i/icon-verify]
- [:div.notification-text (tr "auth.verification-email-sent")]
- [:div.notification-text-email (:email params "")]
- [:div.notification-text (tr "auth.check-your-email")]])
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:div {:class (stl/css :auth-form :register-success)}
+ [:div {:class (stl/css :notification-icon)} i/icon-verify]
+ [:div {:class (stl/css :notification-text)} (tr "auth.verification-email-sent")]
+ [:div {:class (stl/css :notification-text-email)} (:email params "")]
+ [:div {:class (stl/css :notification-text)} (tr "auth.check-your-email")]]
+
+ ;; OLD
+ [:div.form-container
+ [:div.notification-icon i/icon-verify]
+ [:div.notification-text (tr "auth.verification-email-sent")]
+ [:div.notification-text-email (:email params "")]
+ [:div.notification-text (tr "auth.check-your-email")]])))
+
diff --git a/frontend/src/app/main/ui/auth/register.scss b/frontend/src/app/main/ui/auth/register.scss
new file mode 100644
index 0000000000..7fab883e15
--- /dev/null
+++ b/frontend/src/app/main/ui/auth/register.scss
@@ -0,0 +1,38 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "common/refactor/common-refactor.scss" as *;
+@use "./common.scss";
+
+.accept-terms-and-privacy-wrapper {
+ margin: $s-16 0;
+ :global(a) {
+ color: $df-secondary;
+ font-weight: $fw700;
+ }
+}
+
+.register-success {
+ padding-bottom: $s-32;
+}
+
+.notification-icon {
+ fill: $df-primary;
+ display: flex;
+ justify-content: center;
+ margin-bottom: $s-32;
+ svg {
+ width: $s-92;
+ height: $s-92;
+ }
+}
+
+.notification-text-email,
+.notification-text {
+ font-size: $fs-16;
+ color: $df-secondary;
+ margin-bottom: $s-16;
+}
diff --git a/frontend/src/app/main/ui/auth/verify_token.cljs b/frontend/src/app/main/ui/auth/verify_token.cljs
index 7534d37316..c8f917cb95 100644
--- a/frontend/src/app/main/ui/auth/verify_token.cljs
+++ b/frontend/src/app/main/ui/auth/verify_token.cljs
@@ -5,11 +5,13 @@
;; Copyright (c) KALEIDOS INC
(ns app.main.ui.auth.verify-token
+ (:require-macros [app.main.style :as stl])
(:require
[app.main.data.messages :as dm]
[app.main.data.users :as du]
[app.main.repo :as rp]
[app.main.store :as st]
+ [app.main.ui.context :as ctx]
[app.main.ui.icons :as i]
[app.main.ui.static :as static]
[app.util.dom :as dom]
@@ -60,7 +62,8 @@
(mf/defc verify-token
[{:keys [route] :as props}]
- (let [token (get-in route [:query-params :token])
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)
+ token (get-in route [:query-params :token])
bad-token (mf/use-state false)]
(mf/with-effect []
@@ -92,9 +95,7 @@
(st/emit! (rt/nav :auth-login))))))))
(if @bad-token
- [:> static/static-header {}
- [:div.image i/unchain]
- [:div.main-message (tr "errors.invite-invalid")]
- [:div.desc-message (tr "errors.invite-invalid.info")]]
- [:div.verify-token
+ [:> static/invalid-token {}]
+ [:div {:class (stl/css-case :verify-token new-css-system
+ :global/verify-token (not new-css-system))}
i/loader-pencil])))
diff --git a/frontend/src/app/main/ui/auth/verify_token.scss b/frontend/src/app/main/ui/auth/verify_token.scss
new file mode 100644
index 0000000000..b0002114f9
--- /dev/null
+++ b/frontend/src/app/main/ui/auth/verify_token.scss
@@ -0,0 +1,7 @@
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) KALEIDOS INC
+
+@use "./common.scss";
diff --git a/frontend/src/app/main/ui/components/code_block.cljs b/frontend/src/app/main/ui/components/code_block.cljs
index 9bef8150c2..69a54a6567 100644
--- a/frontend/src/app/main/ui/components/code_block.cljs
+++ b/frontend/src/app/main/ui/components/code_block.cljs
@@ -10,16 +10,20 @@
["highlight.js" :as hljs]
[app.common.data.macros :as dm]
[app.main.ui.context :as ctx]
+ [cuerdas.core :as str]
[rumext.v2 :as mf]))
(mf/defc code-block
{::mf/wrap-props false}
[{:keys [code type]}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
- block-ref (mf/use-ref)]
+ block-ref (mf/use-ref)
+ code (str/trim code)]
(mf/with-effect [code type]
(when-let [node (mf/ref-val block-ref)]
(hljs/highlightElement node)))
- [:pre {:class (dm/str type " " (stl/css new-css-system :code-display)) :ref block-ref} code]))
+ (if new-css-system
+ [:pre {:class (dm/str type " " (stl/css :code-display)) :ref block-ref} code]
+ [:pre {:class (dm/str type " " "code-display") :ref block-ref} code])))
diff --git a/frontend/src/app/main/ui/components/code_block.scss b/frontend/src/app/main/ui/components/code_block.scss
index 1b8e72a4d2..49d63fda19 100644
--- a/frontend/src/app/main/ui/components/code_block.scss
+++ b/frontend/src/app/main/ui/components/code_block.scss
@@ -7,8 +7,10 @@
@import "refactor/common-refactor.scss";
.code-display {
+ user-select: text;
border-radius: $br-8;
margin-top: $s-8;
padding: $s-12;
background-color: var(--menu-background-color);
+ overflow: auto;
}
diff --git a/frontend/src/app/main/ui/components/forms.cljs b/frontend/src/app/main/ui/components/forms.cljs
index ee64dc30e1..11b633cc86 100644
--- a/frontend/src/app/main/ui/components/forms.cljs
+++ b/frontend/src/app/main/ui/components/forms.cljs
@@ -27,8 +27,9 @@
(def use-form fm/use-form)
(mf/defc input
- [{:keys [label help-icon disabled form hint trim children data-test on-change-value placeholder] :as props}]
+ [{:keys [label help-icon disabled form hint trim children data-test on-change-value placeholder show-success?] :as props}]
(let [new-css-system (mf/use-ctx ctx/new-css-system)
+
input-type (get props :type "text")
input-name (get props :name)
more-classes (get props :class)
@@ -54,36 +55,17 @@
help-icon' (cond
(and (= input-type "password")
(= @type' "password"))
- i/eye
+ i/shown-refactor
(and (= input-type "password")
(= @type' "text"))
- i/eye-closed
+ i/hide-refactor
:else
help-icon)
on-change-value (or on-change-value (constantly nil))
- klass (str more-classes " "
- (dom/classnames
- :focus @focus?
- :valid (and touched? (not error))
- :invalid (and touched? error)
- :disabled disabled
- :empty (and is-text? (str/empty? value))
- :with-icon (not (nil? help-icon'))
- :custom-input is-text?
- :input-radio is-radio?
- :input-checkbox is-checkbox?))
-
- new-classes (dm/str more-classes " "
- (stl/css-case
- :input-wrapper true
- :global/invalid (and touched? error)
- :checkbox is-checkbox?
- :global/disabled disabled))
-
swap-text-password
(fn []
(swap! type' (fn [input-type]
@@ -100,9 +82,7 @@
on-blur
(fn [_]
- (reset! focus? false)
- (when-not (get-in @form [:touched input-name])
- (swap! form assoc-in [:touched input-name] true)))
+ (reset! focus? false))
on-click
(fn [_]
@@ -126,10 +106,19 @@
(cond-> (and value is-checkbox?) (assoc :default-checked value))
(cond-> (and touched? (:message error)) (assoc "aria-invalid" "true"
"aria-describedby" (dm/str "error-" input-name)))
- (obj/clj->props))]
+ (obj/clj->props))
+
+ show-valid? (and show-success? touched? (not error))
+ show-invalid? (and touched? error)]
(if new-css-system
- [:div {:class new-classes}
+ [:div {:class (dm/str more-classes " "
+ (stl/css-case
+ :input-wrapper true
+ :valid show-valid?
+ :invalid show-invalid?
+ :checkbox is-checkbox?
+ :disabled disabled))}
[:*
(cond
(some? label)
@@ -137,23 +126,38 @@
:input-label is-text?
:radio-label is-radio?
:checkbox-label is-checkbox?)
- :tab-index "0"
+ :tab-index "-1"
:for (name input-name)} label
+
(when is-checkbox?
[:span {:class (stl/css-case :global/checked value)} i/status-tick-refactor])
- [:> :input props]]
+
+ (if is-checkbox?
+ [:> :input props]
+
+ [:div {:class (stl/css :input-and-icon)}
+ [:> :input props]
+ (when help-icon'
+ [:span {:class (stl/css :help-icon)
+ :on-click (when (= "password" input-type)
+ swap-text-password)}
+ help-icon'])
+
+ (when show-valid?
+ [:span {:class (stl/css :valid-icon)}
+ i/tick-refactor])
+
+ (when show-invalid?
+ [:span {:class (stl/css :invalid-icon)}
+ i/close-refactor])])]
(some? children)
[:label {:for (name input-name)}
-
[:> :input props]
children])
- (when help-icon'
- [:span {:class (stl/css :help-icon)
- :on-click (when (= "password" input-type)
- swap-text-password)}
- help-icon'])
+
+
(cond
(and touched? (:message error))
[:div {:id (dm/str "error-" input-name)
@@ -164,9 +168,19 @@
(string? hint)
[:div {:class (stl/css :hint)} hint])]]
-
+ ;;OLD
[:div
- {:class klass}
+ {:class (str more-classes " "
+ (dom/classnames
+ :focus @focus?
+ :valid (and touched? (not error))
+ :invalid (and touched? error)
+ :disabled disabled
+ :empty (and is-text? (str/empty? value))
+ :with-icon (not (nil? help-icon'))
+ :custom-input is-text?
+ :input-radio is-radio?
+ :input-checkbox is-checkbox?))}
[:*
[:> :input props]
(cond
@@ -387,7 +401,7 @@
(true? (unchecked-get props "disabled")))
klass (dm/str class " " (if disabled? "btn-disabled" ""))
- new-klass (if disabled? (stl/css :btn-disabled) class)
+ new-klass (dm/str class " " (if disabled? (stl/css :btn-disabled) ""))
on-key-down
(mf/use-fn
diff --git a/frontend/src/app/main/ui/components/forms.scss b/frontend/src/app/main/ui/components/forms.scss
index 8c022b06a8..2bb900528b 100644
--- a/frontend/src/app/main/ui/components/forms.scss
+++ b/frontend/src/app/main/ui/components/forms.scss
@@ -10,8 +10,8 @@
.input-wrapper {
display: flex;
flex-direction: column;
- gap: $s-6;
align-items: center;
+ position: relative;
.input-with-label {
@include flexColumn;
gap: $s-8;
@@ -24,11 +24,13 @@
cursor: pointer;
color: var(--modal-title-foreground-color);
text-transform: uppercase;
+
input {
@extend .input-element;
color: var(--input-foreground-color-active);
- width: calc(100% - $s-1);
margin-top: 0;
+ width: 100%;
+ height: 100%;
&:focus {
outline: none;
@@ -41,28 +43,101 @@
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
- -webkit-text-fill-color: var(--input-foreground-color-active) !important;
- -webkit-box-shadow: 0 0 0 28px var(--input-background-color) inset !important;
+ -webkit-text-fill-color: var(--input-foreground-color-active);
+ -webkit-box-shadow: inset 0 0 20px 20px var(--input-background-color);
border: $s-1 solid var(--input-background-color);
+ -webkit-background-clip: text;
+ transition: background-color 5000s ease-in-out 0s;
+ caret-color: var(--input-foreground-color-active);
}
}
- &:global(.invalid) {
+ &.valid {
+ input {
+ border: $s-1 solid var(--input-border-color-success);
+ @extend .disabled-input;
+ &:hover,
+ &:focus {
+ border: $s-1 solid var(--input-border-color-success);
+ }
+ }
+ }
+ &.invalid {
input {
border: $s-1 solid var(--input-border-color-error);
@extend .disabled-input;
+ &:hover,
+ &:focus {
+ border: $s-1 solid var(--input-border-color-error);
+ }
}
}
+
+ &.valid .help-icon,
+ &.invalid .help-icon {
+ right: $s-40;
+ }
+}
+
+.input-and-icon {
+ position: relative;
+ width: var(--input-width, calc(100% - $s-1));
+ min-width: var(--input-min-width);
+ height: var(--input-height, $s-32);
}
.help-icon {
cursor: pointer;
+ position: absolute;
+ right: $s-16;
+ top: calc(50% - $s-8);
svg {
@extend .button-icon-small;
- stroke: var(--input-details-color);
+ stroke: $df-secondary;
+ width: $s-16;
+ height: $s-16;
}
}
+.invalid-icon {
+ width: $s-16;
+ height: $s-16;
+ background: var(--input-border-color-error);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ right: $s-16;
+ top: calc(50% - $s-8);
+ svg {
+ width: $s-12;
+ height: $s-12;
+ stroke: var(--input-background-color);
+ }
+}
+
+.valid-icon {
+ width: $s-16;
+ height: $s-16;
+ background: var(--input-border-color-success);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: absolute;
+ right: $s-16;
+ top: calc(50% - $s-8);
+ svg {
+ width: $s-12;
+ height: $s-12;
+ fill: var(--input-border-color-success);
+ stroke: var(--input-background-color);
+ }
+}
+
.error {
color: var(--input-border-color-error);
+ width: 100%;
+ font-size: $fs-14;
}
.hint {
@@ -181,9 +256,6 @@
// SUBMIT-BUTTON
.btn-disabled {
@extend .button-disabled;
- height: $s-32;
- padding: $s-8 $s-24;
- border-radius: $br-8;
}
// MULTI INPUT
diff --git a/frontend/src/app/main/ui/dashboard/sidebar.cljs b/frontend/src/app/main/ui/dashboard/sidebar.cljs
index 7a2c3a50e5..8b469639a6 100644
--- a/frontend/src/app/main/ui/dashboard/sidebar.cljs
+++ b/frontend/src/app/main/ui/dashboard/sidebar.cljs
@@ -139,8 +139,9 @@
(if new-css-system
[:*
[:li {:tab-index "0"
- :class (if selected? (stl/css :current)
- (when (:dragging? local) (stl/css :dragging)))
+ :class (stl/css-case :project-element true
+ :current selected?
+ :dragging (:dragging? local))
:on-click on-click
:on-key-down on-key-down
:on-double-click on-edit-open
@@ -1255,3 +1256,4 @@
[:& profile-section
{:profile profile
:team team}]])))
+
diff --git a/frontend/src/app/main/ui/dashboard/sidebar.scss b/frontend/src/app/main/ui/dashboard/sidebar.scss
index 0dec1777b5..9b4bceddb6 100644
--- a/frontend/src/app/main/ui/dashboard/sidebar.scss
+++ b/frontend/src/app/main/ui/dashboard/sidebar.scss
@@ -356,8 +356,13 @@
cursor: pointer;
display: flex;
flex-shrink: 0;
- padding: $s-8 $s-8 $s-8 $s-24;
+
+ &.project-element {
+ padding: $s-8 $s-8 $s-8 $s-24;
+ }
+
a {
+ padding: $s-8 $s-8 $s-8 $s-24;
font-weight: $fw400;
width: 100%;
&:hover {
diff --git a/frontend/src/app/main/ui/dashboard/team.scss b/frontend/src/app/main/ui/dashboard/team.scss
index 18ec4eadd4..25f9ed9853 100644
--- a/frontend/src/app/main/ui/dashboard/team.scss
+++ b/frontend/src/app/main/ui/dashboard/team.scss
@@ -504,10 +504,9 @@
border-radius: 50%;
color: $df-primary;
z-index: $z-index-modal;
-
background-color: $da-primary;
- height: $s-120;
- width: $s-120;
+ height: 100%;
+ width: 100%;
svg {
fill: $db-primary;
@@ -517,8 +516,6 @@
&:hover {
.update-overlay {
opacity: 1;
- width: $s-72;
- height: $s-72;
top: $s-16;
left: $s-16;
}
diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs
index d6efe6e4af..69adf3914a 100644
--- a/frontend/src/app/main/ui/icons.cljs
+++ b/frontend/src/app/main/ui/icons.cljs
@@ -172,6 +172,7 @@
(def logo-icon (icon-xref :penpot-logo-icon))
(def logo-error-screen (icon-xref :logo-error-screen))
(def logout (icon-xref :logout))
+(def login-illustration (icon-xref :login-illustration))
(def lowercase (icon-xref :lowercase))
(def mail (icon-xref :mail))
(def mask (icon-xref :mask))
diff --git a/frontend/src/app/main/ui/modal.cljs b/frontend/src/app/main/ui/modal.cljs
index 61b088b78d..3ed224d1a3 100644
--- a/frontend/src/app/main/ui/modal.cljs
+++ b/frontend/src/app/main/ui/modal.cljs
@@ -80,7 +80,7 @@
[:div {:ref wrapper-ref
:class (stl/css-case
:modal-wrapper new-css-system
- :old-css/modal-wrapper (not new-css-system))}
+ :global/modal-wrapper (not new-css-system))}
(mf/element component (:props data))])))
(def modal-ref
diff --git a/frontend/src/app/main/ui/settings/access_tokens.cljs b/frontend/src/app/main/ui/settings/access_tokens.cljs
index de1ec0a7cc..a044455aed 100644
--- a/frontend/src/app/main/ui/settings/access_tokens.cljs
+++ b/frontend/src/app/main/ui/settings/access_tokens.cljs
@@ -126,6 +126,7 @@
:name :name
:disabled @created?
:label (tr "modals.create-access-token.name.label")
+ :show-success? true
:placeholder (tr "modals.create-access-token.name.placeholder")}]]
[:div {:class (stl/css :fields-row)}
diff --git a/frontend/src/app/main/ui/settings/change_email.cljs b/frontend/src/app/main/ui/settings/change_email.cljs
index 391fa44754..6cd6ae69f3 100644
--- a/frontend/src/app/main/ui/settings/change_email.cljs
+++ b/frontend/src/app/main/ui/settings/change_email.cljs
@@ -122,6 +122,7 @@
:name :email-1
:label (tr "modals.change-email.new-email")
:trim true
+ :show-success? true
:on-change-value on-email-change}]]
[:div {:class (stl/css :fields-row)}
@@ -129,6 +130,7 @@
:name :email-2
:label (tr "modals.change-email.confirm-email")
:trim true
+ :show-success? true
:on-change-value on-email-change}]]]
[:div {:class (stl/css :modal-footer)}
diff --git a/frontend/src/app/main/ui/settings/feedback.cljs b/frontend/src/app/main/ui/settings/feedback.cljs
index d59185f13c..d8e41518bd 100644
--- a/frontend/src/app/main/ui/settings/feedback.cljs
+++ b/frontend/src/app/main/ui/settings/feedback.cljs
@@ -73,7 +73,8 @@
[:div {:class (stl/css :fields-row)}
[:& fm/input {:label (tr "feedback.subject")
- :name :subject}]]
+ :name :subject
+ :show-success? true}]]
[:div {:class (stl/css :fields-row :description)}
[:& fm/textarea
{:label (tr "feedback.description")
diff --git a/frontend/src/app/main/ui/settings/password.cljs b/frontend/src/app/main/ui/settings/password.cljs
index 6dd7f7f4f8..0b9b1b5a0a 100644
--- a/frontend/src/app/main/ui/settings/password.cljs
+++ b/frontend/src/app/main/ui/settings/password.cljs
@@ -95,17 +95,20 @@
[:& fm/input
{:type "password"
:name :password-1
+ :show-success? true
:label (t locale "labels.new-password")}]]
[:div {:class (stl/css :fields-row)}
[:& fm/input
{:type "password"
:name :password-2
+ :show-success? true
:label (t locale "labels.confirm-password")}]]
[:> fm/submit-button*
{:label (t locale "dashboard.update-settings")
- :data-test "submit-password"}]]
+ :data-test "submit-password"
+ :class (stl/css :update-btn)}]]
;; OLD
[:& fm/form {:class "password-form"
@@ -153,4 +156,3 @@
[:section.dashboard-settings.form-container
[:div.form-container
[:& password-form {:locale locale}]]])))
-
diff --git a/frontend/src/app/main/ui/settings/password.scss b/frontend/src/app/main/ui/settings/password.scss
index 474e96838f..fe44ec71b3 100644
--- a/frontend/src/app/main/ui/settings/password.scss
+++ b/frontend/src/app/main/ui/settings/password.scss
@@ -4,4 +4,11 @@
//
// Copyright (c) KALEIDOS INC
+@use "common/refactor/common-refactor.scss" as *;
@use "./profile" as *;
+
+.update-btn {
+ margin-top: $s-16;
+ @extend .button-primary;
+ height: $s-36;
+}
diff --git a/frontend/src/app/main/ui/settings/profile.cljs b/frontend/src/app/main/ui/settings/profile.cljs
index a6bb4ad308..b946b68462 100644
--- a/frontend/src/app/main/ui/settings/profile.cljs
+++ b/frontend/src/app/main/ui/settings/profile.cljs
@@ -75,7 +75,6 @@
{:type "email"
:name :email
:disabled true
- :help-icon i/at
:label (tr "dashboard.your-email")}]
[:div {:class (stl/css :options)}
diff --git a/frontend/src/app/main/ui/settings/profile.scss b/frontend/src/app/main/ui/settings/profile.scss
index c1f1b622b0..44004ae5c3 100644
--- a/frontend/src/app/main/ui/settings/profile.scss
+++ b/frontend/src/app/main/ui/settings/profile.scss
@@ -48,6 +48,7 @@
}
.fields-row {
+ --input-height: $s-40;
margin-bottom: $s-20;
flex-direction: column;
@@ -57,10 +58,6 @@
font-size: $fs-14;
margin-top: $s-12;
}
-
- :global(input) {
- height: $s-40;
- }
}
.field {
diff --git a/frontend/src/app/main/ui/static.cljs b/frontend/src/app/main/ui/static.cljs
index 163b806710..916d2fa38d 100644
--- a/frontend/src/app/main/ui/static.cljs
+++ b/frontend/src/app/main/ui/static.cljs
@@ -25,7 +25,7 @@
on-click (mf/use-callback #(set! (.-href globals/location) "/"))]
(if new-css-system
[:section {:class (stl/css :exception-layout)}
- [:div
+ [:button
{:class (stl/css :exception-header)
:on-click on-click}
i/logo-icon]
@@ -42,6 +42,19 @@
[:div.exception-content
[:div.container children]]])))
+(mf/defc invalid-token
+ []
+ (let [new-css-system (mf/use-ctx ctx/new-css-system)]
+ (if new-css-system
+ [:> static-header {}
+ [:div {:class (stl/css :main-message)} (tr "errors.invite-invalid")]
+ [:div {:class (stl/css :desc-message)} (tr "errors.invite-invalid.info")]]
+
+ [:> static-header {}
+ [:div.image i/unchain]
+ [:div.main-message (tr "errors.invite-invalid")]
+ [:div.desc-message (tr "errors.invite-invalid.info")]])))
+
(mf/defc not-found
[]
(let [new-css-system (mf/use-ctx ctx/new-css-system)]
diff --git a/frontend/src/app/main/ui/static.scss b/frontend/src/app/main/ui/static.scss
index 63e00828b5..6fc83378ce 100644
--- a/frontend/src/app/main/ui/static.scss
+++ b/frontend/src/app/main/ui/static.scss
@@ -44,6 +44,9 @@
.exception-header {
padding: $s-24 $s-32;
position: fixed;
+ background: none;
+ border: none;
+ cursor: pointer;
svg {
fill: $df-primary;
width: $s-48;
@@ -89,3 +92,9 @@
font-size: $fs-11;
}
}
+
+.image {
+ svg {
+ fill: $df-primary;
+ }
+}
diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs
index 79f76d5c50..e0433a1762 100644
--- a/frontend/src/app/main/ui/workspace/sidebar.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar.cljs
@@ -196,8 +196,8 @@
(obj/set! "on-expand" handle-expand))]
[:aside {:class (stl/css-case new-css-system
- :old-css/settings-bar true
- :old-css/settings-bar-right true
+ :global/settings-bar (not new-css-system)
+ :global/settings-bar-right (not new-css-system)
:right-settings-bar true
:not-expand (not can-be-expanded?)
:expanded (> size 276))
diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs
index a9e42f7df4..a7246b2494 100644
--- a/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs
+++ b/frontend/src/app/main/ui/workspace/sidebar/options/menus/shadow.cljs
@@ -156,7 +156,7 @@
[:div.shadow-option {:class (stl/css-case new-css-system
- :old-css/shadow-option true
+ :global/shadow-option true
:shadow-element true
:dnd-over-top (= (:over dprops) :top)
:dnd-over-bot (= (:over dprops) :bot))
diff --git a/frontend/src/app/util/i18n.cljs b/frontend/src/app/util/i18n.cljs
index 8f0429993d..fc79d676f3 100644
--- a/frontend/src/app/util/i18n.cljs
+++ b/frontend/src/app/util/i18n.cljs
@@ -7,6 +7,7 @@
(ns app.util.i18n
"A i18n foundation."
(:require
+ [app.common.data :as d]
[app.common.logging :as log]
[app.config :as cfg]
[app.util.dom :as dom]
@@ -175,8 +176,10 @@
{::mf/wrap-props false}
[props]
(let [label (obj/get props "label")
- tag-name (obj/get props "tag-name" "p")]
- [:> tag-name {:dangerouslySetInnerHTML #js {:__html (tr label)}}]))
+ tag-name (obj/get props "tag-name" "p")
+ params (obj/get props "params" [])
+ html (apply tr (d/concat-vec [label] params))]
+ [:> tag-name {:dangerouslySetInnerHTML #js {:__html html}}]))
;; DEPRECATED
(defn use-locale
diff --git a/frontend/translations/en.po b/frontend/translations/en.po
index b2fcc11b28..2efb27fc24 100644
--- a/frontend/translations/en.po
+++ b/frontend/translations/en.po
@@ -168,10 +168,14 @@ msgid "auth.terms-of-service"
msgstr "Terms of service"
#: src/app/main/ui/auth/register.cljs
+#, markdown
+msgid "auth.terms-privacy-agreement-md"
+msgstr ""
+"When creating a new account, you agree to our [terms of service](%s) and [privacy policy](%s)."
+
msgid "auth.terms-privacy-agreement"
msgstr ""
-"When creating a new account, you agree to our terms of service and privacy "
-"policy."
+"When creating a new account, you agree to ourf terms of service and privacy policy."
#: src/app/main/ui/auth/register.cljs
msgid "auth.verification-email-sent"
diff --git a/frontend/translations/es.po b/frontend/translations/es.po
index 6a1d1c5fa4..2b332da799 100644
--- a/frontend/translations/es.po
+++ b/frontend/translations/es.po
@@ -173,10 +173,14 @@ msgid "auth.terms-of-service"
msgstr "Términos de servicio"
#: src/app/main/ui/auth/register.cljs
+#, markdown
+msgid "auth.terms-privacy-agreement-md"
+msgstr ""
+"Al crear una nueva cuenta, aceptas nuestros [términos de servicio](%s) y [política de privacidad](%s)."
+
msgid "auth.terms-privacy-agreement"
msgstr ""
-"Al crear una nueva cuenta, aceptas nuestros términos de servicio y política "
-"de privacidad."
+"Al crear una nueva cuenta, aceptas nuestros [términos de servicio](%s) y [política de privacidad](%s)."
#: src/app/main/ui/auth/register.cljs
msgid "auth.verification-email-sent"