mirror of
https://github.com/penpot/penpot.git
synced 2025-02-12 18:18:24 -05:00
🎉 Add new hero projects
This commit is contained in:
parent
61cb43f2f0
commit
bf63e9da95
12 changed files with 301 additions and 30 deletions
|
@ -1,4 +1,8 @@
|
|||
[{:id "penpot-design-system"
|
||||
[{:id "tutorial-for-beginners"
|
||||
:name "Tutorial for beginners"
|
||||
:thumbnail-uri "https://penpot.app/images/libraries/tutorial-for-beginners.jpg"
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/tutorial-for-beginners.penpot"}
|
||||
{:id "penpot-design-system"
|
||||
:name "Penpot Design System"
|
||||
:thumbnail-uri "https://penpot.app/images/libraries/cover-ds-penpot.jpg"
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/binary-files/Penpot-Design-system.penpot"}
|
||||
|
|
|
@ -246,6 +246,8 @@
|
|||
|
||||
props (-> (audit/extract-utm-params params)
|
||||
(merge (:props params))
|
||||
(merge {:viewed-tutorial? false
|
||||
:viewed-walkthrough? false})
|
||||
(db/tjson))
|
||||
|
||||
password (if-let [password (:password params)]
|
||||
|
|
BIN
frontend/resources/images/hands-on-tutorial.png
Normal file
BIN
frontend/resources/images/hands-on-tutorial.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 148 KiB |
BIN
frontend/resources/images/walkthrough-cover.png
Normal file
BIN
frontend/resources/images/walkthrough-cover.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 113 KiB |
|
@ -43,13 +43,9 @@
|
|||
}
|
||||
}
|
||||
.invite {
|
||||
background-color: $color-primary;
|
||||
color: $color-black;
|
||||
width: 180px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
align-self: flex-end;
|
||||
cursor: pointer;
|
||||
}
|
||||
img {
|
||||
width: 274px;
|
||||
|
@ -61,6 +57,112 @@
|
|||
}
|
||||
}
|
||||
|
||||
.hero-projects {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 30px;
|
||||
margin: 0 1rem 1rem 1.2rem;
|
||||
.tutorial,
|
||||
.walkthrough {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
position: relative;
|
||||
border: 2px solid $color-gray-10;
|
||||
border-radius: 8px;
|
||||
min-height: 211px;
|
||||
|
||||
.img {
|
||||
border-top-left-radius: 6px;
|
||||
border-bottom-left-radius: 6px;
|
||||
padding: 30px;
|
||||
display: block;
|
||||
background-color: #e0e4e9;
|
||||
}
|
||||
|
||||
.text {
|
||||
padding: 30px;
|
||||
.title {
|
||||
color: $color-black;
|
||||
font-size: $fs24;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.info {
|
||||
color: $color-gray-30;
|
||||
margin-bottom: 20px;
|
||||
font-size: $fs16;
|
||||
}
|
||||
}
|
||||
.action {
|
||||
font-family: "worksans", sans-serif;
|
||||
width: 180px;
|
||||
height: 40px;
|
||||
}
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: $size-5;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
margin: 20px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
.icon {
|
||||
svg {
|
||||
fill: $color-gray-30;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
transform: rotate(45deg);
|
||||
&:hover {
|
||||
fill: $color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1846px) {
|
||||
grid-template-columns: 190px 1fr;
|
||||
}
|
||||
@media (max-width: 1526px) {
|
||||
grid-template-columns: 1fr;
|
||||
.img {
|
||||
display: none;
|
||||
width: 0;
|
||||
}
|
||||
.text {
|
||||
.info {
|
||||
// font-size: $fs12;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.walkthrough {
|
||||
.img {
|
||||
background-image: url("/images/walkthrough-cover.png");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
.tutorial {
|
||||
.img {
|
||||
background-image: url("/images/hands-on-tutorial.png");
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
.loader {
|
||||
display: flex;
|
||||
svg#loader-pencil {
|
||||
width: 31px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-container {
|
||||
background-color: $color-dashboard;
|
||||
flex: 1 0 0;
|
||||
|
@ -328,8 +430,8 @@
|
|||
width: 100%;
|
||||
text-align: right;
|
||||
height: 56px;
|
||||
cursor: pointer;
|
||||
div {
|
||||
cursor: pointer;
|
||||
height: 58px;
|
||||
display: inline-block;
|
||||
line-height: 58px;
|
||||
|
|
|
@ -296,7 +296,7 @@
|
|||
(rx/map recent-files-fetched)))))))
|
||||
|
||||
|
||||
;; --- EVENT: fetch-team-invitations
|
||||
;; --- EVENT: fetch-template-files
|
||||
|
||||
(defn builtin-templates-fetched
|
||||
[libraries]
|
||||
|
|
|
@ -323,7 +323,6 @@
|
|||
(dcm/close-thread)
|
||||
(rt/nav :viewer pparams (assoc qparams :index (inc index)))))))))
|
||||
|
||||
|
||||
(def select-first-frame
|
||||
(ptk/reify ::select-first-frame
|
||||
ptk/WatchEvent
|
||||
|
|
|
@ -64,7 +64,9 @@
|
|||
|
||||
(mf/defc templates-section
|
||||
[{:keys [default-project-id profile project team content-width] :as props}]
|
||||
(let [templates (mf/deref builtin-templates)
|
||||
(let [templates (->> (mf/deref builtin-templates)
|
||||
(filter #(not= (:id %) "tutorial-for-beginners")))
|
||||
|
||||
route (mf/deref refs/route)
|
||||
route-name (get-in route [:data :name])
|
||||
section (if (= route-name :dashboard-files)
|
||||
|
@ -141,8 +143,8 @@
|
|||
:section section})))]
|
||||
|
||||
[:div.dashboard-templates-section {:class (when collapsed "collapsed")}
|
||||
[:div.title {:on-click toggle-collapse}
|
||||
[:div
|
||||
[:div.title
|
||||
[:div {:on-click toggle-collapse}
|
||||
[:span (tr "dashboard.libraries-and-templates")]
|
||||
[:span.icon (if collapsed i/arrow-up i/arrow-down)]]]
|
||||
[:div.content {:ref content-ref
|
||||
|
@ -192,7 +194,10 @@
|
|||
(case section
|
||||
:dashboard-projects
|
||||
[:*
|
||||
[:& projects-section {:team team :projects projects :profile profile}]
|
||||
[:& projects-section {:team team
|
||||
:projects projects
|
||||
:profile profile
|
||||
:default-project-id default-project-id}]
|
||||
[:& templates-section {:profile profile
|
||||
:project project
|
||||
:default-project-id default-project-id
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
[app.common.math :as mth]
|
||||
[app.main.data.dashboard :as dd]
|
||||
[app.main.data.events :as ev]
|
||||
[app.main.data.messages :as dm]
|
||||
[app.main.data.modal :as modal]
|
||||
[app.main.data.users :as du]
|
||||
[app.main.refs :as refs]
|
||||
|
@ -51,10 +52,78 @@
|
|||
[:div.info
|
||||
[:span (tr "dasboard.team-hero.text")]
|
||||
[:a {:on-click go-members} (tr "dasboard.team-hero.management")]]]
|
||||
[:button.invite {:on-click invite-member} (tr "onboarding.choice.team-up.invite-members")]
|
||||
[:button.btn-primary.invite {:on-click invite-member} (tr "onboarding.choice.team-up.invite-members")]
|
||||
[:button.close {:on-click close-banner}
|
||||
[:span i/close]]]))
|
||||
|
||||
(def builtin-templates
|
||||
(l/derived :builtin-templates st/state))
|
||||
|
||||
(mf/defc tutorial-project
|
||||
[{:keys [close-tutorial default-project-id] :as props}]
|
||||
(let [state (mf/use-state
|
||||
{:status :waiting
|
||||
:file nil})
|
||||
|
||||
template (->> (mf/deref builtin-templates)
|
||||
(filter #(= (:id %) "tutorial-for-beginners"))
|
||||
first)
|
||||
|
||||
on-template-cloned-success
|
||||
(mf/use-callback
|
||||
(fn [response]
|
||||
(swap! state #(assoc % :status :success :file (:first response)))
|
||||
(st/emit! (dd/go-to-workspace {:id (first response) :project-id default-project-id :name "tutorial"})
|
||||
(du/update-profile-props {:viewed-tutorial? true}))))
|
||||
|
||||
on-template-cloned-error
|
||||
(fn []
|
||||
(swap! state #(assoc % :status :waiting))
|
||||
(st/emit!
|
||||
(dm/error (tr "dashboard.libraries-and-templates.import-error"))))
|
||||
|
||||
download-tutorial
|
||||
(fn []
|
||||
(let [mdata {:on-success on-template-cloned-success :on-error on-template-cloned-error}
|
||||
params {:project-id default-project-id :template-id (:id template)}]
|
||||
(swap! state #(assoc % :status :importing))
|
||||
(st/emit! (with-meta (dd/clone-template (with-meta params mdata))
|
||||
{::ev/origin "get-started-hero-block"}))))]
|
||||
[:div.tutorial
|
||||
[:div.img]
|
||||
[:div.text
|
||||
[:div.title (tr "dasboard.tutorial-hero.title")]
|
||||
[:div.info (tr "dasboard.tutorial-hero.info")]
|
||||
[:button.btn-primary.action {:on-click download-tutorial}
|
||||
(case (:status @state)
|
||||
:waiting (tr "dasboard.tutorial-hero.start")
|
||||
:importing [:span.loader i/loader-pencil]
|
||||
:success ""
|
||||
)
|
||||
]]
|
||||
[:button.close
|
||||
{:on-click close-tutorial}
|
||||
[:span.icon i/close]]]))
|
||||
|
||||
(mf/defc interface-walkthrough
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [close-walkthrough] :as props}]
|
||||
(let [handle-walkthrough-link
|
||||
(fn []
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-walkthrough"
|
||||
::ev/origin "get-started-hero-block"
|
||||
:section "dashboard"})))]
|
||||
[:div.walkthrough
|
||||
[:div.img]
|
||||
[:div.text
|
||||
[:div.title (tr "dasboard.walkthrough-hero.title")]
|
||||
[:div.info (tr "dasboard.walkthrough-hero.info")]
|
||||
[:a.btn-primary.action {:href " https://design.penpot.app/walkthrough" :target "_blank" :on-click handle-walkthrough-link}
|
||||
(tr "dasboard.walkthrough-hero.start")]]
|
||||
[:button.close
|
||||
{:on-click close-walkthrough}
|
||||
[:span.icon i/close]]]))
|
||||
|
||||
(mf/defc project-item
|
||||
[{:keys [project first? team files] :as props}]
|
||||
(let [locale (mf/deref i18n/locale)
|
||||
|
@ -215,19 +284,37 @@
|
|||
(l/derived :dashboard-recent-files st/state))
|
||||
|
||||
(mf/defc projects-section
|
||||
[{:keys [team projects profile] :as props}]
|
||||
(let [projects (->> (vals projects)
|
||||
(sort-by :modified-at)
|
||||
(reverse))
|
||||
recent-map (mf/deref recent-files-ref)
|
||||
props (some-> profile (get :props {}))
|
||||
team-hero? (:team-hero? props true)
|
||||
[{:keys [team projects profile default-project-id] :as props}]
|
||||
(let [projects (->> (vals projects)
|
||||
(sort-by :modified-at)
|
||||
(reverse))
|
||||
recent-map (mf/deref recent-files-ref)
|
||||
props (some-> profile (get :props {}))
|
||||
team-hero? (:team-hero? props true)
|
||||
tutorial-viewed? (:viewed-tutorial? props true)
|
||||
walkthrough-viewed? (:viewed-walkthrough? props true)
|
||||
|
||||
close-banner (fn []
|
||||
(st/emit!
|
||||
(du/update-profile-props {:team-hero? false})
|
||||
(ptk/event ::ev/event {::ev/name "dont-show-team-up-hero"
|
||||
::ev/origin "dashboard"})))]
|
||||
close-banner (fn []
|
||||
(st/emit!
|
||||
(du/update-profile-props {:team-hero? false})
|
||||
(ptk/event ::ev/event {::ev/name "dont-show-team-up-hero"
|
||||
::ev/origin "dashboard"})))
|
||||
|
||||
close-tutorial (fn []
|
||||
(st/emit!
|
||||
(du/update-profile-props {:viewed-tutorial? true})
|
||||
(ptk/event ::ev/event {::ev/name "dont-show"
|
||||
::ev/origin "get-started-hero-block"
|
||||
:type "tutorial"
|
||||
:section "dashboard"})))
|
||||
|
||||
close-walkthrough (fn []
|
||||
(st/emit!
|
||||
(du/update-profile-props {:viewed-walkthrough? true})
|
||||
(ptk/event ::ev/event {::ev/name "dont-show"
|
||||
::ev/origin "get-started-hero-block"
|
||||
:type "walkthrough"
|
||||
:section "dashboard"})))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps team)
|
||||
|
@ -250,6 +337,16 @@
|
|||
[:& team-hero
|
||||
{:team team
|
||||
:close-banner close-banner}])
|
||||
(when (or (not tutorial-viewed?) (not walkthrough-viewed?))
|
||||
[:div.hero-projects
|
||||
(when (and (not tutorial-viewed?) (:is-default team))
|
||||
[:& tutorial-project
|
||||
{:close-tutorial close-tutorial
|
||||
:default-project-id default-project-id}])
|
||||
|
||||
(when (and (not walkthrough-viewed?) (:is-default team))
|
||||
[:& interface-walkthrough
|
||||
{:close-walkthrough close-walkthrough}])])
|
||||
|
||||
[:section.dashboard-container.no-bg
|
||||
(for [{:keys [id] :as project} projects]
|
||||
|
|
|
@ -202,9 +202,11 @@
|
|||
(vals)
|
||||
(filter cph/text-shape?)))
|
||||
|
||||
zoom (:zoom local)
|
||||
frames (:frames page)
|
||||
frame (get frames index)
|
||||
zoom (:zoom local)
|
||||
zoom-type (:zoom-type local)
|
||||
|
||||
frames (:frames page)
|
||||
frame (get frames index)
|
||||
|
||||
fullscreen? (mf/deref refs/viewer-fullscreen?)
|
||||
overlays (:overlays local)
|
||||
|
@ -262,7 +264,6 @@
|
|||
(reset! scroll (dom/get-target-scroll event)))]
|
||||
|
||||
(hooks/use-shortcuts ::viewer sc/shortcuts)
|
||||
|
||||
(when (nil? page)
|
||||
(ex/raise :type :not-found))
|
||||
|
||||
|
@ -313,9 +314,21 @@
|
|||
(wapi/request-fullscreen wrapper)
|
||||
(wapi/exit-fullscreen))))))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps page)
|
||||
(fn []
|
||||
(case zoom-type
|
||||
:fit (st/emit! dv/zoom-to-fit)
|
||||
:fill (st/emit! dv/zoom-to-fill)
|
||||
nil)))
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps index)
|
||||
(fn []
|
||||
(case zoom-type
|
||||
:fit (st/emit! dv/zoom-to-fit)
|
||||
:fill (st/emit! dv/zoom-to-fill)
|
||||
nil)
|
||||
;; Navigate animation needs to be started after navigation
|
||||
;; is complete, and we have the next page index.
|
||||
(when (and current-animation
|
||||
|
|
|
@ -476,6 +476,30 @@ msgstr "Penpot is meant for teams. Invite members to work together on projects a
|
|||
msgid "dasboard.team-hero.management"
|
||||
msgstr "Team management"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.tutorial-hero.title"
|
||||
msgstr "Hands on Tutorial"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.tutorial-hero.info"
|
||||
msgstr "Learn the basics at Penpot while having some fun with this hands on tutorial."
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.tutorial-hero.start"
|
||||
msgstr "Start the tutorial"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.walkthrough-hero.title"
|
||||
msgstr "Interface Walkthrough"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.walkthrough-hero.info"
|
||||
msgstr "Take a walk through Penpot and get to know its main features."
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.walkthrough-hero.start"
|
||||
msgstr "Start the tour"
|
||||
|
||||
#: src/app/main/data/dashboard.cljs
|
||||
msgid "dashboard.new-file-prefix"
|
||||
msgstr "New File"
|
||||
|
|
|
@ -496,6 +496,31 @@ msgstr " Penpot está dirigido a equipos. Invita a personas para trabajar conjun
|
|||
msgid "dasboard.team-hero.management"
|
||||
msgstr "Gestión del equipo"
|
||||
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.tutorial-hero.title"
|
||||
msgstr "Tutorial práctico"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.tutorial-hero.info"
|
||||
msgstr "Aprende los básicos de Penpot mientras pasas un buen rato con este tutorial práctico."
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.tutorial-hero.start"
|
||||
msgstr "Comenzar tutorial"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.walkthrough-hero.title"
|
||||
msgstr "Recorrido por el interfaz"
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.walkthrough-hero.info"
|
||||
msgstr " Da un paseo por Penpot para conocer sus principales funcionalidades."
|
||||
|
||||
#: src/app/main/ui/dashboard/projects.cljs
|
||||
msgid "dasboard.walkthrough-hero.start"
|
||||
msgstr "Comenzar"
|
||||
|
||||
#: src/app/main/data/dashboard.cljs
|
||||
msgid "dashboard.new-project-prefix"
|
||||
msgstr "Nuevo Proyecto"
|
||||
|
|
Loading…
Add table
Reference in a new issue