WIP WYSIWYG ~3D SVG editor.
1/* Global styles */
2*, *::before, *::after {
3 box-sizing: border-box;
4 margin: 0;
5 line-height: calc(1em + 0.5rem);
6}
7
8body {
9 -webkit-font-smoothing: antialiased;
10}
11
12img, picture, video, canvas, svg {
13 display: block;
14 max-width: 100%;
15}
16
17input, button, textarea, select {
18 font: inherit;
19 border: none;
20}
21
22/* Presets */
23:root {
24 --charcoal: #333;
25 --raisin: #534;
26 --faded-raisin: #5342;
27 --plum: #636;
28 --rose: #C25;
29 --orange: #E62;
30 --gold: #EA0;
31 --lemon: #ED0;
32 --peach: #FDB;
33 --lace: #FFF4E8;
34 --blueberry: #359;
35 --lime: #4A2;
36 --mint: #CFD;
37
38 --roundness: .5rem;
39}
40
41/* Fonts */
42body {
43 font-family: "din-2014-rounded-variable", sans-serif;
44 font-variation-settings: "wght" 400;
45 color: var(--raisin);
46}
47
48/* Toolbar */
49button {
50 width: 2rem;
51 height: 2rem;
52 border-radius: var(--roundness);
53
54 color: var(--raisin);
55 background: var(--lace);
56 box-shadow: 0 0 0 0.25rem transparent;
57
58 cursor: pointer;
59 font-size: 0;
60 transition: box-shadow 0.2s, background 0.2s;
61}
62
63button:first-letter {
64 font-size: 1.5rem;
65 line-height: 2rem;
66 font-variation-settings: "wght" 600;
67}
68
69button:hover {
70 background: var(--peach);
71 box-shadow: 0 1px 0.25rem 0 color-mix(in srgb, var(--raisin) 10%, transparent);
72}
73
74menu {
75 position: fixed;
76 left: 0;
77 height: 100vh;
78 padding-left: 1rem;
79 padding-top: 1rem;
80 display: flex;
81 flex-direction: column;
82 gap: .5em;
83}
84
85menu li {
86 list-style: none;
87}
88
89main {
90 width: 100vw;
91 height: 100vh;
92
93 display: grid;
94 grid-template-columns: 1fr 20rem;
95 grid-template-rows: 20rem 1fr;
96 grid-template-areas:
97 "canvas outliner"
98 "canvas properties";
99}
100
101/* Canvas */
102.canvas-container {
103 position: relative;
104 grid-area: canvas;
105}
106
107.canvas-layer {
108 position: absolute;
109 width: 100%;
110 height: 100%;
111 pointer-events: none;
112}
113
114#canvas {
115 pointer-events: auto;
116 z-index: 0;
117}
118
119#canvas {
120 cursor: grab;
121}
122
123#overlay ~ #canvas:active {
124 cursor: grabbing;
125}
126
127#canvas > * {
128 cursor: pointer;
129}
130
131/* Change to pointer when clicking on canvas would deselect elements */
132#overlay:has(> *) ~ #canvas {
133 cursor: pointer;
134}
135
136#overlay {
137 opacity: 0.8;
138 z-index: 1;
139}
140
141/*#overlay:not(:empty) {
142 filter: url(#better-highlight);
143}*/
144
145#ui {
146 z-index: 2;
147}
148
149#ui > *, #ui.active {
150 pointer-events: auto;
151 cursor: pointer;
152}
153
154/* Panels */
155#properties, #outliner {
156 max-height: 100%;
157 overflow-y: scroll;
158 margin: 1rem;
159 padding: 1rem;
160 background: var(--lace);
161 color: var(--raisin);
162 border-radius: var(--roundness);
163 border: 2px solid var(--raisin);
164 box-shadow: .5px .5px 0 .5px var(--raisin);
165}
166
167#properties {
168 grid-area: properties;
169 margin-top: .5rem;
170}
171
172#outliner {
173 grid-area: outliner;
174 margin-bottom: .5rem;
175}
176
177/* Properties */
178.prop-group {
179 padding: .5rem;
180 margin: .5rem;
181 border: 2px solid var(--faded-raisin);
182 border-radius: var(--roundness);
183}
184
185.prop {
186 display: flex;
187 flex-flow: row wrap;
188 align-items: center;
189 justify-content: space-between;
190}
191
192.prop h4 {
193 flex-basis: 100%;
194 text-align: center;
195 line-height: 1;
196 margin-top: .5rem;
197}
198
199.prop.vector label {
200 margin-right: 0 !important;
201}
202
203.prop.vector input + label {
204 margin-left: .75rem;
205}
206
207.prop input[type="number"] {
208 width: 1rem;
209 flex-grow: 10;
210}
211
212.prop input {
213 margin: .25rem 0;
214 padding: .125rem;
215 text-align: center;
216 max-width: 6rem;
217 border: 1px solid var(--raisin);
218 box-shadow: .5px .5px 0 .5px var(--raisin);
219 border-radius: calc( var(--roundness) / 2 );
220}
221
222#properties label {
223 font-weight: bold;
224 font-size: 1em;
225 margin-right: .25rem;
226 flex-grow: 1;
227}
228
229#properties.hidden .prop-group,
230#properties .prop-group:not(:has(:not(.hidden))),
231#properties .hidden {
232 display: none;
233}
234
235/* Hide disabled optional properties */
236#properties .prop.optional input[type="checkbox"]:not(:checked) + input {
237 display: none;
238}
239
240/* Outliner */
241#outliner ul {
242 --color: #333;
243 padding-left: 0;
244}
245
246#outliner li {
247 list-style: none;
248 padding: .1rem .5rem;
249 padding-right: 0;
250 font-size: 1.1rem;
251}
252
253#outliner .name {
254 display: inline-block;
255 width: 100%;
256}
257
258#outliner li.selected {
259 background: var(--peach);
260 color: #111;
261 border-radius: var(--roundness);
262
263 & > .name {
264 font-weight: bold;
265 color: #000;
266 text-decoration: underline;
267 }
268}
269
270#outliner .icon {
271 display: inline-block;
272 width: 1rem;
273 height: 1rem;
274 background-color: var(--color);
275 vertical-align: middle;
276 margin-right: .25rem;
277 border-radius: .25rem;
278}
279
280/* Outliner icons */
281/*#outliner .icon {
282 clip-path: circle(50%);
283}
284
285#outliner [data-type] > .name > .icon {
286 width: 32px;
287 height: 32px;
288 transform: scale(0.5);
289 margin: -8px;
290 margin-right: calc( .25rem - 8px );
291}
292
293#outliner [data-type="Illustration"] > .name > .icon {
294 clip-path: path("M30.5 6.3c0-1.8.5-5.1-6.9-5.1S2.5.5 1.4 1.6 1 17.4.9 20C.8 33.8.8 30.8 29.4 30.9s.4-21.1 1-24.7zM3.8 3.7c7.1-.1 14.2 0 21.3.6 1.3 7.2 1.4 14.5.4 21.7-7.1-.1-14.2-.3-21.3-.4-.3-6.1-.4-20.7-.4-21.9zm9.3 16.4c-1 .1-2.3.6-3.3.2-1.7-.8-.5-2.5 0-3.6 1.4-2.6 2.4-5.4 3.6-8 0-1.5 2-2 2.8-.7 1.7 2.8 3.5 5.5 5.1 8.4 2.2 4.1-6.1 3.1-8.3 3.8z");
295}
296
297#outliner [data-type="Cone"] > .name > .icon {
298 clip-path: path("M27.7,22.6c-3.4-5.9-6.4-11.9-9-18.2,0,0,0,0,0,0-.4-.9-.6-2.1-1.8-2.1-4.8-1.4-8.7,12.1-10.9,15.7-.4,2-3.8,4.7-1.8,6.5,3.9,3.3,25,5.9,23.5-1.9ZM10.1,16c1.6-3.6,3.3-7.4,5.8-10.5,2.2,5.2,4.6,10.2,7.3,15.1-4.8-1.3-10.1-1.7-14.9-.6.6-1.3,1.2-2.7,1.8-4Z");
299}
300#outliner [data-type="Shape"] > .name > .icon {
301 clip-path: path("M26.58 5.2c-2.01-5-9.77-1.5-8.26 3.29-9.06 2.82.9 13.49-6.37 15.01 1.51-6.12-7.26-9.07-8.02-2.1-.24 2.47 1.45 4.4 4.36 4.16 9 .93 9.75-1.72 8.85-10.88-.25-2.54 1.82-4.02 3.15-3.98 2.39.69 8.54-.26 6.29-5.5zM6.61 22.66c-1.14-2.55 2.18-3.31 2.7-1.4.45 1.64-1.84 2.96-2.7 1.4zM24.54 7.08c.46 1.93-3.4 2.59-3.73.65-.41-2.39 2.91-4.06 3.73-.65z");
302}*/
303
304/* Footer */
305/* Animation */
306@keyframes toast {
307 0% {
308 transform: translateY(100%);
309 }
310 10%, 90% {
311 transform: translateY(0);
312 }
313 100% {
314 transform: translateY(100%);
315 }
316}
317footer {
318 display: inline-block;
319 position: fixed;
320 bottom: 0;
321 left: 0;
322 padding: .25rem;
323 background: var(--lace);
324 color: var(--raisin);
325 border-top-right-radius: .25rem;
326 animation: toast 5s;
327 animation-delay: 2s;
328 transform: translateY(100%);
329}