mirror of
https://github.com/penpot/penpot.git
synced 2026-05-07 00:58:48 +00:00
Merge pull request #1534 from penpot/feat/toolbars-redesign
Toolbars Redesign
This commit is contained in:
commit
b194c0c5d8
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
$width-settings-bar: 16rem;
|
||||
$width-left-toolbar: 48px;
|
||||
$width-settings-bar: 256px;
|
||||
|
||||
.handoff-layout {
|
||||
height: 100vh;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
26
frontend/resources/styles/main/partials/text-palette.scss
Normal file
26
frontend/resources/styles/main/partials/text-palette.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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])))))
|
||||
|
||||
@ -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 {} (->>
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
109
frontend/src/app/main/ui/hooks/resize.cljs
Normal file
109
frontend/src/app/main/ui/hooks/resize.cljs
Normal 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))
|
||||
@ -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)
|
||||
|
||||
@ -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])]]]]]))
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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}]))
|
||||
|
||||
@ -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
|
||||
[]
|
||||
|
||||
@ -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]]]]))
|
||||
|
||||
|
||||
@ -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]]]]))
|
||||
|
||||
@ -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])]]))
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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}]]))
|
||||
|
||||
152
frontend/src/app/main/ui/workspace/textpalette.cljs
Normal file
152
frontend/src/app/main/ui/workspace/textpalette.cljs
Normal 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}]))
|
||||
@ -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
|
||||
|
||||
@ -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)))))))
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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? %))
|
||||
|
||||
@ -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)]))
|
||||
|
||||
@ -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}])])))
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)]))
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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)))
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user