Merge pull request #1534 from penpot/feat/toolbars-redesign

Toolbars Redesign
This commit is contained in:
Andrey Antukh 2022-02-04 09:26:22 +01:00 committed by GitHub
commit b194c0c5d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1146 additions and 434 deletions

View File

@ -18,6 +18,7 @@
- Improve file menu by adding semantically groups [Github #1203](https://github.com/penpot/penpot/issues/1203)
- Add update components in bulk option in context menu [Taiga #1975](https://tree.taiga.io/project/penpot/us/1975)
- Create first E2E tests [Taiga #2608](https://tree.taiga.io/project/penpot/task/2608), [Taiga #2608](https://tree.taiga.io/project/penpot/task/2608)
- Redesign of workspace toolbars [Taiga #2319](https://tree.taiga.io/project/penpot/us/2319)
### :bug: Bugs fixed
### :arrow_up: Deps updates

View File

@ -11,6 +11,13 @@ body {
display: flex;
flex-direction: column;
font-family: "worksans", sans-serif;
width: 100vw;
height: 100vh;
overflow: hidden;
}
#app {
width: 100vw;
height: 100vh;
overflow: hidden;
}

View File

@ -55,6 +55,7 @@
@import "main/partials/zoom-widget";
@import "main/partials/activity-bar";
@import "main/partials/color-palette";
@import "main/partials/text-palette";
@import "main/partials/colorpicker";
@import "main/partials/dashboard";
@import "main/partials/dashboard-header";

View File

@ -1,4 +1,5 @@
$width-settings-bar: 16rem;
$width-left-toolbar: 48px;
$width-settings-bar: 256px;
.handoff-layout {
height: 100vh;

View File

@ -5,30 +5,26 @@
// Copyright (c) UXBOX Labs SL
.color-cell {
display: grid;
grid-template-columns: 100%;
grid-template-rows: 1fr auto;
height: 100%;
justify-items: center;
width: 65px;
.color-bullet {
// Creates strange artifacts
border: 2px solid $color-gray-60;
// box-shadow: 0 0 0 2px $color-gray-60;
border-radius: 50%;
position: relative;
width: var(--bullet-size);
height: var(--bullet-size);
&:hover {
border-color: $color-primary;
}
}
&.cell-big .color-bullet {
width: 50px;
height: 50px;
}
&.cell-small .color-bullet {
width: 40px;
height: 40px;
}
.color-bullet.color-big {
width: 50px;
height: 50px;
& > * {
overflow: hidden;
}
}
@ -41,7 +37,6 @@
ul.palette-menu .color-bullet {
width: 20px;
height: 20px;
border-radius: 12px;
border: 1px solid $color-gray-10;
margin-right: 5px;
background-size: 8px;
@ -67,14 +62,12 @@ ul.palette-menu .color-bullet {
grid-area: color;
width: 20px;
height: 20px;
border-radius: 12px;
border: 1px solid $color-gray-10;
background-size: 8px;
}
.asset-section .asset-list-item .color-bullet {
border: 1px solid $color-gray-20;
border-radius: 10px;
height: 20px;
margin-right: $size-1;
width: 20px;
@ -91,38 +84,31 @@ ul.palette-menu .color-bullet {
.color-bullet {
display: flex;
flex-direction: row;
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=")
left center;
background-color: $color-white;
border-radius: 50%;
& > * {
& .color-bullet-wrapper {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=")
left center;
background-color: $color-white;
clip-path: circle(50%);
display: flex;
flex-direction: row;
height: 100%;
width: 100%;
}
&.is-gradient {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADFJREFUOE9jZGBgEAFifOANPknGUQMYhkkYEEgG+NMJKAwIAbwJbdQABnBCIgRoG4gAIF8IsXB/Rs4AAAAASUVORK5CYII=")
left center;
background-color: $color-white;
}
& .color-bullet-wrapper > * {
width: 100%;
height: 100%;
}
}
.color-bullet.is-library-color .color-bullet-left,
.selected-colors .color-bullet .color-bullet-left {
border-radius: 10px 0 0 10px;
}
.color-bullet.is-library-color .color-bullet-right,
.selected-colors .color-bullet .color-bullet-right {
border-radius: 0 10px 10px 0;
}
.color-palette .color-bullet .color-bullet-left {
border-radius: 25px 0 0 25px;
}
.color-palette .color-bullet .color-bullet-right {
border-radius: 0 25px 25px 0;
}
.color-data .color-bullet.is-library-color {
border-radius: 50%;
}
.color-data .color-bullet.multiple {
background: transparent;
@ -133,7 +119,7 @@ ul.palette-menu .color-bullet {
.color-data .color-bullet {
border: 1px solid $color-gray-30;
border-radius: $br-small;
border-radius: 50%;
cursor: pointer;
display: flex;
align-items: center;
@ -144,10 +130,6 @@ ul.palette-menu .color-bullet {
margin: 5px 4px 0 0;
width: 20px;
&.color-name {
border-radius: 10px;
}
&.palette-th {
align-items: center;
border: 1px solid $color-gray-30;
@ -198,3 +180,11 @@ ul.palette-menu .color-bullet {
fill: $color-black;
}
}
.color-data .color-bullet.is-not-library-color {
border-radius: $br-small;
& .color-bullet-wrapper {
clip-path: none;
}
}

View File

@ -9,11 +9,10 @@
align-items: center;
background-color: $color-gray-50;
border-top: 1px solid $color-gray-60;
display: flex;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: grid;
grid-template-columns: auto auto 1fr auto auto;
z-index: 11;
& .right-arrow,
@ -46,16 +45,21 @@
@include animation(0, 0.5s, fadeOutDown);
}
&.left-sidebar-open {
left: 303px;
width: calc(100% - 303px);
}
& .context-menu-items {
bottom: 1.5rem;
top: initial;
min-width: 10rem;
}
& .resize-area {
position: absolute;
height: 8px;
width: 100%;
z-index: 10;
cursor: ns-resize;
top: 0;
left: 0;
}
}
.color-palette-actions {
@ -119,8 +123,8 @@
display: flex;
overflow: hidden;
width: 100%;
height: 5rem;
padding: 0.25rem;
height: 100%;
&.size-small {
height: 3.5rem;
@ -134,6 +138,7 @@
transition: all 0.6s ease;
width: 100%;
scroll-behavior: smooth;
height: 100%;
}
.color-cell {
@ -144,24 +149,21 @@
flex-shrink: 0;
position: relative;
&.cell-big {
flex-basis: 66px;
}
&.cell-small {
flex-basis: 52px;
}
.color-text {
color: $color-gray-20;
font-size: $fs12;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 66px;
width: 65px;
text-align: center;
margin-top: 0.25rem;
.no-text & {
display: none;
}
}
&.current {
.color-text {
color: $color-gray-50;
@ -252,7 +254,7 @@
ul.palette-menu {
left: 8px;
top: auto;
bottom: 4.5rem;
bottom: var(--height);
color: $color-black;
li {

View File

@ -5,16 +5,8 @@
// Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
// Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
$width-left-toolbar: 48px;
.left-toolbar {
background-color: $color-gray-50;
bottom: 0;
height: 100%;
position: fixed;
left: 0;
width: $width-left-toolbar;
z-index: 11;
}
.left-toolbar-inside {
@ -23,7 +15,6 @@ $width-left-toolbar: 48px;
display: flex;
flex-direction: column;
overflow: visible;
padding-top: 48px;
height: 100%;
}
@ -44,6 +35,7 @@ $width-left-toolbar: 48px;
justify-content: center;
position: relative;
width: 48px;
color: $color-gray-20;
svg {
fill: $color-gray-20;
@ -53,6 +45,7 @@ $width-left-toolbar: 48px;
&:hover {
background-color: $color-primary;
color: $color-gray-50;
svg {
fill: $color-gray-50;
@ -61,6 +54,7 @@ $width-left-toolbar: 48px;
&.selected {
background-color: $color-gray-60;
color: $color-primary;
svg {
fill: $color-primary;

View File

@ -231,15 +231,23 @@
.asset-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 6vh;
column-gap: 0.5rem;
row-gap: 0.5rem;
&.big {
grid-template-columns: 1fr 1fr;
grid-template-columns: repeat(2, 1fr);
grid-auto-rows: 10vh;
.three-row & {
grid-template-columns: repeat(3, 1fr);
}
.four-row & {
grid-template-columns: repeat(4, 1fr);
}
.grid-cell {
padding: $size-1;

View File

@ -40,6 +40,9 @@
font-size: $fs12;
color: $color-gray-20;
fill: $color-gray-20;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
}
.history-entry {

View File

@ -207,6 +207,11 @@ span.element-name {
margin-left: auto;
position: relative;
width: 32px;
right: 20px;
&.is-parent {
right: 0;
}
svg {
height: 13px;
@ -242,7 +247,7 @@ span.element-name {
}
.toggle-content {
margin-left: auto;
margin-left: 8px;
width: 12px;
svg {

View File

@ -5,8 +5,8 @@
// Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
// Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
.sitemap {
flex: none !important;
#sitemap {
height: var(--height, 200px);
.element-list {
li {
@ -118,6 +118,15 @@
}
}
}
& .resize-area {
position: absolute;
width: 100%;
height: 16px;
bottom: -8px;
left: 0;
cursor: ns-resize;
}
}
.add-page,

View File

@ -5,67 +5,25 @@
// Copyright (c) 2015-2020 Andrey Antukh <niwi@niwi.nz>
// Copyright (c) 2015-2020 Juan de la Cruz <delacruzgarciajuan@gmail.com>
$width-settings-bar: 16rem;
// This width is also used in update-viewport-size at frontend/src/app/main/data/workspace.cljs
.settings-bar {
background-color: $color-gray-50;
border-left: 1px solid $color-gray-60;
bottom: 0;
height: 100%;
position: fixed;
right: 0;
width: $width-settings-bar;
&.expanded {
width: $width-settings-bar * 3;
}
z-index: 10;
overflow-y: auto;
position: relative;
&.settings-bar-left {
border-left: none;
border-right: 1px solid $color-gray-60;
left: 48px;
& .tab-container-tabs {
padding-left: 1.5rem;
}
}
.settings-bar-inside {
align-items: flex-start;
display: grid;
grid-template-columns: 100%;
&[data-layout*="sitemap-pages"] {
grid-template-rows: auto;
}
&[data-layout*="layers"] {
grid-template-rows: auto 1fr;
}
&[data-layout*="libraries"] {
grid-template-rows: auto 1fr;
}
&[data-layout*="layers"][data-layout*="sitemap-pages"] {
grid-template-rows: 11.5rem 1fr;
}
&[data-layout*="libraries"][data-layout*="sitemap-pages"] {
grid-template-rows: 11.5rem 1fr;
}
&[data-layout*="layers"][data-layout*="libraries"] {
grid-template-rows: auto 30% 1fr;
}
&[data-layout*="layers"][data-layout*="libraries"][data-layout*="sitemap-pages"] {
grid-template-rows: 11.5rem 25% 1fr;
}
flex-direction: column;
padding-top: 48px;
height: 100%;
grid-template-rows: 100%;
height: calc(100% - 2px);
.tool-window {
position: relative;
@ -75,7 +33,6 @@ $width-settings-bar: 16rem;
flex: 1;
width: 100%;
height: 100%;
overflow: hidden;
.tool-window-bar {
align-items: center;
@ -163,14 +120,30 @@ $width-settings-bar: 16rem;
height: auto;
}
}
& > .resize-area {
position: absolute;
width: 8px;
height: 100%;
z-index: 10;
cursor: ew-resize;
}
&.settings-bar-left > .resize-area {
right: -8px;
}
&.settings-bar-right > .resize-area {
left: -4px;
}
}
.tool-window-content {
display: flex;
flex-direction: column;
overflow-y: auto;
height: 100%;
width: 100%;
overflow-y: auto;
}
.element-list {
@ -222,3 +195,47 @@ $width-settings-bar: 16rem;
width: 100%;
}
}
button.collapse-sidebar {
background: none;
border: none;
cursor: pointer;
height: 2.5rem;
padding-top: 0.75rem;
position: absolute;
width: 1rem;
& svg {
width: 12px;
height: 12px;
fill: $color-gray-20;
transform: rotate(180deg);
}
&.collapsed {
background: $color-gray-60;
left: 48px;
top: 48px;
width: 28px;
height: 48px;
padding: 0;
border-radius: 0px 4px 4px 0px;
border-left: 1px solid $color-gray-50;
& svg {
transform: rotate(0deg);
}
}
}
#layers.tool-window {
overflow: auto;
}
.layers-tab {
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 100%;
height: 100%;
overflow: hidden;
}

View File

@ -1,8 +1,8 @@
.tab-container {
display: flex;
flex-direction: column;
display: grid;
grid-template-rows: auto 1fr;
grid-template-columns: 100%;
height: 100%;
width: 100%;
}
.tab-container-tabs {
@ -31,11 +31,8 @@
}
.tab-container-content {
flex: 1;
height: 100%;
max-height: 100%;
overflow-x: hidden;
overflow-y: auto;
overflow-x: hidden;
}
.tab-element,

View File

@ -0,0 +1,26 @@
.typography-item {
padding: 0 1rem;
margin-right: 1rem;
cursor: pointer;
& > * {
white-space: nowrap;
}
& .typography-name {
color: $color-white;
}
& .typography-font,
& .typography-data {
font-size: 16px;
color: $color-gray-30;
}
.no-text & {
& .typography-font,
& .typography-data {
display: none;
}
}
}

View File

@ -5,16 +5,36 @@
// Copyright (c) UXBOX Labs SL
.workspace-header {
position: relative;
align-items: center;
background-color: $color-gray-50;
border-bottom: 1px solid $color-gray-60;
display: flex;
height: 48px;
padding: $size-1 $size-4 $size-1 55px;
position: relative;
z-index: 12;
justify-content: space-between;
display: grid;
grid-template-areas: "left center right";
grid-template-columns: auto 1fr auto;
grid-template-rows: 100%;
padding: 0;
.left-area {
grid-area: left;
display: flex;
height: 100%;
}
.center-area {
grid-area: center;
}
.right-area {
grid-area: right;
display: flex;
height: 100%;
}
.main-icon {
align-items: center;
background-color: $color-gray-60;
@ -23,9 +43,6 @@
display: flex;
height: 100%;
justify-content: center;
left: 0;
position: absolute;
top: 0;
width: 48px;
a {
@ -46,6 +63,7 @@
}
.menu-section {
margin-left: 1rem;
display: flex;
justify-content: flex-start;
align-items: center;
@ -75,6 +93,8 @@
justify-content: flex-end;
align-items: center;
position: relative;
padding-right: 1rem;
border-right: 1px solid black;
> * {
margin-left: $size-5;
@ -218,7 +238,8 @@
}
.active-users {
align-items: center;
flex: 1;
justify-content: center;
display: flex;
margin: 0;
@ -235,6 +256,26 @@
}
}
}
& button.document-history {
background: $color-gray-60;
border-radius: 3px;
border: none;
cursor: pointer;
height: 24px;
padding: 3px;
width: 24px;
& svg {
width: 18px;
fill: $color-gray-20;
height: 18px;
}
&.selected svg {
fill: $color-primary;
}
}
}
.persistence-status-widget {

View File

@ -5,8 +5,68 @@
// Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
// Copyright (c) 2015-2016 Juan de la Cruz <delacruzgarciajuan@gmail.com>
$width-left-toolbar: 48px;
$width-settings-bar: 256px;
$width-settings-bar-min: 255px;
$width-settings-bar-max: 500px;
$height-palette: 79px;
$height-palette-min: 54px;
$height-palette-max: 80px;
#workspace {
width: 100vw;
height: 100vh;
user-select: none;
display: grid;
grid-template-areas:
"header header header header"
"toolbar left-sidebar viewport right-sidebar"
"toolbar left-sidebar color-palette right-sidebar";
grid-template-rows: auto 1fr auto;
grid-template-columns: auto auto 1fr auto;
.workspace-header {
grid-area: header;
height: 48px;
}
.left-toolbar {
grid-area: toolbar;
width: $width-left-toolbar;
}
.settings-bar.settings-bar-left {
min-width: $width-settings-bar;
max-width: 500px;
width: var(--width, $width-settings-bar);
grid-area: left-sidebar;
}
.settings-bar.settings-bar-right {
min-width: $width-settings-bar;
max-width: 500px;
width: $width-settings-bar;
grid-area: right-sidebar;
}
.workspace-loader {
grid-area: viewport;
}
.workspace-content {
grid-area: viewport;
}
.color-palette {
grid-area: color-palette;
min-height: $height-palette-min;
max-height: $height-palette-max;
height: var(--height, $height-palette);
}
}
.workspace-context-menu {
@ -97,7 +157,6 @@
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
svg#loader-pencil {
fill: $color-gray-50;
@ -107,12 +166,8 @@
.workspace-content {
background-color: $color-canvas;
display: flex;
height: 100%;
width: calc(100% - #{$width-left-toolbar} - 2 * #{$width-settings-bar});
padding: 0;
margin: 0;
position: fixed;
right: $width-settings-bar;
&.scrolling {
cursor: grab;
@ -171,14 +226,12 @@
}
.workspace-viewport {
height: calc(100% - 40px);
overflow: hidden;
transition: none;
width: 100%;
display: grid;
grid-template-rows: 20px 100%;
grid-template-columns: 20px 100%;
grid-template-rows: 20px 1fr;
grid-template-columns: 20px 1fr;
flex: 1;
}
.viewport {
@ -209,10 +262,14 @@
.render-shapes {
position: absolute;
width: 100%;
height: 100%;
}
.viewport-controls {
position: absolute;
width: 100%;
height: 100%;
}
}

View File

@ -432,6 +432,15 @@
stored
(d/concat-set flags)))))))
(defn remove-layout-flags
[& flags]
(ptk/reify ::remove-layout-flags
ptk/UpdateEvent
(update [_ state]
(update state :workspace-layout
(fn [stored]
(reduce disj stored (d/concat-set flags)))))))
;; --- Set element options mode
(defn set-options-mode
@ -481,7 +490,7 @@
(cond
(or (not (mth/finite? (:width srect)))
(not (mth/finite? (:height srect))))
(assoc local :vbox (assoc size :x 0 :y 0 :left-offset 0))
(assoc local :vbox (assoc size :x 0 :y 0))
(or (> (:width srect) width)
(> (:height srect) height))
@ -522,25 +531,46 @@
(update :y y)))))))
(defn update-viewport-size
[{:keys [width height] :as size}]
[resize-type {:keys [width height] :as size}]
(ptk/reify ::update-viewport-size
ptk/UpdateEvent
(update [_ state]
(update state :workspace-local
(fn [{:keys [vport left-sidebar? zoom] :as local}]
(if (or (mth/almost-zero? width) (mth/almost-zero? height))
(fn [{:keys [vport] :as local}]
(if (or (nil? vport)
(mth/almost-zero? width)
(mth/almost-zero? height))
;; If we have a resize to zero just keep the old value
local
(let [wprop (/ (:width vport) width)
hprop (/ (:height vport) height)
left-offset (if left-sidebar? 0 (/ (* -1 15 16) zoom))]
(-> local ;; This matches $width-settings-bar
(assoc :vport size) ;; in frontend/resources/styles/main/partials/sidebar.scss
(update :vbox (fn [vbox]
(-> vbox
(update :width #(/ % wprop))
(update :height #(/ % hprop))
(assoc :left-offset left-offset))))))))))))
vbox (:vbox local)
vbox-x (:x vbox)
vbox-y (:y vbox)
vbox-width (:width vbox)
vbox-height (:height vbox)
vbox-width' (/ vbox-width wprop)
vbox-height' (/ vbox-height hprop)
vbox-x'
(case resize-type
:left (+ vbox-x (- vbox-width vbox-width'))
:right vbox-x
(+ vbox-x (/ (- vbox-width vbox-width') 2)))
vbox-y'
(case resize-type
:top (+ vbox-y (- vbox-height vbox-height'))
:bottom vbox-y
(+ vbox-y (/ (- vbox-height vbox-height') 2)))]
(-> local
(assoc :vport size)
(assoc-in [:vbox :x] vbox-x')
(assoc-in [:vbox :y] vbox-y')
(assoc-in [:vbox :width] vbox-width')
(assoc-in [:vbox :height] vbox-height')))))))))
(defn start-panning []
(ptk/reify ::start-panning
@ -596,14 +626,12 @@
(defn- impl-update-zoom
[{:keys [vbox] :as local} center zoom]
(let [vbox (update vbox :x + (:left-offset vbox))
new-zoom (if (fn? zoom) (zoom (:zoom local)) zoom)
(let [new-zoom (if (fn? zoom) (zoom (:zoom local)) zoom)
old-zoom (:zoom local)
center (if center center (gsh/center-rect vbox))
scale (/ old-zoom new-zoom)
mtx (gmt/scale-matrix (gpt/point scale) center)
vbox' (gsh/transform-rect vbox mtx)
vbox' (update vbox' :x - (:left-offset vbox))]
vbox' (gsh/transform-rect vbox mtx)]
(-> local
(assoc :zoom new-zoom)
(update :vbox merge (select-keys vbox' [:x :y :width :height])))))

View File

@ -17,6 +17,7 @@
[app.main.data.workspace.transforms :as dwt]
[app.main.data.workspace.undo :as dwu]
[app.main.store :as st]
[app.main.ui.hooks.resize :as r]
[app.util.dom :as dom]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -38,9 +39,17 @@
:command (ds/a-mod "h")
:fn #(st/emit! (dw/go-to-layout :document-history))}
:toggle-palette {:tooltip (ds/alt "P")
:command (ds/a-mod "p")
:fn #(st/emit! (dw/toggle-layout-flags :colorpalette))}
:toggle-colorpalette {:tooltip (ds/alt "P")
:command (ds/a-mod "p")
:fn #(do (r/set-resize-type! :bottom)
(st/emit! (dw/remove-layout-flags :textpalette)
(dw/toggle-layout-flags :colorpalette)))}
:toggle-textpalette {:tooltip (ds/alt "T")
:command (ds/a-mod "t")
:fn #(do (r/set-resize-type! :bottom)
(st/emit! (dw/remove-layout-flags :colorpalette)
(dw/toggle-layout-flags :textpalette)))}
:toggle-rules {:tooltip (ds/meta-shift "R")
:command (ds/c-mod "shift+r")
@ -338,9 +347,15 @@
:command (ds/c-mod "alt+l")
:fn #(st/emit! (dw/toggle-proportion-lock))}
:create-artboard-from-selection {:tooltip (ds/meta (ds/alt "G"))
:command (ds/c-mod "alt+g")
:fn #(st/emit! (dw/create-artboard-from-selection))}})
:create-artboard-from-selection {:tooltip (ds/meta (ds/alt "G"))
:command (ds/c-mod "alt+g")
:fn #(st/emit! (dw/create-artboard-from-selection))}
:hide-ui {:tooltip "\\"
:command "\\"
:fn #(st/emit! (dw/toggle-layout-flags :hide-ui))}
})
(def opacity-shortcuts
(into {} (->>

View File

@ -92,7 +92,7 @@
(l/derived :workspace-drawing st/state))
(def selected-shapes
(l/derived wsh/lookup-selected st/state))
(l/derived wsh/lookup-selected st/state =))
(defn make-selected-ref
[id]
@ -124,6 +124,11 @@
:move-overlay-index])
workspace-local =))
(def typography-data
(l/derived #(select-keys % [:rename-typography
:edit-typography])
workspace-local =))
(def local-displacement
(l/derived #(select-keys % [:modifiers :selected])
workspace-local =))
@ -158,15 +163,15 @@
(def current-hover-ids
(l/derived :hover-ids context-menu))
(def editors
(l/derived :editors workspace-local))
(def selected-assets
(l/derived :selected-assets workspace-local))
(def workspace-layout
(l/derived :workspace-layout st/state))
(def current-file-id
(l/derived :current-file-id st/state))
(def workspace-file
(l/derived (fn [state]
(let [file (:workspace-file state)

View File

@ -300,7 +300,7 @@
(mf/deps thread comments-map)
(fn []
(when-let [node (mf/ref-val ref)]
(.scrollIntoViewIfNeeded ^js node))))
(dom/scroll-into-view-if-needed! node))))
(when (some? comment)
[:div.thread-content

View File

@ -7,6 +7,7 @@
(ns app.main.ui.components.color-bullet
(:require
[app.util.color :as uc]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[rumext.alpha :as mf]))
@ -21,17 +22,18 @@
[:div.color-bullet.multiple {:on-click #(when on-click (on-click %))}]
;; No multiple selection
(let [color (if (string? color) {:color color :opacity 1} color)
background (if (:gradient color) (uc/color->background color) "auto")]
[:div.color-bullet.tooltip.tooltip-right {:class (if (:id color) "is-library-color" "is-not-library-color")
:on-click #(when on-click (on-click %))
:alt (or (:name color) (:color color) (gradient-type->string (:type (:gradient color))))
:style {:background background}}
(when (not(:gradient color))
[:*
(let [color (if (string? color) {:color color :opacity 1} color)]
[:div.color-bullet.tooltip.tooltip-right
{:class (dom/classnames :is-library-color (some? (:id color))
:is-not-library-color (nil? (:id color))
:is-gradient (some? (:gradient color)))
:on-click #(when on-click (on-click %))
:alt (or (:name color) (:color color) (gradient-type->string (:type (:gradient color))))}
(if (:gradient color)
[:div.color-bullet-wrapper {:style {:background (uc/color->background color)}}]
[:div.color-bullet-wrapper
[:div.color-bullet-left {:style {:background (uc/color->background (assoc color :opacity 1))}}]
[:div.color-bullet-right {:style {:background (uc/color->background color)}}]]
)])))
[:div.color-bullet-right {:style {:background (uc/color->background color)}}]])])))
(mf/defc color-name [{:keys [color size on-click on-double-click]}]
(let [color (if (string? color) {:color color :opacity 1} color)

View File

@ -0,0 +1,109 @@
;; 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) UXBOX Labs SL
(ns app.main.ui.hooks.resize
(:require
[app.common.geom.point :as gpt]
[app.common.logging :as log]
[app.main.refs :as refs]
[app.util.dom :as dom]
[app.util.storage :refer [storage]]
[rumext.alpha :as mf]))
(log/set-level! :warn)
(def last-resize-type nil)
(defn set-resize-type! [type]
(set! last-resize-type type))
(defn use-resize-hook
[key initial min-val max-val axis negate? resize-type]
(let [current-file-id (mf/deref refs/current-file-id)
size-state (mf/use-state (or (get-in @storage [::saved-resize current-file-id key]) initial))
parent-ref (mf/use-ref nil)
dragging-ref (mf/use-ref false)
start-size-ref (mf/use-ref nil)
start-ref (mf/use-ref nil)
on-pointer-down
(mf/use-callback
(mf/deps @size-state)
(fn [event]
(dom/capture-pointer event)
(mf/set-ref-val! start-size-ref @size-state)
(mf/set-ref-val! dragging-ref true)
(mf/set-ref-val! start-ref (dom/get-client-position event))
(set! last-resize-type resize-type)))
on-lost-pointer-capture
(mf/use-callback
(fn [event]
(dom/release-pointer event)
(mf/set-ref-val! start-size-ref nil)
(mf/set-ref-val! dragging-ref false)
(mf/set-ref-val! start-ref nil)
(set! last-resize-type nil)))
on-mouse-move
(mf/use-callback
(mf/deps min-val max-val)
(fn [event]
(when (mf/ref-val dragging-ref)
(let [start (mf/ref-val start-ref)
pos (dom/get-client-position event)
delta (-> (gpt/to-vec start pos)
(cond-> negate? gpt/negate)
(get axis))
start-size (mf/ref-val start-size-ref)
new-size (-> (+ start-size delta) (max min-val) (min max-val))]
(reset! size-state new-size)
(swap! storage assoc-in [::saved-resize current-file-id key] new-size)))))]
{:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-mouse-move on-mouse-move
:parent-ref parent-ref
:size @size-state}))
(defn use-resize-observer
[callback]
(assert (some? callback))
(let [prev-val-ref (mf/use-ref nil)
current-observer-ref (mf/use-ref nil)
;; We use the ref as a callback when the dom node is ready (or change)
node-ref
(mf/use-callback
(mf/deps callback)
(fn [^js node]
(let [^js current-observer (mf/ref-val current-observer-ref)
^js prev-val (mf/ref-val prev-val-ref)]
(when (and (not= prev-val node) (some? current-observer))
(log/debug :action "disconnect" :js/prev-val prev-val :js/node node)
(.disconnect current-observer)
(mf/set-ref-val! current-observer-ref nil))
(when (and (not= prev-val node) (some? node))
(let [^js observer
(js/ResizeObserver. #(callback last-resize-type (dom/get-client-size node)))]
(mf/set-ref-val! current-observer-ref observer)
(log/debug :action "observe" :js/node node :js/observer observer)
(.observe observer node))))
(mf/set-ref-val! prev-val-ref node)))]
(mf/use-effect
(fn []
;; On dismount we need to disconnect the current observer
(fn []
(let [current-observer (mf/ref-val current-observer-ref)]
(when (some? current-observer)
(log/debug :action "disconnect")
(.disconnect current-observer))))))
node-ref))

View File

@ -45,8 +45,7 @@
[:*
[:span.tool-window-bar-icon
[:& si/element-icon {:shape first-shape}]]
[:span.tool-window-bar-title (->> selected-type d/name (str "handoff.tabs.code.selected.") (tr))]])
]
[:span.tool-window-bar-title (->> selected-type d/name (str "handoff.tabs.code.selected.") (tr))]])]
[:div.tool-window-content
[:& tab-container {:on-change-tab #(do
(reset! expanded false)

View File

@ -12,6 +12,7 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.context :as ctx]
[app.main.ui.hooks.resize :refer [use-resize-observer]]
[app.main.ui.icons :as i]
[app.main.ui.workspace.colorpalette :refer [colorpalette]]
[app.main.ui.workspace.colorpicker]
@ -21,10 +22,12 @@
[app.main.ui.workspace.left-toolbar :refer [left-toolbar]]
[app.main.ui.workspace.libraries]
[app.main.ui.workspace.sidebar :refer [left-sidebar right-sidebar]]
[app.main.ui.workspace.textpalette :refer [textpalette]]
[app.main.ui.workspace.viewport :refer [viewport]]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
[app.util.object :as obj]
[debug :refer [debug?]]
[okulary.core :as l]
[rumext.alpha :as mf]))
@ -39,25 +42,46 @@
{:keys [options-mode]} local
file (obj/get props "file")
layout (obj/get props "layout")
colorpalette? (:colorpalette layout)]
[:*
(when colorpalette? [:& colorpalette])
[:section.workspace-content
colorpalette? (:colorpalette layout)
textpalette? (:textpalette layout)
hide-ui? (:hide-ui layout)
on-resize
(mf/use-callback
(mf/deps (:vport local))
(fn [resize-type size]
(when (:vport local)
(st/emit! (dw/update-viewport-size resize-type size)))))
node-ref (use-resize-observer on-resize)]
[:*
(when (and colorpalette? (not hide-ui?))
[:& colorpalette])
(when (and textpalette? (not hide-ui?))
[:& textpalette])
[:section.workspace-content {:ref node-ref}
[:section.workspace-viewport
[:& coordinates/coordinates {:colorpalette? colorpalette?}]
(when (debug? :coordinates)
[:& coordinates/coordinates {:colorpalette? colorpalette?}])
[:& viewport {:file file
:local local
:selected selected
:layout layout}]]]
[:& left-toolbar {:layout layout}]
;; Aside
[:& left-sidebar {:layout layout}]
[:& right-sidebar {:section options-mode
:selected selected}]]))
(when-not hide-ui?
[:*
[:& left-toolbar {:layout layout}]
(if (:collapse-left-sidebar layout)
[:button.collapse-sidebar.collapsed {:on-click #(st/emit! (dw/toggle-layout-flags :collapse-left-sidebar))}
i/arrow-slide]
[:& left-sidebar {:layout layout}])
[:& right-sidebar {:section options-mode
:selected selected
:layout layout}]])]))
(def trimmed-page-ref (l/derived :trimmed-page st/state =))
@ -116,10 +140,11 @@
[:& (mf/provider ctx/current-project-id) {:value (:id project)}
[:& (mf/provider ctx/current-page-id) {:value page-id}
[:section#workspace
[:& header {:file file
:page-id page-id
:project project
:layout layout}]
(when (not (:hide-ui layout))
[:& header {:file file
:page-id page-id
:project project
:layout layout}])
[:& context-menu]
@ -131,3 +156,5 @@
:layout layout}]
[:& workspace-loader])]]]]]))

View File

@ -12,8 +12,10 @@
[app.main.store :as st]
[app.main.ui.components.color-bullet :as cb]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.icons :as i]
[app.util.color :as uc]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.keyboard :as kbd]
[app.util.object :as obj]
@ -38,7 +40,7 @@
;; --- Components
(mf/defc palette-item
[{:keys [color size]}]
[{:keys [color]}]
(let [ids-with-children (map :id (mf/deref refs/selected-shapes-with-children))
select-color
(fn [event]
@ -46,14 +48,13 @@
(st/emit! (mdc/change-stroke ids-with-children (merge uc/empty-color color)))
(st/emit! (mdc/change-fill ids-with-children (merge uc/empty-color color)))))]
[:div.color-cell {:class (str "cell-"(name size))
:on-click select-color}
[:div.color-cell {:on-click select-color}
[:& cb/color-bullet {:color color}]
[:& cb/color-name {:color color :size size}]]))
[:& cb/color-name {:color color}]]))
(mf/defc palette
[{:keys [current-colors recent-colors file-colors shared-libs selected size]}]
(let [state (mf/use-state {:show-menu false })
[{:keys [current-colors recent-colors file-colors shared-libs selected]}]
(let [state (mf/use-state {:show-menu false})
width (:width @state 0)
visible (mth/round (/ width 66))
@ -64,6 +65,9 @@
container (mf/use-ref nil)
{:keys [on-pointer-down on-lost-pointer-capture on-mouse-move parent-ref size]}
(use-resize-hook :palette 72 54 80 :y true :bottom)
on-left-arrow-click
(mf/use-callback
(mf/deps max-offset visible)
@ -111,7 +115,13 @@
(fn []
(events/unlistenByKey key1))))
[:div.color-palette.left-sidebar-open
[:div.color-palette {:ref parent-ref
:class (dom/classnames :no-text (< size 72))
:style #js {"--height" (str size "px")
"--bullet-size" (str (if (< size 72) (- size 15) (- size 30)) "px")}}
[:div.resize-area {:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-mouse-move on-mouse-move}]
[:& dropdown {:show (:show-menu @state)
:on-close #(swap! state assoc :show-menu false)}
[:ul.workspace-context-menu.palette-menu
@ -146,33 +156,18 @@
[:div.color-sample
(for [[idx color] (map-indexed vector (take 7 (reverse recent-colors))) ]
[:& cb/color-bullet {:key (str "color-" idx)
:color color}])]]
[:hr.dropdown-separator]
[:li
{:on-click #(st/emit! (mdc/change-palette-size :big))}
(when (= size :big) i/tick)
(tr "workspace.libraries.colors.big-thumbnails")]
[:li
{:on-click #(st/emit! (mdc/change-palette-size :small))}
(when (= size :small) i/tick)
(tr "workspace.libraries.colors.small-thumbnails")]]]
:color color}])]]]]
[:div.color-palette-actions
{:on-click #(swap! state assoc :show-menu true)}
[:div.color-palette-actions-button i/actions]]
[:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide]
[:div.color-palette-content {:class (if (= size :big) "size-big" "size-small")
:ref container :on-wheel on-scroll}
[:div.color-palette-content {:ref container :on-wheel on-scroll}
[:div.color-palette-inside {:style {:position "relative"
:right (str (* 66 offset) "px")}}
(for [[idx item] (map-indexed vector current-colors)]
[:& palette-item {:size size
:color item
:key idx}])]]
[:& palette-item {:color item :key idx}])]]
[:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]]))
@ -183,13 +178,12 @@
(vals))))
(mf/defc colorpalette
{::mf/wrap [mf/memo]}
[]
(let [recent-colors (mf/deref refs/workspace-recent-colors)
file-colors (mf/deref refs/workspace-file-colors)
shared-libs (mf/deref refs/workspace-libraries)
selected (or (mf/deref selected-palette-ref) :recent)
size (or (mf/deref selected-palette-size-ref) :big)
current-library-colors (mf/use-state [])]
(mf/use-effect
@ -219,5 +213,4 @@
:recent-colors recent-colors
:file-colors file-colors
:shared-libs shared-libs
:selected selected
:size size}]))
:selected selected}]))

View File

@ -436,10 +436,15 @@
(mf/defc viewport-context-menu
[]
(let [do-paste (st/emitf dw/paste)]
[:& menu-entry {:title (tr "workspace.shape.menu.paste")
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}]))
(let [do-paste (st/emitf dw/paste)
do-hide-ui (st/emitf (dw/toggle-layout-flags :hide-ui))]
[:*
[:& menu-entry {:title (tr "workspace.shape.menu.paste")
:shortcut (sc/get-tooltip :paste)
:on-click do-paste}]
[:& menu-entry {:title (tr "workspace.shape.menu.hide-ui")
:shortcut (sc/get-tooltip :hide-ui)
:on-click do-hide-ui}]]))
(mf/defc context-menu
[]

View File

@ -18,6 +18,7 @@
[app.main.repo :as rp]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.hooks.resize :as r]
[app.main.ui.icons :as i]
[app.main.ui.workspace.presence :refer [active-sessions]]
[app.util.dom :as dom]
@ -297,12 +298,25 @@
(tr "workspace.header.menu.show-layers"))]
[:span.shortcut (sc/get-tooltip :toggle-layers)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :colorpalette))}
[:li {:on-click (fn []
(r/set-resize-type! :bottom)
(st/emit! (dw/remove-layout-flags :textpalette)
(dw/toggle-layout-flags :colorpalette)))}
[:span
(if (contains? layout :colorpalette)
(tr "workspace.header.menu.hide-palette")
(tr "workspace.header.menu.show-palette"))]
[:span.shortcut (sc/get-tooltip :toggle-palette)]]
(tr "workspace.header.menu.hide-colorpalette")
(tr "workspace.header.menu.show-colorpalette"))]
[:span.shortcut (sc/get-tooltip :toggle-colorpalette)]]
[:li {:on-click (fn []
(r/set-resize-type! :bottom)
(st/emit! (dw/remove-layout-flags :colorpalette)
(dw/toggle-layout-flags :textpalette)))}
[:span
(if (contains? layout :textpalette)
(tr "workspace.header.menu.hide-textpalette")
(tr "workspace.header.menu.show-textpalette"))]
[:span.shortcut (sc/get-tooltip :toggle-textpalette)]]
[:li {:on-click #(st/emit! (dw/toggle-layout-flags :assets))}
[:span
@ -360,31 +374,40 @@
(st/emitf (dw/go-to-viewer params)))]
[:header.workspace-header
[:div.main-icon
[:a {:on-click go-back} i/logo-icon]]
[:div.left-area
[:div.main-icon
[:a {:on-click go-back} i/logo-icon]]
[:& menu {:layout layout
:project project
:file file
:team-id team-id
:page-id page-id}]
[:& menu {:layout layout
:project project
:file file
:team-id team-id
:page-id page-id}]]
[:div.users-section
[:& active-sessions]]
[:div.center-area
[:div.users-section
[:& active-sessions]]]
[:div.options-section
[:& persistence-state-widget]
[:div.right-area
[:div.options-section
[:& persistence-state-widget]
[:button.document-history
{:alt (tr "workspace.sidebar.history" (sc/get-tooltip :toggle-history))
:class (when (contains? layout :document-history) "selected")
:on-click (st/emitf (dw/toggle-layout-flags :document-history))}
i/recent]]
[:& zoom-widget-workspace
{:zoom zoom
:on-increase #(st/emit! (dw/increase-zoom nil))
:on-decrease #(st/emit! (dw/decrease-zoom nil))
:on-zoom-reset #(st/emit! dw/reset-zoom)
:on-zoom-fit #(st/emit! dw/zoom-to-fit-all)
:on-zoom-selected #(st/emit! dw/zoom-to-selected-shape)}]
[:div.options-section
[:& zoom-widget-workspace
{:zoom zoom
:on-increase #(st/emit! (dw/increase-zoom nil))
:on-decrease #(st/emit! (dw/decrease-zoom nil))
:on-zoom-reset #(st/emit! dw/reset-zoom)
:on-zoom-fit #(st/emit! dw/zoom-to-fit-all)
:on-zoom-selected #(st/emit! dw/zoom-to-selected-shape)}]
[:a.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
{:alt (tr "workspace.header.viewer" (sc/get-tooltip :open-viewer))
:on-click go-viewer}
i/play]]]))
[:a.btn-icon-dark.btn-small.tooltip.tooltip-bottom-left
{:alt (tr "workspace.header.viewer" (sc/get-tooltip :open-viewer))
:on-click go-viewer}
i/play]]]]))

View File

@ -14,6 +14,7 @@
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.file-uploader :refer [file-uploader]]
[app.main.ui.hooks.resize :as r]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@ -119,22 +120,19 @@
[:ul.left-toolbar-options.panels
[:li.tooltip.tooltip-right
{:alt (tr "workspace.sidebar.layers" (sc/get-tooltip :toggle-layers))
:class (when (contains? layout :layers) "selected")
:on-click (st/emitf (dw/go-to-layout :layers))}
i/layers]
{:alt (tr "workspace.toolbar.text-palette" (sc/get-tooltip :toggle-textpalette))
:class (when (contains? layout :textpalette) "selected")
:on-click (fn []
(r/set-resize-type! :bottom)
(st/emit! (dw/remove-layout-flags :colorpalette)
(dw/toggle-layout-flags :textpalette)))}
"Ag"]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.assets" (sc/get-tooltip :toggle-assets))
:class (when (contains? layout :assets) "selected")
:on-click (st/emitf (dw/go-to-layout :assets))}
i/library]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.sidebar.history" (sc/get-tooltip :toggle-history))
:class (when (contains? layout :document-history) "selected")
:on-click (st/emitf (dw/go-to-layout :document-history))}
i/recent]
[:li.tooltip.tooltip-right
{:alt (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-palette))
{:alt (tr "workspace.toolbar.color-palette" (sc/get-tooltip :toggle-colorpalette))
:class (when (contains? layout :colorpalette) "selected")
:on-click (st/emitf (dw/toggle-layout-flags :colorpalette))}
:on-click (fn []
(r/set-resize-type! :bottom)
(st/emit! (dw/remove-layout-flags :textpalette)
(dw/toggle-layout-flags :colorpalette)))}
i/palette]]]]))

View File

@ -6,14 +6,21 @@
(ns app.main.ui.workspace.sidebar
(:require
[app.main.data.workspace :as dw]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.tab-container :refer [tab-container tab-element]]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.icons :as i]
[app.main.ui.workspace.comments :refer [comments-sidebar]]
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox]]
[app.main.ui.workspace.sidebar.history :refer [history-toolbox]]
[app.main.ui.workspace.sidebar.layers :refer [layers-toolbox]]
[app.main.ui.workspace.sidebar.options :refer [options-toolbox]]
[app.main.ui.workspace.sidebar.sitemap :refer [sitemap]]
[cuerdas.core :as str]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[app.util.object :as obj]
[rumext.alpha :as mf]))
;; --- Left Sidebar (Component)
@ -21,19 +28,40 @@
(mf/defc left-sidebar
{:wrap [mf/memo]}
[{:keys [layout ] :as props}]
[:aside.settings-bar.settings-bar-left
[:div.settings-bar-inside
{:data-layout (str/join "," layout)}
(when (contains? layout :layers)
[:*
[:& sitemap {:layout layout}]
[:& layers-toolbox]])
(let [section (cond (contains? layout :layers) :layers
(contains? layout :assets) :assets)
(when (contains? layout :document-history)
[:& history-toolbox])
{:keys [on-pointer-down on-lost-pointer-capture on-mouse-move parent-ref size]}
(use-resize-hook :left-sidebar 255 255 500 :x false :left)
(when (contains? layout :assets)
[:& assets-toolbox])]])
handle-collapse
(fn []
(st/emit! (dw/toggle-layout-flags :collapse-left-sidebar)))]
[:aside.settings-bar.settings-bar-left {:ref parent-ref
:class (dom/classnames
:two-row (<= size 300)
:three-row (and (> size 300) (<= size 400))
:four-row (> size 400))
:style #js {"--width" (str size "px")}}
[:div.resize-area {:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-mouse-move on-mouse-move}]
[:div.settings-bar-inside
[:button.collapse-sidebar
{:on-click handle-collapse}
i/arrow-slide]
[:& tab-container {:on-change-tab #(st/emit! (dw/go-to-layout %))
:selected section}
[:& tab-element {:id :layers :title (tr "workspace.sidebar.layers")}
[:div.layers-tab
[:& sitemap {:layout layout}]
[:& layers-toolbox]]]
[:& tab-element {:id :assets :title (tr "workspace.toolbar.assets")}
[:& assets-toolbox]]]]]))
;; --- Right Sidebar (Component)
@ -41,10 +69,18 @@
{::mf/wrap-props false
::mf/wrap [mf/memo]}
[props]
(let [drawing-tool (:tool (mf/deref refs/workspace-drawing))]
[:aside.settings-bar
(let [layout (obj/get props "layout")
drawing-tool (:tool (mf/deref refs/workspace-drawing))]
[:aside.settings-bar.settings-bar-right
[:div.settings-bar-inside
(if (= drawing-tool :comments)
(cond
(= drawing-tool :comments)
[:& comments-sidebar]
(contains? layout :document-history)
[:& history-toolbox]
:else
[:> options-toolbox props])]]))

View File

@ -1087,7 +1087,7 @@
;; ---- Typography box ----
(mf/defc typographies-group
[{:keys [file-id prefix groups open-groups file local? selected-typographies local
[{:keys [file-id prefix groups open-groups file local? selected-typographies local-data
editing-id on-asset-click handle-change apply-typography
on-rename-group on-ungroup on-context-menu]}]
(let [group-open? (get open-groups prefix true)]
@ -1115,7 +1115,7 @@
:on-click #(on-asset-click % (:id typography)
(partial apply-typography typography))
:editing? (= editing-id (:id typography))
:focus-name? (= (:rename-typography local) (:id typography))}])])
:focus-name? (= (:rename-typography local-data) (:id typography))}])])
(for [[path-item content] groups]
(when-not (empty? path-item)
@ -1127,7 +1127,7 @@
:local? local?
:selected-typographies selected-typographies
:editing-id editing-id
:local local
:local-data local-data
:on-asset-click on-asset-click
:handle-change handle-change
:apply-typography apply-typography
@ -1141,11 +1141,9 @@
(let [state (mf/use-state {:detail-open? false
:id nil})
local-data (mf/deref refs/typography-data)
menu-state (mf/use-state auto-pos-menu-state)
local (deref refs/workspace-local)
groups (group-assets typographies reverse-sort?)
groups (group-assets typographies reverse-sort?)
selected-typographies (:typographies selected-assets)
multi-typographies? (> (count selected-typographies) 1)
@ -1174,7 +1172,11 @@
{:typography-ref-file file-id
:typography-ref-id (:id typography)}
(dissoc typography :id :name))]
(run! #(st/emit! (dwt/update-text-attrs {:id % :editor (get-in local [:editors %]) :attrs attrs}))
(run! #(st/emit!
(dwt/update-text-attrs
{:id %
:editor (get @refs/workspace-editor-state %)
:attrs attrs}))
ids)))
create-group
@ -1273,14 +1275,15 @@
(dwl/sync-file file-id file-id)
(dwu/commit-undo-transaction)))))
editing-id (or (:rename-typography local) (:edit-typography local))]
editing-id (or (:rename-typography local-data)
(:edit-typography local-data))]
(mf/use-effect
(mf/deps local)
(mf/deps local-data)
(fn []
(when (:rename-typography local)
(when (:rename-typography local-data)
(st/emit! #(update % :workspace-local dissoc :rename-typography)))
(when (:edit-typography local)
(when (:edit-typography local-data)
(st/emit! #(update % :workspace-local dissoc :edit-typography)))))
[:& asset-section {:file-id file-id
@ -1303,7 +1306,7 @@
:local? local?
:selected-typographies selected-typographies
:editing-id editing-id
:local local
:local-data local-data
:on-asset-click (partial on-asset-click groups)
:handle-change handle-change
:apply-typography apply-typography

View File

@ -180,12 +180,17 @@
:name (:name item)})]
(mf/use-effect
(mf/deps selected)
(mf/deps selected? selected)
(fn []
(let [subid
(when (and (= (count selected) 1) selected?)
(ts/schedule-on-idle
#(.scrollIntoView (mf/ref-val dref) #js {:block "nearest", :behavior "smooth"})))]
(let [single? (= (count selected) 1)
node (mf/ref-val dref)
subid
(when (and single? selected?)
(ts/schedule
100
#(dom/scroll-into-view! node #js {:block "nearest", :behavior "smooth"})))]
#(when (some? subid)
(rx/dispose! subid)))))
@ -208,7 +213,7 @@
:on-start-edit #(reset! disable-drag true)
:on-stop-edit #(reset! disable-drag false)}]
[:div.element-actions
[:div.element-actions {:class (when (:shapes item) "is-parent")}
[:div.toggle-element {:class (when (:hidden item) "selected")
:on-click toggle-visibility}
(if (:hidden item) i/eye-closed i/eye)]
@ -247,6 +252,7 @@
{::mf/wrap [#(mf/memo % =)]}
[{:keys [objects] :as props}]
(let [selected (mf/deref refs/selected-shapes)
selected (hooks/use-equal-memo selected)
root (get objects uuid/zero)]
[:ul.element-list
[:& hooks/sortable-container {}

View File

@ -6,6 +6,7 @@
(ns app.main.ui.workspace.sidebar.options.common
(:require
[app.util.dom :as dom]
[rumext.alpha :as mf]))
(mf/defc advanced-options [{:keys [visible? children]}]
@ -15,7 +16,7 @@
(fn []
(when-let [node (mf/ref-val ref)]
(when visible?
(.scrollIntoViewIfNeeded ^js node)))))
(dom/scroll-into-view-if-needed! node)))))
(when visible?
[:div.advanced-options-wrapper {:ref ref}

View File

@ -14,6 +14,7 @@
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks :as hooks]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :as i18n :refer [tr]]
@ -106,7 +107,7 @@
(fn []
(when selected?
(let [node (mf/ref-val dref)]
(.scrollIntoViewIfNeeded ^js node)))))
(dom/scroll-into-view-if-needed! node)))))
(mf/use-layout-effect
(mf/deps (:edition @local))
@ -205,10 +206,14 @@
:project-id (:project-id file)}))))
show-pages? (mf/use-state true)
{:keys [on-pointer-down on-lost-pointer-capture on-mouse-move parent-ref size]}
(use-resize-hook :sitemap 200 38 400 :y false nil)
toggle-pages
(mf/use-callback #(reset! show-pages? not))]
[:div.sitemap.tool-window
[:div#sitemap.tool-window {:ref parent-ref
:style #js {"--height" (str size "px")}}
[:div.tool-window-bar
[:span (tr "workspace.sidebar.sitemap")]
[:div.add-page {:on-click create} i/close]
@ -216,4 +221,8 @@
(when @show-pages?
[:div.tool-window-content
[:& pages-list {:file file :key (:id file)}]])]))
[:& pages-list {:file file :key (:id file)}]])
[:div.resize-area {:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-mouse-move on-mouse-move}]]))

View File

@ -0,0 +1,152 @@
;; 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) UXBOX Labs SL
(ns app.main.ui.workspace.textpalette
(:require
[app.common.data :as d]
[app.main.data.workspace.texts :as dwt]
[app.main.fonts :as f]
[app.main.refs :as refs]
[app.main.store :as st]
[app.main.ui.components.dropdown :refer [dropdown]]
[app.main.ui.context :as ctx]
[app.main.ui.hooks.resize :refer [use-resize-hook]]
[app.main.ui.icons :as i]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]]
[cuerdas.core :as str]
[rumext.alpha :as mf]))
(mf/defc typography-item
[{:keys [file-id selected-ids typography name-only?]}]
(let [font-data (f/get-font-data (:font-id typography))
font-variant-id (:font-variant-id typography)
variant-data (->> font-data :variants (d/seek #(= (:id %) font-variant-id)))
handle-click
(mf/use-callback
(mf/deps typography selected-ids)
(fn []
(let [attrs (merge
{:typography-ref-file file-id
:typography-ref-id (:id typography)}
(dissoc typography :id :name))]
(run! #(st/emit!
(dwt/update-text-attrs
{:id %
:editor (get @refs/workspace-editor-state %)
:attrs attrs}))
selected-ids))))]
[:div.typography-item {:on-click handle-click}
[:div.typography-name
{:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
(:name typography)]
(when-not name-only?
[:*
[:div.typography-font (:name font-data)]
[:div.typography-data (str (:font-size typography) "pt | " (:name variant-data))]])]))
(mf/defc palette
[{:keys [selected-ids current-file-id file-typographies shared-libs]}]
(let [state (mf/use-state {:show-menu false})
selected (mf/use-state :file)
file-id
(case @selected
:recent nil
:file current-file-id
@selected)
current-typographies
(case @selected
:recent []
:file (vals file-typographies)
(vals (get-in shared-libs [@selected :data :typographies])))
container (mf/use-ref nil)
on-left-arrow-click
(mf/use-callback
(fn []
(when-let [node (mf/ref-val container)]
(.scrollBy node #js {:left -200 :behavior "smooth"}))))
on-right-arrow-click
(mf/use-callback
(fn []
(when-let [node (mf/ref-val container)]
(.scrollBy node #js {:left 200 :behavior "smooth"}))))
on-wheel
(mf/use-callback
(fn [event]
(let [delta (+ (.. event -nativeEvent -deltaY) (.. event -nativeEvent -deltaX))]
(if (pos? delta)
(on-right-arrow-click)
(on-left-arrow-click)))))
{:keys [on-pointer-down on-lost-pointer-capture on-mouse-move parent-ref size]}
(use-resize-hook :palette 72 54 80 :y true :bottom)]
[:div.color-palette {:ref parent-ref
:class (dom/classnames :no-text (< size 72))
:style #js {"--height" (str size "px")}}
[:div.resize-area {:on-pointer-down on-pointer-down
:on-lost-pointer-capture on-lost-pointer-capture
:on-mouse-move on-mouse-move}]
[:& dropdown {:show (:show-menu @state)
:on-close #(swap! state assoc :show-menu false)}
[:ul.workspace-context-menu.palette-menu
(for [[idx cur-library] (map-indexed vector (vals shared-libs))]
(let [typographies (-> cur-library (get-in [:data :typographies]) vals)]
[:li.palette-library
{:key (str "library-" idx)
:on-click #(reset! selected (:id cur-library))}
(when (= @selected (:id cur-library)) i/tick)
[:div.library-name (str (:name cur-library) " " (str/format "(%s)" (count typographies)))]]))
[:li.palette-library
{:on-click #(reset! selected :file)}
(when (= selected :file) i/tick)
[:div.library-name (str (tr "workspace.libraries.colors.file-library")
(str/format " (%s)" (count file-typographies)))]]]]
[:div.color-palette-actions
{:on-click #(swap! state assoc :show-menu true)}
[:div.color-palette-actions-button i/actions]]
[:span.left-arrow {:on-click on-left-arrow-click} i/arrow-slide]
[:div.color-palette-content {:ref container :on-wheel on-wheel}
[:div.color-palette-inside
(for [[idx item] (map-indexed vector current-typographies)]
[:& typography-item
{:key idx
:file-id file-id
:selected-ids selected-ids
:typography item}])]]
[:span.right-arrow {:on-click on-right-arrow-click} i/arrow-slide]]))
(mf/defc textpalette
{::mf/wrap [mf/memo]}
[]
(let [selected-ids (mf/deref refs/selected-shapes)
file-typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/workspace-libraries)
current-file-id (mf/use-ctx ctx/current-file-id)]
[:& palette {:current-file-id current-file-id
:selected-ids selected-ids
:file-typographies file-typographies
:shared-libs shared-libs}]))

View File

@ -156,14 +156,13 @@
show-selrect? (and selrect (empty? drawing))
show-measures? (and (not transform) (not node-editing?) show-distances?)
show-artboard-names? (contains? layout :display-artboard-names)
show-rules? (contains? layout :rules)
show-rules? (and (contains? layout :rules) (not (contains? layout :hide-ui)))
disabled-guides? (or drawing-tool transform)]
(hooks/setup-dom-events viewport-ref zoom disable-paste in-viewport?)
(hooks/setup-viewport-size viewport-ref)
(hooks/setup-cursor cursor alt? panning drawing-tool drawing-path? node-editing?)
(hooks/setup-resize layout viewport-ref)
(hooks/setup-keyboard alt? ctrl? space?)
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected ctrl? hover hover-ids @hover-disabled? zoom)
(hooks/setup-viewport-modifiers modifiers base-objects)
@ -222,8 +221,6 @@
:xmlnsXlink "http://www.w3.org/1999/xlink"
:preserveAspectRatio "xMidYMid meet"
:key (str "viewport" page-id)
:width (:width vport 0)
:height (:height vport 0)
:view-box (utils/format-viewbox vbox)
:ref viewport-ref
:class (when drawing-tool "drawing")
@ -370,7 +367,8 @@
[:*
[:& rules/rules
{:zoom zoom
:vbox vbox}]
:vbox vbox
:selected-shapes selected-shapes}]
[:& guides/viewport-guides
{:zoom zoom

View File

@ -492,11 +492,3 @@
(when (and (not (#{"INPUT" "TEXTAREA"} tag-name)) (not @disable-paste))
(st/emit! (dw/paste-from-event event @in-viewport?)))))))
(defn on-resize [viewport-ref]
(mf/use-callback
(fn [_]
(let [node (mf/ref-val viewport-ref)
prnt (dom/get-parent node)
size (dom/get-client-size prnt)]
;; We schedule the event so it fires after `initialize-page` event
(timers/schedule #(st/emit! (dw/update-viewport-size size)))))))

View File

@ -29,6 +29,11 @@
(def guide-pill-corner-radius 4)
(def guide-active-area 16)
(def guide-creation-margin-left 8)
(def guide-creation-margin-top 28)
(def guide-creation-width 16)
(def guide-creation-height 24)
(defn use-guide
"Hooks to support drag/drop for existing guides and new guides"
[on-guide-change get-hover-frame zoom {:keys [position axis frame-id]}]
@ -220,15 +225,15 @@
(defn guide-creation-area
[vbox zoom axis]
(if (= axis :x)
{:x (:x vbox)
{:x (+ (:x vbox) (/ guide-creation-margin-left zoom))
:y (:y vbox)
:width (/ 24 zoom)
:width (/ guide-creation-width zoom)
:height (:height vbox)}
{:x (:x vbox)
{:x (+ (:x vbox) (+ guide-creation-margin-top zoom))
:y (:y vbox)
:width (:width vbox)
:height (/ 24 zoom)}))
:height (/ guide-creation-height zoom)}))
(defn is-guide-inside-frame?
[guide frame]

View File

@ -31,10 +31,9 @@
on-key-up (actions/on-key-up)
on-mouse-move (actions/on-mouse-move viewport-ref zoom)
on-mouse-wheel (actions/on-mouse-wheel viewport-ref zoom)
on-resize (actions/on-resize viewport-ref)
on-paste (actions/on-paste disable-paste in-viewport?)]
(mf/use-layout-effect
(mf/deps on-key-down on-key-up on-mouse-move on-mouse-wheel on-resize on-paste)
(mf/deps on-key-down on-key-up on-mouse-move on-mouse-wheel on-paste)
(fn []
(let [node (mf/ref-val viewport-ref)
keys [(events/listen js/document EventType.KEYDOWN on-key-down)
@ -43,7 +42,6 @@
;; bind with passive=false to allow the event to be cancelled
;; https://stackoverflow.com/a/57582286/3219895
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
(events/listen js/window EventType.RESIZE on-resize)
(events/listen js/window EventType.PASTE on-paste)]]
(fn []
@ -52,12 +50,12 @@
(defn setup-viewport-size [viewport-ref]
(mf/use-layout-effect
(fn []
(let [node (mf/ref-val viewport-ref)
prnt (dom/get-parent node)
size (dom/get-client-size prnt)]
;; We schedule the event so it fires after `initialize-page` event
(timers/schedule #(st/emit! (dw/initialize-viewport size)))))))
(fn []
(let [node (mf/ref-val viewport-ref)
prnt (dom/get-parent node)
size (dom/get-client-size prnt)]
;; We schedule the event so it fires after `initialize-page` event
(timers/schedule #(st/emit! (dw/initialize-viewport size)))))))
(defn setup-cursor [cursor alt? panning drawing-tool drawing-path? path-editing?]
(mf/use-effect
@ -80,10 +78,6 @@
(when (not= @cursor new-cursor)
(reset! cursor new-cursor))))))
(defn setup-resize [layout viewport-ref]
(let [on-resize (actions/on-resize viewport-ref)]
(mf/use-layout-effect (mf/deps layout) on-resize)))
(defn setup-keyboard [alt? ctrl? space?]
(hooks/use-stream ms/keyboard-alt #(reset! alt? %))
(hooks/use-stream ms/keyboard-ctrl #(reset! ctrl? %))

View File

@ -25,7 +25,7 @@
(:import goog.events.EventType))
(defn format-viewbox [vbox]
(str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))
(str/join " " [(:x vbox 0)
(:y vbox 0)
(:width vbox 0)
(:height vbox 0)]))

View File

@ -8,13 +8,25 @@
(:require
[app.common.colors :as colors]
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.math :as mth]
[app.main.ui.hooks :as hooks]
[app.util.object :as obj]
[rumext.alpha :as mf]))
(def rules-pos 15)
(def rules-size 4)
(def rules-width 1)
(def rule-area-size 22)
(def rule-area-half-size (/ rule-area-size 2))
(def rules-background "var(--color-gray-50)")
(def selection-area-color "var(--color-primary)")
(def selection-area-opacity 0.3)
(def over-number-size 50)
(def over-number-opacity 0.7)
(def font-size 13)
(def font-family "sourcesanspro")
;; ----------------
;; RULES
@ -53,6 +65,21 @@
height (- (:height vbox) (/ 21 zoom))]
{:x x :y y :width width :height height})))
(defn get-background-area
[vbox zoom axis]
(if (= axis :x)
(let [x (:x vbox)
y (:y vbox)
width (:width vbox)
height (/ rule-area-size zoom)]
{:x x :y y :width width :height height})
(let [x (:x vbox)
y (+ (:y vbox) (/ rule-area-size zoom))
width (/ rule-area-size zoom)
height (- (:height vbox) (/ 21 zoom))]
{:x x :y y :width width :height height})))
(defn get-rule-params
[vbox axis]
(if (= axis :x)
@ -89,49 +116,156 @@
step (calculate-step-size zoom)
clip-id (str "clip-rule-" (d/name axis))]
[:g.rules {:clipPath (str "url(#" clip-id ")")}
[:*
(let [{:keys [x y width height]} (get-background-area vbox zoom axis)]
[:rect {:x x :y y :width width :height height :style {:fill rules-background}}])
[:defs
[:clipPath {:id clip-id}
(let [{:keys [x y width height]} (get-clip-area vbox zoom axis)]
[:rect {:x x :y y :width width :height height}])]]
[:g.rules {:clipPath (str "url(#" clip-id ")")}
(let [{:keys [start end]} (get-rule-params vbox axis)
minv (max (mth/round start) -100000)
minv (* (mth/ceil (/ minv step)) step)
maxv (min (mth/round end) 100000)
maxv (* (mth/floor (/ maxv step)) step)]
[:defs
[:clipPath {:id clip-id}
(let [{:keys [x y width height]} (get-clip-area vbox zoom axis)]
[:rect {:x x :y y :width width :height height}])]]
(for [step-val (range minv (inc maxv) step)]
(let [{:keys [text-x text-y line-x1 line-y1 line-x2 line-y2]}
(get-rule-axis step-val vbox zoom axis)]
[:*
[:text {:key (str "text-" (d/name axis) "-" step-val)
:x text-x
:y text-y
:text-anchor "middle"
:dominant-baseline "middle"
:transform (when (= axis :y) (str "rotate(-90 " text-x "," text-y ")"))
:style {:font-size (/ 13 zoom)
:font-family "sourcesanspro"
:fill colors/gray-30}}
(str (mth/round step-val))]
[:line {:key (str "line-" (d/name axis) "-" step-val)
:x1 line-x1
:y1 line-y1
:x2 line-x2
:y2 line-y2
:style {:stroke colors/gray-30
:stroke-width rules-width}}]])))]))
(let [{:keys [start end]} (get-rule-params vbox axis)
minv (max (mth/round start) -100000)
minv (* (mth/ceil (/ minv step)) step)
maxv (min (mth/round end) 100000)
maxv (* (mth/floor (/ maxv step)) step)]
(for [step-val (range minv (inc maxv) step)]
(let [{:keys [text-x text-y line-x1 line-y1 line-x2 line-y2]}
(get-rule-axis step-val vbox zoom axis)]
[:*
[:text {:key (str "text-" (d/name axis) "-" step-val)
:x text-x
:y text-y
:text-anchor "middle"
:dominant-baseline "middle"
:transform (when (= axis :y) (str "rotate(-90 " text-x "," text-y ")"))
:style {:font-size (/ font-size zoom)
:font-family font-family
:fill colors/gray-30}}
(str (mth/round step-val))]
[:line {:key (str "line-" (d/name axis) "-" step-val)
:x1 line-x1
:y1 line-y1
:x2 line-x2
:y2 line-y2
:style {:stroke colors/gray-30
:stroke-width rules-width}}]])))]]))
(mf/defc selection-area
[{:keys [vbox zoom selection-rect]}]
[:g.selection-area
[:g
[:rect {:x (:x selection-rect)
:y (:y vbox)
:width (:width selection-rect)
:height (/ rule-area-size zoom)
:style {:fill selection-area-color
:fill-opacity selection-area-opacity}}]
[:rect {:x (- (:x selection-rect) (/ over-number-size zoom))
:y (:y vbox)
:width (/ over-number-size zoom)
:height (/ rule-area-size zoom)
:style {:fill rules-background
:fill-opacity over-number-opacity}}]
[:text {:x (- (:x1 selection-rect) (/ 4 zoom))
:y (+ (:y vbox) (/ 12 zoom))
:text-anchor "end"
:dominant-baseline "middle"
:style {:font-size (/ font-size zoom)
:font-family font-family
:fill selection-area-color}}
(str (mth/round (:x1 selection-rect)))]
[:rect {:x (:x2 selection-rect)
:y (:y vbox)
:width (/ over-number-size zoom)
:height (/ rule-area-size zoom)
:style {:fill rules-background
:fill-opacity over-number-opacity}}]
[:text {:x (+ (:x2 selection-rect) (/ 4 zoom))
:y (+ (:y vbox) (/ 12 zoom))
:text-anchor "start"
:dominant-baseline "middle"
:style {:font-size (/ font-size zoom)
:font-family font-family
:fill selection-area-color}}
(str (mth/round (:x2 selection-rect)))]]
(let [center-x (+ (:x vbox) (/ rule-area-half-size zoom))
center-y (- (+ (:y selection-rect) (/ (:height selection-rect) 2)) (/ rule-area-half-size zoom))]
[:g {:transform (str "rotate(-90 " center-x "," center-y ")")}
[:rect {:x (- center-x (/ (:height selection-rect) 2) (/ rule-area-half-size zoom))
:y (- center-y (/ rule-area-half-size zoom))
:width (:height selection-rect)
:height (/ rule-area-size zoom)
:style {:fill selection-area-color
:fill-opacity selection-area-opacity}}]
[:rect {:x (- center-x (/ (:height selection-rect) 2) (/ rule-area-half-size zoom) (/ over-number-size zoom))
:y (- center-y (/ rule-area-half-size zoom))
:width (/ over-number-size zoom)
:height (/ rule-area-size zoom)
:style {:fill rules-background
:fill-opacity over-number-opacity}}]
[:rect {:x (+ (- center-x (/ (:height selection-rect) 2) (/ rule-area-half-size zoom) ) (:height selection-rect))
:y (- center-y (/ rule-area-half-size zoom))
:width (/ over-number-size zoom)
:height (/ rule-area-size zoom)
:style {:fill rules-background
:fill-opacity over-number-opacity}}]
[:text {:x (- center-x (/ (:height selection-rect) 2) (/ 15 zoom))
:y center-y
:text-anchor "end"
:dominant-baseline "middle"
:style {:font-size (/ font-size zoom)
:font-family font-family
:fill selection-area-color}}
(str (mth/round (:y2 selection-rect)))]
[:text {:x (+ center-x (/ (:height selection-rect) 2) )
:y center-y
:text-anchor "start"
:dominant-baseline "middle"
:style {:font-size (/ font-size zoom)
:font-family font-family
:fill selection-area-color}}
(str (mth/round (:y1 selection-rect)))]])])
(mf/defc rules
{::mf/wrap-props false
::mf/wrap [mf/memo]}
::mf/wrap [#(mf/memo' % (mf/check-props ["zoom" "vbox" "selected-shapes"]))]}
[props]
(let [zoom (obj/get props "zoom")
vbox (obj/get props "vbox")]
(let [zoom (obj/get props "zoom")
vbox (obj/get props "vbox")
selected-shapes (-> (obj/get props "selected-shapes")
(hooks/use-equal-memo))
selection-rect
(mf/use-memo
(mf/deps selected-shapes)
#(when (d/not-empty? selected-shapes)
(gsh/selection-rect selected-shapes)))]
(when (some? vbox)
[:g.rules {:pointer-events "none"}
[:& rules-axis {:zoom zoom :vbox vbox :axis :x}]
[:& rules-axis {:zoom zoom :vbox vbox :axis :y}]])))
[:& rules-axis {:zoom zoom :vbox vbox :axis :y}]
(when (some? selection-rect)
[:& selection-area {:zoom zoom
:vbox vbox
:selection-rect selection-rect}])])))

View File

@ -15,6 +15,16 @@
[app.util.dom :as dom]
[rumext.alpha :as mf]))
(def scroll-x 10)
(def scroll-y 10)
(def scroll-height (+ scroll-x 4))
(def scroll-width (+ scroll-y 4))
(def other-x 26)
(def other-y 26)
(def other-width 100)
(def other-height 100)
(mf/defc viewport-scrollbars
{::mf/wrap [mf/memo]}
[{:keys [objects viewport-ref zoom vbox]}]
@ -49,8 +59,8 @@
(gsh/selection-rect shapes))))
inv-zoom (/ 1 zoom)
vbox-height (- (:height vbox) (* inv-zoom 44))
vbox-width (- (:width vbox) (* inv-zoom 34))
vbox-height (- (:height vbox) (* inv-zoom scroll-height))
vbox-width (- (:width vbox) (* inv-zoom scroll-width))
;; top space hidden because of the scroll
top-offset (-> (- vbox-y (:y base-objects-rect))
@ -78,28 +88,28 @@
show-v-scroll? (or @v-scrolling? (> top-offset 0) (> bottom-offset 0))
show-h-scroll? (or @h-scrolling? (> left-offset 0) (> right-offset 0))
v-scrollbar-x (+ vbox-x (:width vbox) (* inv-zoom -32))
v-scrollbar-x (+ vbox-x (:width vbox) (* inv-zoom (- scroll-x)))
v-scrollbar-y (+ vbox-y top-offset)
h-scrollbar-x (+ vbox-x left-offset)
h-scrollbar-y (+ vbox-y (:height vbox) (* inv-zoom -40))
h-scrollbar-y (+ vbox-y (:height vbox) (* inv-zoom (- scroll-y)))
scrollbar-height (-> (- (+ vbox-y vbox-height) bottom-offset v-scrollbar-y))
scrollbar-height (-> (cond
@v-scrolling? scrollbar-height-stored
:else scrollbar-height)
(max (* inv-zoom 100)))
(max (* inv-zoom other-height)))
scrollbar-width (-> (- (+ vbox-x vbox-width) right-offset h-scrollbar-x))
scrollbar-width (-> (cond
@h-scrolling? scrollbar-width-stored
:else scrollbar-width)
(max (* inv-zoom 100)))
(max (* inv-zoom other-width)))
v-scrollbar-y (-> (cond
@v-scrolling? (- v-scrollbar-y-stored (- (- vbox-y (mf/ref-val vbox-y-ref))))
:else v-scrollbar-y)
(max (+ vbox-y (* inv-zoom 26))))
(max (+ vbox-y (* inv-zoom other-y))))
v-scrollbar-y (if (> (+ v-scrollbar-y scrollbar-height) (+ vbox-y vbox-height)) ;; the scroll bar is stick to the bottom
(-> (+ vbox-y vbox-height)
@ -109,7 +119,7 @@
h-scrollbar-x (-> (cond
@h-scrolling? (- h-scrollbar-x-stored (- (- vbox-x (mf/ref-val vbox-x-ref))))
:else h-scrollbar-x)
(max (+ vbox-x (* inv-zoom 26))))
(max (+ vbox-x (* inv-zoom other-x))))
h-scrollbar-x (if (> (+ h-scrollbar-x scrollbar-width) (+ vbox-x vbox-width)) ;; the scroll bar is stick to the right
(-> (+ vbox-x vbox-width)

View File

@ -148,7 +148,7 @@
(dom/remove-attribute node "transform")))))))
(defn format-viewbox [vbox]
(str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))
(str/join " " [(:x vbox 0)
(:y vbox 0)
(:width vbox 0)
(:height vbox 0)]))

View File

@ -407,21 +407,19 @@
(defn scroll-into-view!
([^js element]
(when (some? element)
(.scrollIntoView element false)))
(scroll-into-view! element false))
([^js element scroll-top]
([^js element options]
(when (some? element)
(.scrollIntoView element scroll-top))))
(.scrollIntoView element options))))
(defn scroll-into-view-if-needed!
([^js element]
(when (some? element)
(.scrollIntoViewIfNeeded ^js element false)))
(scroll-into-view-if-needed! element false))
([^js element scroll-top]
([^js element options]
(when (some? element)
(.scrollIntoViewIfNeeded ^js element scroll-top))))
(.scrollIntoViewIfNeeded ^js element options))))
(defn is-in-viewport?
[^js element]

View File

@ -278,3 +278,8 @@
dw/reset-zoom
(dw/update-viewport-position {:x (constantly 0) :y (constantly 0)})))
(defn ^:export hide-ui
[]
(st/emit!
(dw/toggle-layout-flags :hide-ui)))

View File

@ -3127,7 +3127,7 @@ msgstr "Historial (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Capes (%s)"
msgstr "Capes"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -3143,7 +3143,7 @@ msgstr "Mapa del lloc"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Recursos (%s)"
msgstr "Recursos"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -3032,7 +3032,7 @@ msgstr "Verlauf (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Ebenen (%s)"
msgstr "Ebenen"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -3048,7 +3048,7 @@ msgstr "Sitemap"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Assets (%s)"
msgstr "Assets"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -2163,7 +2163,7 @@ msgstr "Ιστορικό (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "στρώσεις (%s)"
msgstr "στρώσεις"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -2179,7 +2179,7 @@ msgstr "Χάρτης ιστοτόπου"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Στοιχεία (%s)"
msgstr "Στοιχεία"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -3244,7 +3244,7 @@ msgstr "History (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Layers (%s)"
msgstr "Layers"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -3260,7 +3260,7 @@ msgstr "Sitemap"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Assets (%s)"
msgstr "Assets"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"
@ -3430,4 +3430,7 @@ msgid "workspace.updates.update"
msgstr "Update"
msgid "workspace.viewport.click-to-close-path"
msgstr "Click to close the path"
msgstr "Click to close the path"
msgid "workspace.shape.menu.hide-ui"
msgstr "Show/Hide UI"

View File

@ -3257,7 +3257,7 @@ msgstr "Historial (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Capas (%s)"
msgstr "Capas"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -3273,7 +3273,7 @@ msgstr "Mapa del sitio"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Recursos (%s)"
msgstr "Recursos"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"
@ -3443,4 +3443,7 @@ msgid "workspace.updates.update"
msgstr "Actualizar"
msgid "workspace.viewport.click-to-close-path"
msgstr "Pulsar para cerrar la ruta"
msgstr "Pulsar para cerrar la ruta"
msgid "workspace.shape.menu.hide-ui"
msgstr "Mostrar/Ocultar Interfaz"

View File

@ -2535,7 +2535,7 @@ msgstr "Historique (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Calques (%s)"
msgstr "Calques"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -2551,7 +2551,7 @@ msgstr "Plan du site"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Ressources (%s)"
msgstr "Ressources"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -3078,7 +3078,7 @@ msgstr "היסטוריה (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "שכבות (%s)"
msgstr "שכבות"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -3094,7 +3094,7 @@ msgstr "מפת אתר"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "משאבים (%s)"
msgstr "משאבים"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -1844,7 +1844,7 @@ msgstr "Histórico (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Camadas (%s)"
msgstr "Camadas"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"

View File

@ -2417,7 +2417,7 @@ msgstr "Istoric (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Layere (%s)"
msgstr "Layere"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -2433,7 +2433,7 @@ msgstr "Harta site-ului"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Obiecte (%s)"
msgstr "Obiecte"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -3112,7 +3112,7 @@ msgstr "Geçmiş (%s)"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "Katmanlar (%s)"
msgstr "Katmanlar"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -3128,7 +3128,7 @@ msgstr "Site haritası"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "Varlıklar(%s)"
msgstr "Varlıklar"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"

View File

@ -2527,7 +2527,7 @@ msgstr "历史(%s"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.sidebar.layers"
msgstr "图层%s"
msgstr "图层"
#: src/app/main/ui/workspace/sidebar/options/menus/svg_attrs.cljs, src/app/main/ui/handoff/attributes/svg.cljs
msgid "workspace.sidebar.options.svg-attrs.title"
@ -2543,7 +2543,7 @@ msgstr "站点地图"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.assets"
msgstr "素材%s"
msgstr "素材"
#: src/app/main/ui/workspace/left_toolbar.cljs
msgid "workspace.toolbar.color-palette"