diff --git a/frontend/resources/images/features/blend-modes.gif b/frontend/resources/images/features/blend-modes.gif new file mode 100644 index 000000000..6826d6f38 Binary files /dev/null and b/frontend/resources/images/features/blend-modes.gif differ diff --git a/frontend/resources/images/features/manage-files.gif b/frontend/resources/images/features/manage-files.gif new file mode 100644 index 000000000..8ca2c635e Binary files /dev/null and b/frontend/resources/images/features/manage-files.gif differ diff --git a/frontend/resources/images/features/rtl.gif b/frontend/resources/images/features/rtl.gif new file mode 100644 index 000000000..df3f6d07b Binary files /dev/null and b/frontend/resources/images/features/rtl.gif differ diff --git a/frontend/resources/images/features/select-files.gif b/frontend/resources/images/features/select-files.gif new file mode 100644 index 000000000..8b0c2ff66 Binary files /dev/null and b/frontend/resources/images/features/select-files.gif differ diff --git a/frontend/resources/images/login-on.jpg b/frontend/resources/images/login-on.jpg new file mode 100644 index 000000000..83a7e04bb Binary files /dev/null and b/frontend/resources/images/login-on.jpg differ diff --git a/frontend/resources/locales.json b/frontend/resources/locales.json index 23248e5cd..71fa1f305 100644 --- a/frontend/resources/locales.json +++ b/frontend/resources/locales.json @@ -2255,6 +2255,12 @@ }, "used-in" : [ "src/app/main/ui/dashboard/team_form.cljs", "src/app/main/ui/dashboard/team_form.cljs" ] }, + "labels.create-team.placeholder" : { + "translations" : { + "en" : "Enter new team name" + }, + "used-in" : [ "src/app/main/ui/dashboard/team_form.cljs" ] + }, "labels.dashboard" : { "translations" : { "de" : "Dashboard", @@ -2626,6 +2632,17 @@ }, "unused" : true }, + "labels.release-notes" : { + "translations" : { + "de" : "Versionshinweise", + "en" : "Release notes", + "es" : "Notas de versión", + "fr" : "Notes de version", + "ru" : "примечания к выпуску", + "zh_cn" : "發行說明" + }, + "used-in" : [ "src/app/main/ui/settings/sidebar.cljs" ] + }, "labels.remove" : { "translations" : { "de" : "Entfernen", @@ -6577,10 +6594,5 @@ "zh_cn" : "单击以闭合路径" }, "unused" : true - }, - "labels.create-team.placeholder": { - "translations" : { - "en": "Enter new team name" - } } } diff --git a/frontend/resources/styles/main/partials/modal.scss b/frontend/resources/styles/main/partials/modal.scss index 6e200c7b3..fee4b62d6 100644 --- a/frontend/resources/styles/main/partials/modal.scss +++ b/frontend/resources/styles/main/partials/modal.scss @@ -369,7 +369,7 @@ background-color: $color-white; box-shadow: 0 10px 10px rgba(0,0,0,.2); display: flex; - height: 350px; + min-height: 370px; flex-direction: row; font-family: "sourcesanspro", sans-serif; min-width: 620px; @@ -383,6 +383,7 @@ display: flex; flex-shrink: 0; justify-content: center; + overflow: hidden; padding: $x-big; width: 230px; } @@ -476,6 +477,8 @@ img { border-top-left-radius: 5px; border-bottom-left-radius: 5px; + height: 100%; + width: 106%; } } } diff --git a/frontend/src/app/main/data/auth.cljs b/frontend/src/app/main/data/auth.cljs index 00612a6b0..972f66362 100644 --- a/frontend/src/app/main/data/auth.cljs +++ b/frontend/src/app/main/data/auth.cljs @@ -5,22 +5,23 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.main.data.auth (:require - [cljs.spec.alpha :as s] - [beicon.core :as rx] - [potok.core :as ptk] [app.common.spec :as us] + [app.config :as cf] + [app.main.data.messages :as dm] + [app.main.data.modal :as modal] + [app.main.data.users :as du] [app.main.repo :as rp] [app.main.store :refer [initial-state]] - [app.main.data.users :as du] - [app.main.data.modal :as modal] - [app.main.data.messages :as dm] - [app.util.router :as rt] [app.util.i18n :as i18n :refer [tr]] - [app.util.storage :refer [storage]])) + [app.util.router :as rt] + [app.util.storage :refer [storage]] + [beicon.core :as rx] + [cljs.spec.alpha :as s] + [potok.core :as ptk])) (s/def ::email ::us/email) (s/def ::password string?) @@ -44,11 +45,13 @@ (ptk/reify ::logged-in ptk/WatchEvent (watch [this state stream] - (let [team-id (current-team-id profile)] + (let [team-id (current-team-id profile) + props (:props profile)] (rx/merge (rx/of (du/profile-fetched profile) (rt/nav' :dashboard-projects {:team-id team-id})) - (when-not (get-in profile [:props :onboarding-viewed]) + + (when-not (:onboarding-viewed props) (->> (rx/of (modal/show {:type :onboarding})) (rx/delay 1000)))))))) diff --git a/frontend/src/app/main/data/users.cljs b/frontend/src/app/main/data/users.cljs index a586b8126..bb15a0526 100644 --- a/frontend/src/app/main/data/users.cljs +++ b/frontend/src/app/main/data/users.cljs @@ -9,7 +9,7 @@ (ns app.main.data.users (:require - [app.config :as cfg] + [app.config :as cf] [app.common.data :as d] [app.common.spec :as us] [app.main.data.media :as di] @@ -154,14 +154,17 @@ (defn mark-onboarding-as-viewed - [] - (ptk/reify ::mark-oboarding-as-viewed - ptk/WatchEvent - (watch [_ state stream] - (let [{:keys [id] :as profile} (:profile state)] - (->> (rp/mutation :update-profile-props {:props {:onboarding-viewed true}}) - (rx/map (constantly (fetch-profile)))))))) - + ([] (mark-onboarding-as-viewed nil)) + ([{:keys [version]}] + (ptk/reify ::mark-oboarding-as-viewed + ptk/WatchEvent + (watch [_ state stream] + (let [version (or version (:main @cf/version)) + props (-> (get-in state [:profile :props]) + (assoc :onboarding-viewed true) + (assoc :release-notes-viewed version))] + (->> (rp/mutation :update-profile-props {:props props}) + (rx/map (constantly (fetch-profile))))))))) ;; --- Update Photo @@ -180,7 +183,6 @@ {:file file})] (di/notify-start-loading) - (->> (rx/of file) (rx/map di/validate-file) (rx/map prepare) diff --git a/frontend/src/app/main/ui.cljs b/frontend/src/app/main/ui.cljs index 2c606d7f2..c1232b886 100644 --- a/frontend/src/app/main/ui.cljs +++ b/frontend/src/app/main/ui.cljs @@ -5,10 +5,11 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.main.ui (:require + [app.config :as cf] [app.common.data :as d] [app.common.exceptions :as ex] [app.common.spec :as us] @@ -139,7 +140,10 @@ :dashboard-libraries :dashboard-team-members :dashboard-team-settings) - [:& dashboard {:route route}] + [:* + #_[:div.modal-wrapper + [:& app.main.ui.onboarding/release-notes-modal {:version "1.4"}]] + [:& dashboard {:route route}]] :viewer (let [index (get-in route [:query-params :index]) diff --git a/frontend/src/app/main/ui/dashboard.cljs b/frontend/src/app/main/ui/dashboard.cljs index 52e024ade..230389399 100644 --- a/frontend/src/app/main/ui/dashboard.cljs +++ b/frontend/src/app/main/ui/dashboard.cljs @@ -5,13 +5,14 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.main.ui.dashboard (:require [app.common.exceptions :as ex] [app.common.spec :as us] [app.common.uuid :as uuid] + [app.config :as cf] [app.main.data.dashboard :as dd] [app.main.data.modal :as modal] [app.main.refs :as refs] @@ -26,6 +27,8 @@ [app.main.ui.icons :as i] [app.util.i18n :as i18n :refer [t]] [app.util.router :as rt] + [app.util.timers :as tm] + [beicon.core :as rx] [cuerdas.core :as str] [okulary.core :as l] [rumext.alpha :as mf])) @@ -105,6 +108,16 @@ (mf/deps team-id) (st/emitf (dd/fetch-bundle {:id team-id}))) + (mf/use-effect + (mf/deps) + (fn [] + (let [props (:props profile) + version (:release-notes-viewed props)] + (when (and (:onboarding-viewed props) + (not= version (:main @cf/version)) + (not= "0.0" (:main @cf/version))) + (tm/schedule 1000 #(st/emit! (modal/show {:type :release-notes :version (:main @cf/version)}))))))) + [:& (mf/provider ctx/current-file-id) {:value nil} [:& (mf/provider ctx/current-team-id) {:value team-id} [:& (mf/provider ctx/current-project-id) {:value project-id} diff --git a/frontend/src/app/main/ui/onboarding.cljs b/frontend/src/app/main/ui/onboarding.cljs index 484b3d09c..282d42b61 100644 --- a/frontend/src/app/main/ui/onboarding.cljs +++ b/frontend/src/app/main/ui/onboarding.cljs @@ -19,10 +19,13 @@ [app.util.dom :as dom] [app.util.router :as rt] [app.util.timers :as tm] + [app.util.object :as obj] [cljs.spec.alpha :as s] [rumext.alpha :as mf])) +;; --- ONBOARDING LIGHTBOX + (mf/defc navigation-bullets [{:keys [slide navigate total]}] [:ul.step-dots @@ -34,7 +37,7 @@ [{:keys [next] :as props}] [:div.modal-container.onboarding [:div.modal-left - [:img {:src "images/pot.png" :border "0" :alt "Penpot"}]] + [:img {:src "images/login-on.jpg" :border "0" :alt "Penpot"}]] [:div.modal-right [:div.modal-title [:h2 "Welcome to Penpot!"]] @@ -182,22 +185,6 @@ (s/def ::team-form (s/keys :req-un [::name])) -(defn- on-success - [form response] - (st/emit! (modal/hide) - (rt/nav :dashboard-projects {:team-id (:id response)}))) - -(defn- on-error - [form response] - (st/emit! (dm/error "Error on creating team."))) - -(defn- on-submit - [form event] - (let [mdata {:on-success (partial on-success form) - :on-error (partial on-error form)} - params {:name (get-in @form [:clean-data :name])}] - (st/emit! (dd/create-team (with-meta params mdata))))) - (mf/defc onboarding-team-modal {::mf/register modal/components ::mf/register-as :onboarding-team} @@ -205,9 +192,25 @@ (let [close (mf/use-fn (st/emitf (modal/hide))) form (fm/use-form :spec ::team-form :initial {}) + on-success + (mf/use-callback + (fn [form response] + (st/emit! (modal/hide) + (rt/nav :dashboard-projects {:team-id (:id response)})))) + + on-error + (mf/use-callback + (fn [form response] + (st/emit! (dm/error "Error on creating team.")))) on-submit - (mf/use-callback (partial on-submit form))] + (mf/use-callback + (fn [form event] + (let [mdata {:on-success (partial on-success form) + :on-error (partial on-error form)} + params {:name (get-in @form [:clean-data :name])}] + (st/emit! (dd/create-team (with-meta params mdata))))))] + [:div.modal-overlay [:div.modal-container.onboarding.final.animated.fadeInUp [:div.modal-left @@ -222,6 +225,7 @@ :label "Enter new team name"}] [:& fm/submit-button {:label "Create team"}]]] + [:div.modal-right [:img {:src "images/onboarding-start.jpg" :border "0" :alt "Start designing"}] [:h2 "Start designing"] @@ -232,3 +236,163 @@ [:img.deco {:src "images/deco-left.png" :border "0"}] [:img.deco.right {:src "images/deco-right.png" :border "0"}]]])) + +;;; --- RELEASE NOTES MODAL + +(defmulti render-release-notes :version) + +(mf/defc release-notes-modal + {::mf/register modal/components + ::mf/register-as :release-notes} + [{:keys [version] :as props}] + (let [slide (mf/use-state :start) + klass (mf/use-state "fadeInDown") + + navigate + (mf/use-callback #(reset! slide %)) + + next + (mf/use-callback + (mf/deps slide) + (fn [] + (if (= @slide :start) + (navigate 0) + (navigate (inc @slide))))) + + finish + (mf/use-callback + (st/emitf (modal/hide) + (du/mark-onboarding-as-viewed {:version version}))) + ] + + (mf/use-effect + (mf/deps) + (fn [] + (st/emitf (du/mark-onboarding-as-viewed {:version version})))) + + (mf/use-layout-effect + (mf/deps @slide) + (fn [] + (when (not= :start @slide) + (reset! klass "fadeIn")) + (let [sem (tm/schedule 300 #(reset! klass nil))] + (fn [] + (reset! klass nil) + (tm/dispose! sem))))) + + (render-release-notes + {:next next + :navigate navigate + :finish finish + :klass klass + :slide slide + :version version}))) + +;; This case should never happen; but if happen just hide inmediatelly +;; the modal. +(defmethod render-release-notes :default + [props] + (tm/schedule 0 #(st/emit! (modal/hide))) + (mf/html [:span ""])) + +(defmethod render-release-notes "0.0" + [params] + (render-release-notes (assoc params :version "1.4"))) + +(defmethod render-release-notes "1.4" + [{:keys [slide klass next finish navigate version]}] + (mf/html + (case @slide + :start + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/login-on.jpg" :border "0" :alt "What's new Alpha release 1.4.0"}]] + [:div.modal-right + [:div.modal-title + [:h2 "What's new?"]] + [:span.release "Alpha version " version] + [:div.modal-content + [:p "Penpot continues growing with new features that improve performance, user experience and visual design."] + [:p "We are happy to show you a sneak peak of the most important stuff that the Alpha 1.4.0 version brings."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"]]] + [:img.deco {:src "images/deco-left.png" :border "0"}] + [:img.deco.right {:src "images/deco-right.png" :border "0"}]]]] + + 0 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/select-files.gif" :border "0" :alt "New file selection"}]] + [:div.modal-right + [:div.modal-title + [:h2 "New file selection and open files"]] + [:div.modal-content + [:p "Now you can select files with left click and make multi-selections holding down the shift + left click."] + [:p "To open a file you just have to double click it. You can also open a file in a new tab with right click."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"] + [:& navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]] + + 1 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/manage-files.gif" :border "0" :alt "Manage files"}]] + [:div.modal-right + [:div.modal-title + [:h2 "New files/projects management"]] + [:div.modal-content + [:p "Penpot now allows to duplicate and move files and projects."] + [:p "Also, now you have an easy way to manage files and projects between teams."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"] + [:& navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]] + + 2 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/rtl.gif" :border "0" :alt "RTL support"}]] + [:div.modal-right + [:div.modal-title + [:h2 "RTL support is now available!"]] + [:div.modal-content + [:p "Diversity and inclusion is one major Penpot concern and that's why we love to give support to RTL languages, unlike in most of design tools."] + [:p "If you write in arabic, hebrew or other RTL language text direction will be automatically detected in text layers."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click next} "Continue"] + [:& navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]] + + 3 + [:div.modal-overlay + [:div.animated {:class @klass} + [:div.modal-container.onboarding.feature + [:div.modal-left + [:img {:src "images/features/blend-modes.gif" :border "0" :alt "Blend modes"}]] + [:div.modal-right + [:div.modal-title + [:h2 "New layer opacity and blend modes"]] + [:div.modal-content + [:p "Combining elements visually is an important part of the design process."] + [:p "This is why the standard blend modes and opacity level are now available for each element."]] + [:div.modal-navigation + [:button.btn-secondary {:on-click finish} "Start!"] + [:& navigation-bullets + {:slide @slide + :navigate navigate + :total 4}]]]]]]))) diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index 3b00c1220..b0850b59b 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -5,12 +5,13 @@ ;; This Source Code Form is "Incompatible With Secondary Licenses", as ;; defined by the Mozilla Public License, v. 2.0. ;; -;; Copyright (c) 2020 UXBOX Labs SL +;; Copyright (c) UXBOX Labs SL (ns app.main.ui.settings.sidebar (:require - [app.config :as cfg] + [app.config :as cf] [app.main.data.auth :as da] + [app.main.data.modal :as modal] [app.main.store :as st] [app.main.ui.dashboard.sidebar :refer [profile-section]] [app.main.ui.icons :as i] @@ -48,7 +49,16 @@ go-settings-options (mf/use-callback (mf/deps profile) - (st/emitf (rt/nav :settings-options)))] + (st/emitf (rt/nav :settings-options))) + + show-release-notes + (mf/use-callback + (fn [event] + (let [version (:main @cf/version)] + (if (and (.-ctrlKey ^js event) + (.-altKey ^js event)) + (st/emit! (modal/show {:type :onboarding})) + (st/emit! (modal/show {:type :release-notes :version version}))))))] [:div.sidebar-content [:div.sidebar-content-section @@ -74,7 +84,13 @@ i/tree [:span.element-title (tr "labels.settings")]] - (when cfg/feedback-enabled + [:hr] + + [:li {:on-click show-release-notes} + i/msg-info + [:span.element-title (tr "labels.release-notes")]] + + (when cf/feedback-enabled [:li {:class (when feedback? "current") :on-click go-settings-feedback} i/msg-info