diff --git a/CHANGES.md b/CHANGES.md index 8d58bb61c..8fd1bbad5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,7 @@ - Multiple team invitations on onboarding [Taiga #3084](https://tree.taiga.io/project/penpot/us/3084) - Change text properties position at the sidebar [Taiga #3047](https://tree.taiga.io/project/penpot/us/3047) - Group assets by drag and drop [Taiga #2831](https://tree.taiga.io/project/penpot/us/2831) +- View mode improvements to enable access and use in different conditions [Taiga #3023](https://tree.taiga.io/project/penpot/us/3023) ### :bug: Bugs fixed - Fix menu file not accessible in certain conditions [Taiga #3385](https://tree.taiga.io/project/penpot/issue/3385) diff --git a/frontend/resources/images/icons/go-next.svg b/frontend/resources/images/icons/go-next.svg new file mode 100644 index 000000000..ed48fbcde --- /dev/null +++ b/frontend/resources/images/icons/go-next.svg @@ -0,0 +1 @@ + diff --git a/frontend/resources/images/icons/go-prev.svg b/frontend/resources/images/icons/go-prev.svg new file mode 100644 index 000000000..6737a43ab --- /dev/null +++ b/frontend/resources/images/icons/go-prev.svg @@ -0,0 +1 @@ + diff --git a/frontend/resources/images/icons/reset.svg b/frontend/resources/images/icons/reset.svg new file mode 100644 index 000000000..59dd005ea --- /dev/null +++ b/frontend/resources/images/icons/reset.svg @@ -0,0 +1 @@ + diff --git a/frontend/resources/styles/main/partials/viewer-header.scss b/frontend/resources/styles/main/partials/viewer-header.scss index 378019f3c..1c64546ff 100644 --- a/frontend/resources/styles/main/partials/viewer-header.scss +++ b/frontend/resources/styles/main/partials/viewer-header.scss @@ -3,11 +3,12 @@ background-color: $color-gray-50; border-bottom: 1px solid $color-gray-60; display: grid; - grid-template-columns: 1fr auto 1fr; + grid-template-columns: 45% 10% 45%; height: 48px; padding: 0 $size-4 0 55px; position: relative; justify-content: space-between; + width: 100vw; a { font-size: $fs12; @@ -15,6 +16,7 @@ .nav-zone { justify-content: flex-start; + width: 100%; } .main-icon { @@ -54,10 +56,25 @@ > * { margin-left: $size-5; + @media only screen and (max-width: 1366px) { + margin-left: 0.5rem; + } } .btn-primary { flex-shrink: 0; + svg { + display: none; + } + @media only screen and (max-width: 1366px) { + padding: 0 0.5rem; + svg { + display: inline-block; + } + span { + display: none; + } + } } .view-options { @@ -105,6 +122,7 @@ display: flex; padding: $size-1; position: relative; + width: 100%; .icon { display: flex; @@ -119,9 +137,13 @@ } } + .breadcrumb { + display: grid; + grid-template-columns: auto 10px auto 10px auto; + } + .breadcrumb, .current-frame { - display: flex; position: relative; > span { @@ -140,7 +162,8 @@ } .current-frame { - display: flex; + display: grid; + grid-template-columns: 14px 1fr; span { color: $color-white; margin-right: $size-1; diff --git a/frontend/resources/styles/main/partials/viewer.scss b/frontend/resources/styles/main/partials/viewer.scss index 4f9f13fe1..cc4b72730 100644 --- a/frontend/resources/styles/main/partials/viewer.scss +++ b/frontend/resources/styles/main/partials/viewer.scss @@ -21,6 +21,107 @@ overflow: auto; + & .viewer-go-prev, + & .viewer-go-next { + position: absolute; + height: 100%; + display: flex; + align-items: center; + + .arrow { + display: flex; + align-items: center; + justify-content: center; + border-radius: 12px; + background: $color-gray-50; + width: 24px; + height: 24px; + cursor: pointer; + fill: $color-gray-30; + + svg { + width: 12px; + height: 12px; + } + + &:hover { + background: $color-primary; + fill: $color-black; + } + } + } + + & .viewer-go-next { + right: 0; + padding-right: 29px; + svg { + margin-left: 2px; + } + } + + & .viewer-go-next.right-bar { + right: 256px; + } + + & .viewer-go-prev { + left: 0; + padding-left: 29px; + svg { + margin-right: 2px; + } + } + + & .viewer-go-prev.left-bar { + left: 256px; + } + + & .viewer-bottom { + position: absolute; + bottom: 0; + height: 50px; + width: 100%; + display: flex; + justify-content: space-between; + + &.left-bar { + width: calc(100% - 512px); + } + + .reset { + display: flex; + align-items: center; + border-radius: 12px; + background: $color-gray-50; + width: 24px; + height: 24px; + cursor: pointer; + fill: $color-gray-30; + margin-left: 29px; + + svg { + margin-left: 4px; + width: 15px; + height: 15px; + } + + &:hover { + background: $color-primary; + fill: $color-black; + } + } + + .counter { + display: flex; + align-items: center; + justify-content: center; + border-radius: 12px; + background: $color-gray-50; + width: 67px; + height: 25px; + fill: $color-gray-20; + } + } + & .viewer-wrapper { position: relative; } @@ -42,6 +143,23 @@ transform-origin: center; } } + + & .viewer-wrapper-out { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + + & .comments-right-sidebar { + position: absolute; + right: 0; + top: 50px; + width: 256px; + height: 100%; + } } .viewport-container { diff --git a/frontend/src/app/main/data/comments.cljs b/frontend/src/app/main/data/comments.cljs index 36a9a9e71..3dd8741c0 100644 --- a/frontend/src/app/main/data/comments.cljs +++ b/frontend/src/app/main/data/comments.cljs @@ -243,7 +243,7 @@ (update :workspace-drawing dissoc :comment))))) (defn update-filters - [{:keys [mode show] :as params}] + [{:keys [mode show list] :as params}] (ptk/reify ::update-filters ptk/UpdateEvent (update [_ state] @@ -254,7 +254,10 @@ (assoc :mode mode) (some? show) - (assoc :show show))))))) + (assoc :show show) + + (some? list) + (assoc :list list))))))) (s/def ::create-draft-params (s/keys :req-un [::page-id ::file-id ::position])) diff --git a/frontend/src/app/main/data/viewer.cljs b/frontend/src/app/main/data/viewer.cljs index c79909eec..7dbbe296c 100644 --- a/frontend/src/app/main/data/viewer.cljs +++ b/frontend/src/app/main/data/viewer.cljs @@ -303,6 +303,18 @@ (dcm/close-thread) (rt/nav :viewer pparams (assoc qparams :index (inc index))))))))) + +(def select-first-frame + (ptk/reify ::select-first-frame + ptk/WatchEvent + (watch [_ state _] + (let [route (:route state) + qparams (:query-params route) + pparams (:path-params route)] + (rx/of + (dcm/close-thread) + (rt/nav :viewer pparams (assoc qparams :index 0))))))) + (s/def ::interactions-mode #{:hide :show :show-on-click}) (defn set-interactions-mode diff --git a/frontend/src/app/main/data/viewer/shortcuts.cljs b/frontend/src/app/main/data/viewer/shortcuts.cljs index 4c3aa333e..68971ea27 100644 --- a/frontend/src/app/main/data/viewer/shortcuts.cljs +++ b/frontend/src/app/main/data/viewer/shortcuts.cljs @@ -42,12 +42,12 @@ :fn #(st/emit! dv/toggle-fullscreen)} :next-frame {:tooltip ds/left-arrow - :command "left" + :command ["left" "up"] :subsections [:general-viewer] :fn #(st/emit! dv/select-prev-frame)} :prev-frame {:tooltip ds/right-arrow - :command "right" + :command ["right" "down"] :subsections [:general-viewer] :fn #(st/emit! dv/select-next-frame)} diff --git a/frontend/src/app/main/ui/icons.cljs b/frontend/src/app/main/ui/icons.cljs index 14d531418..b8232b043 100644 --- a/frontend/src/app/main/ui/icons.cljs +++ b/frontend/src/app/main/ui/icons.cljs @@ -76,6 +76,8 @@ (def full-screen-off (icon-xref :full-screen-off)) (def grid (icon-xref :grid)) (def grid-snap (icon-xref :grid-snap)) +(def go-next (icon-xref :go-next)) +(def go-prev (icon-xref :go-prev)) (def help (icon-xref :help)) (def icon-empty (icon-xref :icon-empty)) (def icon-filter (icon-xref :filter)) @@ -143,6 +145,7 @@ (def radius-4 (icon-xref :radius-4)) (def recent (icon-xref :recent)) (def redo (icon-xref :redo)) +(def reset (icon-xref :reset)) (def rotate (icon-xref :rotate)) (def ruler (icon-xref :ruler)) (def ruler-tool (icon-xref :ruler-tool)) diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index c148c3db1..4b84d5c03 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -24,7 +24,7 @@ [app.main.ui.shapes.filters :as filters] [app.main.ui.share-link] [app.main.ui.static :as static] - [app.main.ui.viewer.comments :refer [comments-layer]] + [app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]] [app.main.ui.viewer.handoff :as handoff] [app.main.ui.viewer.header :refer [header]] [app.main.ui.viewer.interactions :as interactions] @@ -32,6 +32,7 @@ [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [app.util.webapi :as wapi] + [cuerdas.core :as str] [goog.events :as events] [rumext.alpha :as mf])) @@ -60,6 +61,113 @@ :height (* height zoom) :vbox (str "0 0 " width " " height)}))) + +(mf/defc viewer-pagination + [{:keys [index num-frames left-bar right-bar] :as props}] + [:* + (when (pos? index) + [:div.viewer-go-prev {:class (when left-bar "left-bar")} + [:div.arrow {:on-click #(st/emit! dv/select-prev-frame)} i/go-prev]]) + (when (< (+ index 1) num-frames) + [:div.viewer-go-next {:class (when right-bar "right-bar")} + [:div.arrow {:on-click #(st/emit! dv/select-next-frame)} i/go-next]]) + [:div.viewer-bottom {:class (when left-bar "left-bar")} + [:div.reset {:on-click #(st/emit! dv/select-first-frame)} i/reset] + [:div.counter (str/join " / " [(+ index 1) num-frames])] + [:span]]]) + + +(mf/defc viewer-wrapper + [{:keys [wrapper-size scroll orig-frame orig-viewport-ref orig-size page file users current-viewport-ref + size frame interactions-mode overlays zoom close-overlay section index] :as props}] + (let [{clist :list} (mf/deref refs/comments-local) + show-comments-list (and (= section :comments) (= :show clist))] + [:* + [:& viewer-pagination {:index index :num-frames (count (:frames page)) :right-bar show-comments-list}] + + (when show-comments-list + [:& comments-sidebar {:users users :frame frame :page page}]) + + [:div.viewer-wrapper + {:style {:width (:width wrapper-size) + :height (:height wrapper-size)}} + [:& (mf/provider ctx/scroll-ctx) {:value @scroll} + [:div.viewer-clipper + [:* + (when orig-frame + [:div.viewport-container + {:ref orig-viewport-ref + :style {:width (:width orig-size) + :height (:height orig-size) + :position "relative"}} + + [:& interactions/viewport + {:frame orig-frame + :base-frame orig-frame + :frame-offset (gpt/point 0 0) + :size orig-size + :page page + :file file + :users users + :interactions-mode :hide}]]) + + [:div.viewport-container + {:ref current-viewport-ref + :style {:width (:width size) + :height (:height size) + :position "relative"}} + + [:& interactions/viewport + {:frame frame + :base-frame frame + :frame-offset (gpt/point 0 0) + :size size + :page page + :file file + :users users + :interactions-mode interactions-mode}] + + (for [overlay overlays] + (let [size-over (calculate-size (:frame overlay) zoom)] + [:* + (when (or (:close-click-outside overlay) + (:background-overlay overlay)) + [:div.viewer-overlay-background + {:class (dom/classnames + :visible (:background-overlay overlay)) + :style {:width (:width wrapper-size) + :height (:height wrapper-size) + :position "absolute" + :left 0 + :top 0} + :on-click #(when (:close-click-outside overlay) + (close-overlay (:frame overlay)))}]) + [:div.viewport-container.viewer-overlay + + {:id (str "overlay-" (-> overlay :frame :id)) + :style {:width (:width size-over) + :height (:height size-over) + :left (* (:x (:position overlay)) zoom) + :top (* (:y (:position overlay)) zoom)}} + [:& interactions/viewport + {:frame (:frame overlay) + :base-frame frame + :frame-offset (:position overlay) + :size size-over + :page page + :file file + :users users + :interactions-mode interactions-mode}]]]))]] + + (when (= section :comments) + [:& comments-layer {:file file + :users users + :frame frame + :page page + :zoom zoom}])]]]])) + + + (mf/defc viewer [{:keys [params data]}] @@ -120,11 +228,6 @@ (when (= section :comments) (st/emit! (dcm/close-thread))))) - close-overlay - (mf/use-callback - (fn [frame] - (st/emit! (dv/close-overlay (:id frame))))) - set-up-new-size (mf/use-callback (fn [_] @@ -288,85 +391,28 @@ :page page :file file :section section - :local local}] + :local local + :index index + :viewer-pagination viewer-pagination}] - [:* - [:div.viewer-wrapper - {:style {:width (:width wrapper-size) - :height (:height wrapper-size)}} - [:& (mf/provider ctx/scroll-ctx) {:value @scroll} - [:div.viewer-clipper - [:* - (when orig-frame - [:div.viewport-container - {:ref orig-viewport-ref - :style {:width (:width orig-size) - :height (:height orig-size) - :position "relative"}} - - [:& interactions/viewport - {:frame orig-frame - :base-frame orig-frame - :frame-offset (gpt/point 0 0) - :size orig-size - :page page - :file file - :users users - :interactions-mode :hide}]]) - - [:div.viewport-container - {:ref current-viewport-ref - :style {:width (:width size) - :height (:height size) - :position "relative"}} - - [:& interactions/viewport - {:frame frame - :base-frame frame - :frame-offset (gpt/point 0 0) - :size size - :page page - :file file - :users users - :interactions-mode interactions-mode}] - - (for [overlay overlays] - (let [size-over (calculate-size (:frame overlay) zoom)] - [:* - (when (or (:close-click-outside overlay) - (:background-overlay overlay)) - [:div.viewer-overlay-background - {:class (dom/classnames - :visible (:background-overlay overlay)) - :style {:width (:width wrapper-size) - :height (:height wrapper-size) - :position "absolute" - :left 0 - :top 0} - :on-click #(when (:close-click-outside overlay) - (close-overlay (:frame overlay)))}]) - [:div.viewport-container.viewer-overlay - {:id (str "overlay-" (str (:id (:frame overlay)))) - :style {:width (:width size-over) - :height (:height size-over) - :left (* (:x (:position overlay)) zoom) - :top (* (:y (:position overlay)) zoom)}} - [:& interactions/viewport - {:frame (:frame overlay) - :base-frame frame - :frame-offset (:position overlay) - :size size-over - :page page - :file file - :users users - :interactions-mode interactions-mode}]]]))]] - - (when (= section :comments) - [:& comments-layer {:file file - :users users - :frame frame - :page page - :zoom zoom}])]]]]))]]])) + + [:& viewer-wrapper + {:wrapper-size wrapper-size + :scroll scroll + :orig-frame orig-frame + :orig-viewport-ref orig-viewport-ref + :orig-size orig-size + :page page + :file file + :users users + :current-viewport-ref current-viewport-ref + :size size + :frame frame + :interactions-mode interactions-mode + :overlays overlays + :zoom zoom + :section section + :index index}]))]]])) ;; --- Component: Viewer Page diff --git a/frontend/src/app/main/ui/viewer/comments.cljs b/frontend/src/app/main/ui/viewer/comments.cljs index c813485fb..ad29c0e40 100644 --- a/frontend/src/app/main/ui/viewer/comments.cljs +++ b/frontend/src/app/main/ui/viewer/comments.cljs @@ -15,6 +15,7 @@ [app.main.ui.comments :as cmt] [app.main.ui.components.dropdown :refer [dropdown]] [app.main.ui.icons :as i] + [app.main.ui.workspace.comments :as wc] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] [okulary.core :as l] @@ -22,7 +23,7 @@ (mf/defc comments-menu [] - (let [{cmode :mode cshow :show} (mf/deref refs/comments-local) + (let [{cmode :mode cshow :show clist :list} (mf/deref refs/comments-local) show-dropdown? (mf/use-state false) toggle-dropdown (mf/use-fn #(swap! show-dropdown? not)) @@ -36,7 +37,12 @@ update-show (mf/use-callback (fn [mode] - (st/emit! (dcm/update-filters {:show mode}))))] + (st/emit! (dcm/update-filters {:show mode})))) + + update-list + (mf/use-callback + (fn [show-list] + (st/emit! (dcm/update-filters {:list show-list}))))] [:div.view-options {:on-click toggle-dropdown} [:span.label (tr "labels.comments")] @@ -59,7 +65,14 @@ [:li {:class (dom/classnames :selected (= :pending cshow)) :on-click #(update-show (if (= :pending cshow) :all :pending))} [:span.icon i/tick] - [:span.label (tr "labels.hide-resolved-comments")]]]]])) + [:span.label (tr "labels.hide-resolved-comments")]] + + [:hr] + + [:li {:class (dom/classnames :selected (= :show clist)) + :on-click #(update-list (if (= :show clist) :hide :show))} + [:span.icon i/tick] + [:span.label (tr "labels.show-comments-list")]]]]])) (defn- frame-contains? @@ -156,3 +169,17 @@ :on-cancel on-draft-cancel :on-submit on-draft-submit :zoom zoom}])]]])) + + +(mf/defc comments-sidebar + [{:keys [users frame page]}] + (let [profile (mf/deref refs/profile) + cstate (mf/deref refs/comments-local) + threads-map (mf/deref threads-ref) + threads (->> (vals threads-map) + (dcm/apply-filters cstate profile) + (filter (fn [{:keys [position]}] + (frame-contains? frame position))))] + [:aside.settings-bar.settings-bar-right.comments-right-sidebar + [:div.settings-bar-inside + [:& wc/comments-sidebar {:users users :threads threads :page-id (:id page)}]]])) diff --git a/frontend/src/app/main/ui/viewer/handoff.cljs b/frontend/src/app/main/ui/viewer/handoff.cljs index 4a00631ea..a17fecc13 100644 --- a/frontend/src/app/main/ui/viewer/handoff.cljs +++ b/frontend/src/app/main/ui/viewer/handoff.cljs @@ -6,13 +6,13 @@ (ns app.main.ui.viewer.handoff (:require - [app.main.data.viewer :as dv] + [app.main.data.viewer :as dv] [app.main.store :as st] [app.main.ui.viewer.handoff.left-sidebar :refer [left-sidebar]] [app.main.ui.viewer.handoff.render :refer [render-frame-svg]] [app.main.ui.viewer.handoff.right-sidebar :refer [right-sidebar]] [app.util.dom :as dom] - [app.util.keyboard :as kbd] + [app.util.keyboard :as kbd] [goog.events :as events] [rumext.alpha :as mf]) (:import goog.events.EventType)) @@ -25,7 +25,7 @@ (st/emit! (dv/select-shape (:id frame))))) (mf/defc viewport - [{:keys [local file page frame]}] + [{:keys [local file page frame index viewer-pagination]}] (let [on-mouse-wheel (fn [event] (when (kbd/mod? event) @@ -58,6 +58,7 @@ :local local :page page}] [:div.handoff-svg-wrapper {:on-click (handle-select-frame frame)} + [:& viewer-pagination {:index index :num-frames (count (:frames page)) :left-bar true :right-bar true}] [:div.handoff-svg-container [:& render-frame-svg {:frame frame :page page :local local}]]] diff --git a/frontend/src/app/main/ui/viewer/header.cljs b/frontend/src/app/main/ui/viewer/header.cljs index ad5f2e49c..33d2df800 100644 --- a/frontend/src/app/main/ui/viewer/header.cljs +++ b/frontend/src/app/main/ui/viewer/header.cljs @@ -107,18 +107,17 @@ i/full-screen)] (when (:is-admin permissions) - [:span.btn-primary {:on-click open-share-dialog} (tr "labels.share-prototype")]) + [:span.btn-primary {:on-click open-share-dialog} i/export [:span (tr "labels.share-prototype")]]) (when (:can-edit permissions) [:span.btn-text-dark {:on-click go-to-workspace} (tr "labels.edit-file")])])) (mf/defc header-sitemap - [{:keys [project file page frame index] :as props}] + [{:keys [project file page frame] :as props}] (let [project-name (:name project) file-name (:name file) page-name (:name page) frame-name (:name frame) - total (count (:frames page)) show-dropdown? (mf/use-state false) toggle-thumbnails @@ -151,7 +150,7 @@ [:span "/"] [:span.page-name page-name] - [:span.icon i/arrow-down] + [:& dropdown {:show @show-dropdown? :on-close close-dropdown} @@ -161,12 +160,12 @@ :on-click (partial navigate-to id)} (get-in file [:data :pages-index id :name])])]]] + [:span.icon {:on-click open-dropdown} i/arrow-down] [:div.current-frame {:on-click toggle-thumbnails} [:span.label "/"] - [:span.label frame-name] - [:span.icon i/arrow-down] - [:span.counters (str (inc index) " / " total)]]])) + [:span.label frame-name]] + [:span.icon {:on-click toggle-thumbnails} i/arrow-down]])) (mf/defc header diff --git a/frontend/src/app/main/ui/workspace/comments.cljs b/frontend/src/app/main/ui/workspace/comments.cljs index 322aa473c..3963cf933 100644 --- a/frontend/src/app/main/ui/workspace/comments.cljs +++ b/frontend/src/app/main/ui/workspace/comments.cljs @@ -57,20 +57,23 @@ [:span.label (tr "labels.hide-resolved-comments")]]])) (mf/defc comments-sidebar - [] + [{:keys [users threads page-id]}] (let [threads-map (mf/deref refs/threads-ref) profile (mf/deref refs/profile) - users (mf/deref refs/users) + users-refs (mf/deref refs/users) + users (or users users-refs) local (mf/deref refs/comments-local) options? (mf/use-state false) + threads (if (nil? threads) + (->> (vals threads-map) + (sort-by :modified-at) + (reverse) + (dcm/apply-filters local profile)) + threads) + tgroups (->> threads + (dcm/group-threads-by-page)) - tgroups (->> (vals threads-map) - (sort-by :modified-at) - (reverse) - (dcm/apply-filters local profile) - (dcm/group-threads-by-page)) - - page-id (mf/use-ctx ctx/current-page-id) + page-id (or page-id (mf/use-ctx ctx/current-page-id)) on-thread-click (mf/use-callback @@ -87,7 +90,7 @@ [:div.comments-section.comment-threads-section [:div.workspace-comment-threads-sidebar-header - [:div.label "Comments"] + [:div.label (tr "labels.comments")] [:div.options {:on-click #(reset! options? true)} [:div.label (case (:mode local) (nil :all) (tr "labels.all") diff --git a/frontend/translations/en.po b/frontend/translations/en.po index 5e36646de..156b7ffc7 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -1182,6 +1182,9 @@ msgstr "Help Center" msgid "labels.hide-resolved-comments" msgstr "Hide resolved comments" +msgid "labels.show-comments-list" +msgstr "Show comments list" + msgid "labels.icons" msgstr "Icons" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 64520a989..7d521607a 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -1246,6 +1246,9 @@ msgstr "Centro de ayuda" msgid "labels.hide-resolved-comments" msgstr "Ocultar comentarios resueltos" +msgid "labels.show-comments-list" +msgstr "Mostrar lista de comentarios" + msgid "labels.icons" msgstr "Iconos"