Compare commits

...

546 Commits

Author SHA1 Message Date
Vilius
4f4ca0c96c
Update README.md 2025-08-19 21:23:41 +03:00
Vilius
6d0b95e50c
Merge pull request #414 from emresaracoglu/patch-1
Update README.md
2024-11-14 22:07:59 +02:00
Emre Saraçoğlu
c48593190f
Update README.md
Same fix
2024-11-14 10:00:05 +03:00
Vilius
054d89cccd
Merge pull request #408 from arthurdeka/master
Update pt.json
2024-06-30 19:44:58 +03:00
Arthur
d32e925125 Update pt.json
Fixing portuguese grammatical errors.
2024-06-28 18:58:43 -03:00
Vilius
352a231973
Merge pull request #403 from Seayouth/fix_zh_trans
Fix Chinese translation problem
2024-04-11 22:56:15 +03:00
Skyyouth
e38f1040c0 Fix Manually check and supplement some missing Chinese translations 2024-04-11 10:28:06 +08:00
Skyyouth
faf9a2afc4 Fix Chinese translation problem 2024-04-10 16:44:48 +08:00
Vilius
c47dcbf6e5
Merge pull request #399 from new-sankaku/master
Improved Japanese translation
2024-03-20 21:58:06 +02:00
new-sankaku
96d9e12017 Improved Japanese translation 2024-03-20 23:34:34 +09:00
viliusle
9e57e09371 version 4.14.2 2024-03-19 22:05:16 +02:00
viliusle
2ba14fe4ef #396 - IME input compatible 2024-03-19 22:01:39 +02:00
viliusle
df0f259172 v4.14.1 2023-12-01 15:42:41 +02:00
viliusle
f4aba673d4 XSS fix update 2023-12-01 15:40:32 +02:00
viliusle
7c2c056642 version 4.14.0 2023-12-01 15:07:17 +02:00
viliusle
f22cb46515 XSS fix (layers name) 2023-12-01 15:05:05 +02:00
viliusle
1fce319dc9 updated nl translations 2023-12-01 14:49:47 +02:00
viliusle
1fed01dde0 updated tool to extract translations 2023-12-01 14:49:21 +02:00
viliusle
1e11f8d590 added nl translation 2023-12-01 14:31:08 +02:00
viliusle
b34b031f3d auto focus fields on some modal dialogs 2023-12-01 14:24:02 +02:00
Vilius
85e850b40d
Merge pull request #378 from bit9labs/master
Switch to select tool after choosing a media clip
2023-12-01 13:56:01 +02:00
viliusle
cf894ac34a npm update (libraries update) & audit 2023-12-01 13:55:45 +02:00
viliusle
79c79ca4a5 added latest translations, updated base transaltion file 2023-12-01 13:40:11 +02:00
viliusle
95b496c480 updated translation tool to extract translations 2023-12-01 12:55:13 +02:00
viliusle
1032804da4 fixed PR-386 2023-12-01 12:54:30 +02:00
Vilius
8189d9c4a6
Merge pull request #386 from phpony/master
Multiple translation issues + RU lang file
2023-12-01 12:25:47 +02:00
Volkov Maksim
153134809b
Corrected and completed Russian lang file 2023-11-27 00:41:35 +03:00
Volkov Maksim
b3cb94e7bd
Make "details" box translatable 2023-11-27 00:18:11 +03:00
Volkov Maksim
dcc3d08d33
Make color box and color dialog translatable 2023-11-27 00:13:58 +03:00
Volkov Maksim
8f255597e4
Make "Infromation" box translatable 2023-11-27 00:02:21 +03:00
Volkov Maksim
eff3ce5894
Enabling translation in "Layers" interface block 2023-11-26 23:59:39 +03:00
Volkov Maksim
cef7e6f79c
Unnecessary spaces in toolbar labels
We don't need space symbols at the end of label HTML. Spacing is done in CSS anyway.
2023-11-26 23:00:37 +03:00
Volkov Maksim
48bda1d41f
Untranslated menu fix
Menu is not being translated from page load till first interaction with it. Should call translate after render_main().
2023-11-26 22:52:38 +03:00
Volkov Maksim
53d3ef7f83
Make labels in toolbar translatable
<label> elements in toolbar should have "tr" class to be translatable too.
2023-11-26 22:24:31 +03:00
Bit9Labs
7ca23d9e07 Switch to select tool after choosing a media clip 2023-07-28 16:46:50 -04:00
Vilius
d36fbadd86
Merge pull request #370 from parse-g/master
Update russian translate
2023-07-23 21:15:57 +03:00
Mihail
9522fd4343 Update russian translate
In this update fixed some inaccuracies, letters registers and some untranslatable words, like language names or font names.
2023-06-09 14:21:11 +03:00
viliusle
7b8ad8b6ac version 4.13.0 2023-04-21 19:47:20 +03:00
viliusle
9dd908c390 change canvas size with "in proportion" feature (resize and move all layers) 2023-04-21 19:22:18 +03:00
viliusle
e5af391390 information window update, fixed issues when formatting numbers 2023-04-21 13:30:47 +03:00
viliusle
39f8d5ed52 resolution small update while saving 2023-04-21 13:27:25 +03:00
viliusle
b71c64b227 better error messages when tryng to do forbidden actions on rotated objects 2023-04-21 11:43:48 +03:00
viliusle
e5022921e2 translations strings update 2023-04-21 11:40:48 +03:00
viliusle
f5f79d055f show resolution during save dialog 2023-04-21 11:39:42 +03:00
Vilius
69b08a1326
security.md file 2023-04-21 10:44:52 +03:00
viliusle
bf0b62e6c5 webpack version update 2023-04-21 10:33:10 +03:00
viliusle
f9015fe58d npm audit 2023-04-21 10:29:19 +03:00
Vilius
736aea47e2
Merge pull request #367 from wklkejw239/patch-1
add contributors in README.md
2023-04-21 10:12:19 +03:00
vincivermeer
b424482e4d
add contributors in README.md
Hello everyone!

I added the contributors in the readme.md file in the repository: viliusle/miniPaint. I would like to contribute to this pull-request and I hope you all accept it.

what do you all think of this idea?
2023-04-06 01:37:37 -03:00
viliusle
35acc344a8 version 4.12.0 2023-02-07 00:08:37 +02:00
viliusle
fe020842b0 ability to edit tools (shapes) attributes like color, size after object is created 2023-02-07 00:07:22 +02:00
viliusle
0bc28fcbc4 fixed layer details section styles 2023-02-05 17:45:23 +02:00
viliusle
abc3704c9a npm audit 2023-02-05 17:37:03 +02:00
viliusle
ee7d8325cd fixed keypoints tool, when layer is smaller than canvas 2023-02-04 23:15:53 +02:00
viliusle
790c1e100e 4.11.0 version bundle 2023-01-31 22:30:18 +02:00
viliusle
f1eb954087 bezier tool update: support for CTRL modifier ke 2023-01-26 13:33:49 +02:00
viliusle
b9693d21db #314: fixed Gaussian Blur & shadow filters (it was affected by zoom level) 2023-01-08 22:58:52 +02:00
viliusle
ddf97ca4c4 #333: dynamically change theme based on OS preferences (disabled) 2023-01-08 22:45:30 +02:00
viliusle
62ca359776 #310: fixed content fill 2023-01-08 22:09:43 +02:00
viliusle
bbb17d5dc3 #311 polygons 2023-01-07 23:28:14 +02:00
viliusle
fc0ccf3fa7 #311 fixed bezier undo states 2023-01-07 22:25:55 +02:00
viliusle
3df83776c7 #311 bezier curve 2023-01-07 21:31:40 +02:00
viliusle
5350803089 better duplicated layer name 2022-12-23 23:18:25 +02:00
viliusle
b3ca4dbd49 #311 - star24 shape migrated to star, old star object updated to general star with parameters 2022-12-23 23:18:02 +02:00
viliusle
92975b2dca #288 - fixed undo on rotated objects 2022-12-23 18:15:01 +02:00
viliusle
59f80c16bc service-worker.js comment 2022-08-29 20:09:24 +03:00
viliusle
342086f3f0 fixed CSS comment 2022-08-29 20:05:25 +03:00
viliusle
a72e3f12a3 v4.10.1 2022-08-06 22:32:00 +03:00
viliusle
ce570658f7 npm update 2022-08-06 22:30:14 +03:00
viliusle
1a9ea280e4 #328 fixed JSON import (canvas size, version check) 2022-08-06 22:28:33 +03:00
Vilius
b249e2b70b
Merge pull request #316 from parse-g/ru-fix
some russian languages fixes
2022-04-28 22:18:14 +03:00
Mihail
ec27681450
more fixes 2022-04-28 20:52:48 +03:00
Mihail
caf9f03f1a
some languages fixes 2022-04-27 23:19:36 +03:00
Vilius
9556235502
Merge pull request #309 from viliusle/dependabot/npm_and_yarn/minimist-1.2.6
Bump minimist from 1.2.5 to 1.2.6
2022-04-01 21:26:54 +03:00
dependabot[bot]
797f946aa8
Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-01 17:43:34 +00:00
Vilius
885a162558
Merge pull request #306 from viliusle/dependabot/npm_and_yarn/node-forge-1.3.0
Bump node-forge from 1.2.1 to 1.3.0
2022-04-01 20:43:04 +03:00
viliusle
7e75b4c353 #304 base layers class fixes related to width, height and export, 308 PR by Giwayume 2022-04-01 20:41:32 +03:00
dependabot[bot]
f1be2f3145
Bump node-forge from 1.2.1 to 1.3.0
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-22 13:11:02 +00:00
viliusle
81afb22a39 version 4.10.0 2022-03-17 22:54:10 +02:00
viliusle
0855adb797 fixed layers list style (related to source-atop composition) 2022-03-16 23:18:20 +02:00
viliusle
7c5b8101e6 #179 - pencil update (pressure activation/deactivation UI) 2022-03-16 22:58:38 +02:00
viliusle
dae340d0ea pencil tool update: size and pressure support 2022-03-14 21:21:06 +02:00
viliusle
7d54a2d73e fixed preview buttons 2022-03-13 21:43:14 +02:00
viliusle
a596d2e59b disable right click on drawable area (it is browser menu, not related to app) 2022-03-13 19:20:18 +02:00
viliusle
e37651a4d9 flatten update: allow to flatten 1 layer 2022-03-13 18:53:00 +02:00
viliusle
35adb236ad button titles, duplicate and raster buttons 2022-02-23 00:06:54 +02:00
viliusle
b9ab37497a #297 - fix for PR (layers GUI was not updated automatically) 2022-02-22 22:45:54 +02:00
viliusle
7b1fac9fb5 Merge remote-tracking branch 'origin/master' 2022-02-22 22:44:36 +02:00
Vilius
170124f041
Merge pull request #298 from kmanaseryan/feature/indicate-layer-c-masked
Issue #297 - Indicate when the layer has clipping mask applied
2022-02-22 22:44:25 +02:00
viliusle
e8c784e2bd Merge branch 'feature/indicate-layer-c-masked' of https://github.com/kmanaseryan/miniPaint 2022-02-22 22:34:06 +02:00
Vilius
ff82f90435
Merge pull request #296 from kmanaseryan/fix/clipping-mask-2nd-layer-295
Issue #295 - Fix the bug related to 2nd clipped layer
2022-02-22 22:32:26 +02:00
Vilius
db8d0af14f
Merge pull request #293 from kmanaseryan/fix/rotate-imprv-286
Issue #286 - Rotation handle improvements
2022-02-22 22:23:00 +02:00
viliusle
2fa0c079e9 Merge remote-tracking branch 'origin/master' 2022-02-22 22:16:59 +02:00
viliusle
5f32f3797e npm audit 2022-02-22 22:15:17 +02:00
Karlen Manaseryan
e2a7446725 Issue #297 - Indicate when the layer has clipping mask applied 2022-02-20 22:30:45 +04:00
Karlen Manaseryan
82f641631b Issue #295 - Fix the bug related to 2nd clipped layer 2022-02-20 19:00:55 +04:00
Karlen Manaseryan
70938e3452 Issue #286 - Rotation handle improvements 2022-02-13 21:27:42 +04:00
Vilius
7cc20aaaa6
Merge pull request #281 from kmanaseryan/fix/rotate-bug-279
Issue #279 - Fix resize bug on certain rotate degree
2022-02-07 21:12:30 +02:00
Vilius
72647e4d0a
Merge pull request #282 from kmanaseryan/fix/source-atop-280
Fix: Clipped layers should respect the layers on top of it
2022-02-02 22:57:02 +02:00
Karlen Manaseryan
46928a2b18 Fix: Clipped layers should respect the layers on top of it 2022-02-02 20:23:45 +04:00
Karlen Manaseryan
877d35ebfb Issue #279 - Fix rotate bug 2022-02-01 17:48:28 +04:00
viliusle
0ea34e8997 version 4.9.3 2022-01-16 18:07:27 +02:00
viliusle
5658ae0684 npm audit 2022-01-16 18:05:25 +02:00
viliusle
45103ef618 trim fix: stop jumping layer to old coordinates, if image is big 2022-01-10 21:36:58 +02:00
viliusle
4c6204224d trim update: power parameter 2022-01-10 21:17:59 +02:00
viliusle
d71629e49a disabled rotation on brush, pencil 2022-01-10 20:54:27 +02:00
Vilius
c2aa4594e3
Merge pull request #276 from kmanaseryan/feature/rotate-text
Issue #185 - Allow text rotation
2022-01-03 23:59:20 +02:00
Karlen Manaseryan
f1e512ae2f Issue #185 - Allow text rotation 2021-12-24 18:09:29 +04:00
Vilius
d23b5e83fb
Merge pull request #275 from kmanaseryan/feature/clipped-layer-shadow-192
Issue #192 - Isolate shadow from clipped layer
2021-11-28 21:08:39 +02:00
Karlen Manaseryan
ee53f86e83 Issue #192 - formatting 2021-11-28 22:01:17 +04:00
Karlen Manaseryan
c07d9f8c9f Merge branch 'master' of https://github.com/viliusle/miniPaint into feature/clipped-layer-shadow-192 2021-11-28 21:56:03 +04:00
Karlen Manaseryan
2c4717a9f9 Issue #192 - Isolated shadow from clipped layer 2021-11-22 11:12:37 +04:00
Karlen Manaseryan
68b6835c54
Merge pull request #3 from kmanaseryan/feature/source-atop-231
Issue #231 - Feature/source atop
2021-10-27 20:35:10 +04:00
viliusle
1951006cf9 version 4.9.2 2021-10-24 20:30:57 +03:00
viliusle
e32e7d6a6e fixed issue, where opening big image + json would end with wrong preview in main canvas 2021-10-24 20:22:28 +03:00
viliusle
076ceae74e fixes for opening files on FireFix (fixed double file opening, fixed directory opening) 2021-10-24 16:32:50 +03:00
viliusle
aa48644325 fixed cog shape color 2021-10-24 16:10:22 +03:00
viliusle
c9f93538df #228 - manifest disabled forever - even it may work before this commit, still too much troubles to maintain (worker) and test everything. 2021-10-23 23:27:23 +03:00
viliusle
47dbbea3bc #228 - last attempt to add manifest, npm update 2021-10-23 23:14:09 +03:00
viliusle
ae900ac17e code format (reverting required PR #272) 2021-10-19 22:20:06 +03:00
Vilius
dde4ab4f26
Merge pull request #271 from kmanaseryan/feature/source-atop-231
Issue #231 - Feature source atop
2021-10-19 22:18:20 +03:00
Vilius
e062b421da
Merge pull request #272 from kmanaseryan/feature/source-atop-231-formatting
Issue #231 - Code formatting
2021-10-19 22:18:06 +03:00
Karlen Manaseryan
5d489738f6 Issue #231 - Implement Clipping Mask for render() method 2021-10-17 18:16:43 +04:00
Karlen Manaseryan
e6923445dc Issue #231 - Changes in main render funciton for the clipping mask 2021-09-28 20:29:50 +04:00
Karlen Manaseryan
497b0054a5 Issue #231 - Code refactoring for render_object() method 2021-09-28 18:37:02 +04:00
Karlen Manaseryan
a6e52102d2 Issue #231 - remove extra if condition which will never be entered 2021-09-27 18:55:49 +04:00
Karlen Manaseryan
6b22b1f80b
Merge pull request #2 from kmanaseryan/feature/source-atop-231-formatting
Issue #231 - Code formatting
2021-09-27 18:28:45 +04:00
Karlen Manaseryan
c720c768bc Issue #231 - Code formatting 2021-09-27 18:26:33 +04:00
viliusle
8b8aa3cd38 version 4.9.1 2021-08-03 00:12:57 +03:00
viliusle
b528b5d9d2 menu small change 2021-08-03 00:11:07 +03:00
viliusle
12e2e37a8a fix for saving as GIF 2021-08-02 23:51:27 +03:00
viliusle
cd2bd75804 version 4.9.0 2021-06-22 23:50:36 +03:00
viliusle
997089d506 fixed search shortcut on Mac 2021-06-22 23:47:07 +03:00
viliusle
fa6d7b69c7 #204 - global search 2021-06-21 23:38:55 +03:00
viliusle
b7a8e5eb9a #230: rotate with mouse 2021-06-20 20:57:15 +03:00
viliusle
28671d130c improved layers details GUI 2021-06-20 18:59:56 +03:00
viliusle
baba50ab7c improved mouse cursors on resize and move 2021-06-20 17:00:32 +03:00
viliusle
1c67672af5 bundle license 2021-06-20 12:03:24 +03:00
viliusle
2fe3781be0 version 4.8.0 2021-06-20 12:02:32 +03:00
viliusle
6008e723fc fixed select tool + coposition modal windows issue 2021-06-20 11:37:44 +03:00
viliusle
50b5c29e0e non destructive color corrections (when possible) 2021-06-20 11:13:49 +03:00
viliusle
f8689b180f color corrections code improvements 2021-06-20 01:44:01 +03:00
viliusle
3ba9005fbb #244: rendering improvements, if zoom in, sharpness is disabled and images will be rendered smoothly. 2021-06-20 01:03:04 +03:00
viliusle
8884e13a9b undo button for mobile 2021-06-20 00:31:03 +03:00
viliusle
43088b19c2 button to toggle left sidebar 2021-06-19 23:55:21 +03:00
viliusle
1c3568079d Landscape and Portrait layouts 2021-06-19 23:31:58 +03:00
viliusle
0fa15bd180 better parameters possibility on config-menu.js 2021-06-19 22:46:43 +03:00
viliusle
16f19baf47 fixed broken build 2021-06-19 21:27:09 +03:00
viliusle
e52df1c649 small fixes to brush and paint 2021-06-19 20:04:21 +03:00
viliusle
8a27ce1656 #240: borders type migrated to effects. 2021-06-19 20:04:03 +03:00
viliusle
1dab3914a2 guides small improvements 2021-06-19 17:11:17 +03:00
viliusle
7c4455f3d9 updated shapes default settings (activated borders) 2021-06-19 16:53:44 +03:00
viliusle
7e0d519e3c updated shortcuts (H fro shape, better list, also sorted) 2021-06-19 16:36:42 +03:00
viliusle
1699063904 new shapes: callout, cog, moon, tear 2021-06-19 15:58:17 +03:00
viliusle
6bb57b1590 ability to always force safe search 2021-06-13 22:16:10 +03:00
viliusle
433d702b0b editable filters (only if non-destructive) 2021-06-13 22:00:34 +03:00
viliusle
dc0c5de453 shadow filter improvements 2021-06-13 19:28:54 +03:00
viliusle
87bc43970c new translation language: English (UK) 2021-06-13 18:25:54 +03:00
viliusle
d680289719 fixed error during text drag 2021-06-11 22:41:43 +03:00
viliusle
4dcdb0fcbc npm udpate (upgrade to latest versions) 2021-06-11 22:41:11 +03:00
viliusle
928dcc218a npm update 2021-06-10 23:56:52 +03:00
viliusle
13c8912343 ability to drag directory 2021-06-10 23:43:54 +03:00
viliusle
4241260361 sprites update 2021-06-10 22:22:27 +03:00
viliusle
98730c226d shortcuts for both save and export 2021-06-10 21:53:57 +03:00
viliusle
b47682c93a trim fix 2021-06-10 21:47:31 +03:00
viliusle
6f56d1ba35 brush and undo fix 2021-06-10 21:38:02 +03:00
viliusle
4567f00493 fixed button hover color on top tools menu 2021-05-10 23:19:03 +03:00
viliusle
28dd0ffa6a updated zoom example 2021-05-10 23:05:30 +03:00
viliusle
91d2b8e9d0 #247 - vulnerability fix 2021-04-24 17:49:03 +03:00
viliusle
d9364248ef #251 - Update iframe examples to add feature policy for camera access 2021-04-24 17:33:40 +03:00
viliusle
6b7fd928f3 .gitignore update 2021-04-24 17:31:26 +03:00
viliusle
a4e4d3aef5 translations changes (order, new exclusions) 2021-04-24 17:31:26 +03:00
Vilius
5f83a58ef8
Merge pull request #252 from viliusle/dependabot/npm_and_yarn/ssri-6.0.2
Bump ssri from 6.0.1 to 6.0.2
2021-04-24 17:31:18 +03:00
viliusle
c02f662932 Greek language 2021-04-24 17:17:38 +03:00
dependabot[bot]
450c4db2e8
Bump ssri from 6.0.1 to 6.0.2
Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/npm/ssri/releases)
- [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md)
- [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-19 16:31:30 +00:00
viliusle
9e2cdac358 version 4.7.1 2021-04-15 21:02:59 +03:00
Vilius
d4a48230d7
Merge pull request #248 from lionel0806/master
Fix switch language error because of some strings not translation
2021-04-15 20:08:44 +03:00
lixian
08aa91d82b Fix switch language error because of some strings not translation 2021-04-15 09:24:01 +08:00
viliusle
cdc51cbfce version 4.7.0 2021-04-12 00:05:14 +03:00
viliusle
0e5bc1219c fixed file > save 2021-04-11 23:48:10 +03:00
viliusle
ad0558f71d fixed opening multiple various sizes images 2021-04-11 23:10:36 +03:00
viliusle
994552c387 ability to export multiple images with original type 2021-04-11 23:08:11 +03:00
viliusle
97872d230e fixed initial layer name 2021-04-11 22:27:57 +03:00
viliusle
d471fc41fc ability to have thick guides 2021-04-11 22:18:02 +03:00
viliusle
67aae07781 #243 - "File > new" will auto fit to screen 2021-04-11 22:08:01 +03:00
viliusle
e6901014c6 safe image search by default 2021-04-11 22:02:14 +03:00
viliusle
b346e60e90 trim fixes, it required to apply trim 2 times in some cases 2021-04-11 21:55:57 +03:00
viliusle
f0d3d06f7b more units (pixels, inches, cm, mm) 2021-04-11 21:19:06 +03:00
viliusle
ae39fd5f0b fixed few effects bugs 2021-04-06 23:12:39 +03:00
viliusle
f2cf1b6737 menu item rename (image > size, layers) 2021-04-06 21:24:14 +03:00
viliusle
ef6e45caa3 popup lib small fix () 2021-04-05 16:54:55 +03:00
viliusle
481fd5ae4c exit confirmation 2021-04-03 23:06:56 +03:00
viliusle
7e7454087a guide color update, was not clearly visible 2021-04-03 22:40:21 +03:00
viliusle
02bcee0e6a pagination on media search 2021-04-03 22:34:15 +03:00
viliusle
17b410fe44 safe search feature 2021-04-03 21:51:40 +03:00
viliusle
5ba3fbe4aa fixed loading last resolution 2021-04-03 21:50:51 +03:00
viliusle
2cd9227e4d optimized settings reading and saving. 2021-04-03 21:03:05 +03:00
viliusle
7507599d72 fixed current zoom level - was always showing 100% 2021-04-03 19:57:52 +03:00
viliusle
80ad57f7a8 fixed color on zoom button (hover state) 2021-04-03 19:55:53 +03:00
viliusle
c64af51d1c pencil tool update - removed antialiasing, brush should be used here instead 2021-04-03 19:25:55 +03:00
Vilius
ea86375ed4
Merge pull request #238 from viliusle/dependabot/npm_and_yarn/y18n-4.0.1
Bump y18n from 4.0.0 to 4.0.1
2021-04-03 18:44:41 +03:00
dependabot[bot]
7f545c5ed1
Bump y18n from 4.0.0 to 4.0.1
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-29 16:29:03 +00:00
Vilius
4eb75b3b26
Merge pull request #235 from viliusle/dependabot/npm_and_yarn/elliptic-6.5.4
Bump elliptic from 6.5.3 to 6.5.4
2021-03-12 23:02:05 +02:00
Vilius
4b0bf4a781
Merge pull request #234 from Giwayume/feature/google-font
Add google font search
2021-03-12 23:00:02 +02:00
viliusle
3b16567be5 fixed demo with importing image 2021-03-11 18:26:11 +02:00
viliusle
c77ce6aa54 fixed color #ffffffff handling (last commit was wrong) 2021-03-11 18:15:33 +02:00
dependabot[bot]
6c80a30e51
Bump elliptic from 6.5.3 to 6.5.4
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-03-08 16:49:40 +00:00
viliusle
5ee74e261f fixed color #ffffffff handling 2021-03-07 23:47:18 +02:00
acer
07c03377e5 Fix for user font same as default font 2021-02-27 22:40:33 -05:00
acer
b79bf2b020 Add google font search 2021-02-27 21:46:49 -05:00
viliusle
fdaac09784 version update - 4.6.1 2021-02-23 23:00:57 +02:00
viliusle
23c9f40bda popup lib code validation 2021-02-23 22:58:04 +02:00
viliusle
d398cd7117 fixed issue with saving big image, changing name and clicking "OK" to save (was working from second OK click) 2021-02-23 22:57:39 +02:00
viliusle
5948e6bb8a #232 - fixed rotate 2021-02-23 22:08:32 +02:00
viliusle
59b19f69a8 Arabic language 2021-02-14 18:32:02 +02:00
viliusle
3f8b4f4058 #228 - completely disabled manifest 2021-02-14 18:24:29 +02:00
viliusle
0dfd4b8db3 #228 - manifest.json disabled - development on local ENV was totally broken. 2021-02-14 18:19:22 +02:00
viliusle
fa14d98d58 #228 - Web app manifests (for offline usage) 2021-02-14 17:21:17 +02:00
Vilius
5831aac2ef
Merge pull request #227 from Giwayume/feature/color-picker-dialogs
Add new color selection to popups
2021-02-14 15:55:27 +02:00
acer
8034826180 Block user from clicking in background while popup is open 2021-02-11 12:43:16 -05:00
acer
c2c21f4d54 Add abiility to have multiple popup overlays, add new color picker to popups 2021-02-11 12:24:42 -05:00
viliusle
f837b0c40c updated text modal windows 2021-02-07 19:16:49 +02:00
viliusle
7f1e7e6242 save as TIFF 2021-02-07 18:31:08 +02:00
viliusle
10dd17363e #174 - color block items reorder, toggle colros on color small preview field click 2021-02-07 17:34:15 +02:00
viliusle
6f7829ceb1 version 4.6.0 2021-01-31 18:51:48 +02:00
viliusle
6867e4edca ruler 2021-01-31 18:50:34 +02:00
viliusle
bee177d4aa fixed layer details block if layer is text 2021-01-31 15:33:05 +02:00
viliusle
f737c2779d full-screen feature 2021-01-31 15:24:16 +02:00
viliusle
4a150c7d53 Menu items update: translations moved to tools, add "View" menu 2021-01-31 15:18:36 +02:00
viliusle
203185f0ef #223 - guides 2021-01-27 00:44:35 +02:00
viliusle
f30040f359 #222 #176 ability to work with tools outside of canvas 2021-01-25 00:18:22 +02:00
viliusle
052f1ac301 "save as" changed to "save" and "export" 2021-01-24 23:26:47 +02:00
viliusle
14813e1993 Translations, strings 2021-01-24 23:00:19 +02:00
viliusle
38d334251a draw ellipse from begin to end, not from center 2021-01-24 20:45:58 +02:00
viliusle
5f518d19f3 fixed broken image 2021-01-10 21:18:29 +02:00
viliusle
1a2995d184 version 4.5.0 2021-01-10 21:07:06 +02:00
viliusle
408d9ae62f snap improvements 2021-01-10 20:58:07 +02:00
viliusle
11624bfbc5 #220 - fixed menu > file > "search images" 2021-01-10 20:07:58 +02:00
viliusle
a80d2a617f snap updates 2021-01-10 20:07:21 +02:00
viliusle
8a8790ec76 fixed hexagon, pentagon, star, plus ration and bounds 2021-01-09 21:34:06 +02:00
viliusle
7d9ddf4dea fixed arrow resize 2021-01-05 23:43:01 +02:00
viliusle
601ac6a2e1 #205 - fixed non-transparent setting support 2021-01-05 23:36:57 +02:00
viliusle
f4f391fb13 #205 - basic support for copying layer to clipboard 2021-01-05 23:32:40 +02:00
viliusle
5ccd056cde updated human shape - removed border option. 2021-01-04 21:31:32 +02:00
viliusle
33503a28fc rolbacked and fixed attributes blur event 2021-01-04 21:29:14 +02:00
viliusle
5a8bc496f3 test image update 2021-01-03 22:48:56 +02:00
viliusle
85ba03dc59 optmized layers selection (simple check on big images) 2021-01-03 22:04:41 +02:00
viliusle
2873aab522 fixed bug, where editing layer details could affect another object after clicking on it 2021-01-03 21:51:48 +02:00
viliusle
1a8114fe68 snap fix: mousemove bug even if mouse is not moving. 2021-01-03 21:47:58 +02:00
viliusle
9b62f90efb modal browser style changes 2021-01-03 21:23:13 +02:00
viliusle
a15464d431 shapes, optimized tools events 2021-01-03 21:13:43 +02:00
viliusle
459e0e8b86 show render errors, if something is wrong. 2020-12-31 17:53:14 +02:00
Vilius
01ecec9731
Merge pull request #219 from Giwayume/feature/fix-autoresize-scenarios
Search image fix - ignore same size abort
2020-12-28 22:05:20 +02:00
acer
461f98a8ed Ignore same size in most autoresize scenarios 2020-12-27 22:26:38 -05:00
viliusle
067f0ea208 fixed issue where on_activate was not activated on multiple clicks 2020-12-27 21:06:43 +02:00
viliusle
ed059604ef fixed snap after undo changes 2020-12-27 18:59:52 +02:00
viliusle
a29cb75a8e wiki moved to web 2020-12-27 17:55:47 +02:00
Vilius
276e15d889
Merge pull request #218 from Giwayume/feature/rework-undo
Implement smarter undo/redo system
2020-12-27 17:37:20 +02:00
acer
8abbe2dfc0 Fix readme formatting 2020-12-26 20:33:36 -05:00
acer
aeb84f69fc Fix documentation spacing 2020-12-26 20:24:27 -05:00
acer
4d42a83912 Add readme to repository 2020-12-26 17:52:12 -05:00
acer
f4dd2d68ee Fix select across multiple layer bug 2020-12-26 16:27:47 -05:00
acer
374695c6ae Fix open image 2020-12-26 16:09:22 -05:00
acer
4cfcd228ad Fix indentation in new files 2020-12-25 00:47:15 -05:00
acer
a2234c0bee Add back log for test file 2020-12-25 00:22:23 -05:00
acer
d187d2073d Check rest of tools 2020-12-25 00:19:07 -05:00
acer
00ab65e12a Merge conflict with master 2020-12-24 10:51:58 -05:00
acer
8faf6625e7 Update a couple more tools 2020-12-24 10:29:33 -05:00
viliusle
0fa9934f93 favicon update 2020-12-23 22:57:22 +02:00
viliusle
8ea6cdcf34 snap fix - remove helping lines after mouse release 2020-12-13 20:47:30 +02:00
viliusle
c084eea157 removed console.log 2020-12-13 20:35:33 +02:00
viliusle
2180f6a60e #208 - snap feature 2020-12-13 20:33:48 +02:00
Vilius
e5f3b34d18
Merge pull request #215 from viliusle/dependabot/npm_and_yarn/ini-1.3.7
Bump ini from 1.3.5 to 1.3.7
2020-12-11 21:44:17 +02:00
viliusle
52cfef2afd npm audit + update 2020-12-11 21:43:17 +02:00
viliusle
4d14e5edb1 renamed some latest core methods 2020-12-11 21:16:10 +02:00
dependabot[bot]
50742a761e
Bump ini from 1.3.5 to 1.3.7
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-11 19:14:17 +00:00
viliusle
97998cf761 more GUI core methods, removed direct config access from libs 2020-12-11 21:13:09 +02:00
viliusle
a7a3820298 information tool update (no need to hover mouse over canvas to get dimensions) 2020-12-11 21:01:00 +02:00
viliusle
0b39902ed5 crop lines 2020-12-11 20:52:22 +02:00
viliusle
2344dee5d2 Information and Open shortcuts 2020-12-11 20:27:14 +02:00
viliusle
50c6951b37 animation tool fix 2020-12-11 20:18:19 +02:00
acer
84b2e1da25 Merge from master 2020-12-06 19:43:53 -05:00
acer
778ecd4d97 Implement undo in most tools 2020-12-06 19:24:03 -05:00
viliusle
31058a0661 version 4.4.2 2020-12-06 21:11:48 +02:00
viliusle
19be76e590 fixed render debugging 2020-12-06 21:09:50 +02:00
viliusle
26b979efc9 ability to debug rendering after opening test template 2020-12-06 21:05:47 +02:00
viliusle
99a6d33c3e #212 - GUI background color update 2020-12-06 20:41:15 +02:00
Vilius
3b21ebb72e
Merge pull request #213 from Giwayume/feature/text-tool-bugs
Text tool causing infinite render
2020-12-06 20:37:48 +02:00
acer
61cf584a93 Text tool causing infinite render 2020-12-06 11:13:37 -05:00
acer
3f27fea41f Working on selection 2020-12-06 11:11:55 -05:00
acer
209524648c Get most filters working with history and some tools 2020-12-06 00:13:14 -05:00
viliusle
478906e9ba fixed missing icons, 4.4.1 version. 2020-12-05 20:44:48 +02:00
viliusle
b64f53b840 bundling resources for version 4.4.0 2020-12-05 20:16:38 +02:00
viliusle
98f00969a8 reverted "Alt color option" commit 2020-12-05 20:11:44 +02:00
Vilius
543124d254
Merge pull request #207 from Giwayume/feature/inline-text-editing
Restyle selection to make it work easier with text and smaller layers
2020-12-05 20:02:07 +02:00
viliusle
31a480cf97 fixed last id after opening json 2020-12-05 20:01:43 +02:00
viliusle
9dda862a1f empty layer width and height should be null 2020-12-05 19:51:49 +02:00
viliusle
274a8f46eb removed color 2 alpha (deprecated, not useful), "replace color" should be used instead. 2020-12-05 19:22:25 +02:00
acer
2a67ea7782 Merge branch 'master' into feature/rework-undo 2020-12-05 11:52:11 -05:00
Vilius
32f9116025
Merge pull request #209 from Giwayume/feature/rectangle-toolsnap
Pixel Snap Rectangle Tool
2020-12-05 18:20:30 +02:00
viliusle
007ada9840 fixed popup range slider, code format 2020-12-05 17:55:32 +02:00
viliusle
8eff466afa added missing shortcuts to menu 2020-12-05 17:40:28 +02:00
acer
956bd5eca6 Fix radius offset nearest pixel 2020-12-05 00:20:58 -05:00
acer
f3e709460f Rectangle sizing 2020-12-04 22:28:29 -05:00
acer
82078d75d5 Fix rotation angle 2020-12-04 19:07:26 -05:00
acer
3f18c0b575 Fix rotate 2020-12-04 19:06:11 -05:00
acer
51e8d8254d Alt color option 2020-12-04 18:53:20 -05:00
acer
a37ea5af90 Try circles on the outside 2020-12-04 18:23:16 -05:00
acer
0a6d3fe874 Start undo work 2020-12-04 17:52:02 -05:00
viliusle
c92478e3f3 multi-touch brush 2020-12-04 23:50:20 +02:00
viliusle
c21791af74 GUI changes: dont render canvas border during load, remove background gradient. 2020-12-04 23:24:45 +02:00
viliusle
1ffb49205c GUI fixes for mobile (based on test on real mobile android device) 2020-12-04 22:34:42 +02:00
acer
0a68963701 Restyle inner handles to always contrast 2020-12-02 23:30:49 -05:00
acer
dc29a6793b Restyle selection to make it work easier with text and smaller layers 2020-12-02 23:15:47 -05:00
viliusle
d3c26b3dea sidebar style fix on mobile 2020-12-02 09:21:27 +02:00
viliusle
fcf53cf71a dragable popup dialog 2020-12-02 00:39:20 +02:00
viliusle
5a872d7f37 updated menus (added ellipsis to some items) 2020-12-01 23:56:15 +02:00
viliusle
eaa38ecd66 popup style improvements on mobile, code cleanup 2020-12-01 23:55:46 +02:00
viliusle
aeadafd7b1 line improvements, better accuracy, ability to draw multiline without gaps 2020-12-01 14:58:32 +02:00
viliusle
8c09fb03b6 loading fix for text tools 2020-12-01 14:38:10 +02:00
viliusle
e3d3d0d3a4 touch support for tools 2020-12-01 14:37:41 +02:00
viliusle
81af357a85 fill/wand tools fix for touch screens 2020-12-01 00:19:24 +02:00
viliusle
451bf8836e erase tool fix for touch events 2020-11-30 23:46:32 +02:00
viliusle
ec7788f963 color picker fix 2020-11-30 21:32:45 +02:00
Vilius
612590da3b
Merge pull request #203 from Giwayume/feature/color-dialog
Color picker dialog
2020-11-30 21:30:12 +02:00
acer
c967d12610 Make color picker work in layer details 2020-11-29 22:07:07 -05:00
acer
9cfb873788 Merge branch 'master' into feature/color-dialog 2020-11-29 20:43:00 -05:00
acer
b482cd9451 Add color picker popup 2020-11-29 20:42:32 -05:00
viliusle
e9144e2ad3 reverting Docker files PR (id=200) 2020-11-30 00:40:01 +02:00
viliusle
6157737c56 ability to have live filters without chaning core code 2020-11-30 00:22:37 +02:00
viliusle
7fd7731210 color picker improvements - copy color to clipboard 2020-11-29 22:53:29 +02:00
viliusle
061092e700 #199 - fix for no undoing some actions on cancel in modal window 2020-11-29 22:17:23 +02:00
Vilius
62ed40f4b7
Merge pull request #200 from PootisPenserHere/master
Basic Dockerfile
2020-11-29 22:09:32 +02:00
viliusle
5ee41f6476 test json update (text line height) 2020-11-29 22:07:53 +02:00
Vilius
94f9e0f047
Merge pull request #198 from Giwayume/feature/inline-text-editing
Text tool - Add leading and detect kerning from font
2020-11-29 22:03:33 +02:00
viliusle
97ab719c98 #201 - gradient fix 2020-11-29 21:54:53 +02:00
Jose Pablo Domingo Aramburo Sanchez
8d75a80ac6
[add] Basic Dockerfile
Still needs some work to load the favicon
2020-11-28 23:56:16 -07:00
acer
8529b1de13 Regression: allow negative width/height on line and gradient tool 2020-11-29 00:41:06 -05:00
acer
893c0d8730 Fix stroke width shouldnt be affected by strikethrough 2020-11-28 23:45:27 -05:00
acer
746b8cf090 Add leading and detect kerning from font 2020-11-28 19:48:44 -05:00
viliusle
3716709a9b popup lib small fix 2020-11-28 22:52:47 +02:00
viliusle
99a5ea33d1 save current color after reload 2020-11-28 22:43:44 +02:00
viliusle
accab50355 removed modal popup for effects without parameters 2020-11-28 22:33:58 +02:00
viliusle
dfd44bbf2b file/search moved to tools/media 2020-11-28 22:15:02 +02:00
viliusle
5a6e2e2e7f Instagram filters, effect browser. 2020-11-28 22:14:40 +02:00
Vilius
6e2594977e
Merge pull request #197 from Giwayume/feature/inline-text-editing
Backwards compatibility align format
2020-11-24 21:57:05 +02:00
acer
f23e4efcc8 Fix text line centering when space causes wrap 2020-11-23 21:58:30 -05:00
acer
ea053f46b3 Backwards compatibility align format 2020-11-23 20:36:35 -05:00
Vilius
23273aed80
Merge pull request #196 from Giwayume/feature/inline-text-editing
Fix icon button with image vertical align
2020-11-23 21:47:33 +02:00
acer
d5d27dceb9 Fix icon button with image vertical align 2020-11-23 13:43:55 -05:00
viliusle
4448ca8703 show error if image could not be loaded 2020-11-22 20:07:41 +02:00
viliusle
ee3caad3a2 ability to undo CSS effect removal 2020-11-22 18:23:11 +02:00
viliusle
78957f049a magic wand tool renamed to magic eraser tool 2020-11-22 18:17:27 +02:00
viliusle
e6de758c33 small changes: readme update, fixed save bug, hide AVIF save, until it will work. 2020-11-22 18:11:57 +02:00
viliusle
08d6447046 version update 2020-11-22 17:45:32 +02:00
viliusle
5477a3996f #194 - updated test template (file > open > test template) with text types 2020-11-22 17:39:02 +02:00
viliusle
c01d988b21 #194 - fixed opening old text layers 2020-11-22 16:55:07 +02:00
viliusle
6d3ae4faa3 #194 - config.js cleanup - moved icons to images/ folder 2020-11-22 16:53:47 +02:00
Vilius
b817035e39
Merge pull request #194 from Giwayume/feature/inline-text-editing
Feature/inline text editing
2020-11-22 16:02:56 +02:00
acer
16f9e23465 Toggle button style 2020-11-20 23:13:04 -05:00
acer
f6d0f8dcb1 Remove serve script 2020-11-19 16:20:49 -05:00
acer
d86ab7c62a Convert whitespace to tab indentation 2020-11-19 13:00:04 -05:00
acer
d938690740 Fix old format conversion 2020-11-19 12:34:58 -05:00
acer
2521b9c37d Merge from master 2020-11-19 12:27:27 -05:00
acer
5e424d4f77 Add todo list 2020-11-19 12:18:57 -05:00
acer
f596833a30 Fix number input scrolling when non-integer step 2020-11-19 12:13:29 -05:00
acer
7b1338c580 Implement layer details 2020-11-19 02:36:36 -05:00
acer
ca69919c26 Add more keyboard controls 2020-11-16 23:26:38 -05:00
acer
18b4e52aab Remember meta when placing cursor after changing params 2020-11-16 02:52:37 -05:00
acer
e0ba72c033 Set/get meta working 2020-11-16 01:47:01 -05:00
viliusle
f8c48784ad AVIF support (future image format, currently not supported by browsers yet) 2020-11-14 23:14:07 +02:00
viliusle
6bc8bb2836 version 4.3.1 2020-11-14 21:49:22 +02:00
viliusle
800003347b example with imprt/export JSON 2020-11-07 21:16:16 +02:00
viliusle
f9408070fe #185 - 3rd parameter "is_preview" to render function 2020-11-07 20:44:17 +02:00
viliusle
b5db71661a 3rd parameter "is_preview" to render function 2020-11-07 20:41:46 +02:00
viliusle
3280a30614 #188 - zoom/position bugfix for File->new 2020-11-07 20:26:40 +02:00
viliusle
88730c6f75 core code improvements 2020-11-07 20:08:59 +02:00
acer
56377c00b2 Only fix selection aspect ratio on images 2020-11-07 00:35:09 -05:00
acer
14c7b9e8e0 Get text typing working 2020-11-07 00:17:06 -05:00
acer
77ac72d7e5 D 2020-11-05 22:01:37 -05:00
viliusle
a796994c2e #188 - fixed CSS effect on different zoom. 2020-11-05 23:52:48 +02:00
viliusle
837c2f4d6b dont allow to save media tool. 2020-11-05 22:05:57 +02:00
acer
90037ded9d Add text selection via mouse 2020-11-05 03:08:53 -05:00
viliusle
31a9210162 4.3.0 version - fixed missing SVG, fixed .gitignore 2020-11-01 20:00:43 +02:00
viliusle
2b2d09bfcc 4.2.6 version 2020-11-01 19:49:42 +02:00
viliusle
dc9fd09c2f #187 svg icons 2020-11-01 19:26:15 +02:00
viliusle
36a89a3ae6 minified dist files 2020-10-25 22:25:38 +02:00
viliusle
8e753d7a30 fixed textarea color on modal dialog (for example add text layer) 2020-10-25 13:57:18 +02:00
viliusle
91990f5ef2 improved test JSON template (minimized content, updated structure, added brush with pressure sample, pencil wihtout antialiasing) 2020-10-25 13:50:21 +02:00
viliusle
b6408e9295 ability to select pencil, brush, borders, 2020-10-25 13:47:16 +02:00
Vilius
d72c9a2336
Merge pull request #184 from Giwayume/feature/line-stabiliser-fix-for-pen
Fix for pen pressure render after line smoothing implemented
2020-10-23 21:30:45 +03:00
Vilius
64fc122760
Merge pull request #183 from Giwayume/feature/fix-spin-button
Fix bug in spinner css
2020-10-23 21:06:04 +03:00
giwayume
dea1eeed59 Convert indentation to tabs 2020-10-22 18:00:26 -04:00
giwayume
66e101a33a Fix for pen pressure drawing 2020-10-22 17:55:13 -04:00
giwayume
c609c701e7 Fix bug in spinner css 2020-10-22 17:45:01 -04:00
viliusle
b40f82dc9b color inputs fix 2020-10-22 23:46:32 +03:00
Vilius
324d94d035
Merge pull request #181 from Giwayume/feature/color-improvements
Feature/color improvements
2020-10-22 23:42:37 +03:00
viliusle
40569c8c71 #143 - line stabiliser for brush 2020-10-22 22:59:15 +03:00
acer
dae792cc35 comment out host 2020-10-22 03:07:43 -04:00
acer
f1c3c93064 Rename missed helper functions 2020-10-22 03:04:37 -04:00
acer
4db10f1e5a Fix color picker, renamed functions 2020-10-22 02:47:41 -04:00
acer
42aa88fabd Move aria labelledby to input on number input 2020-10-22 02:41:20 -04:00
acer
f8cfdf6ab6 Add color swatches 2020-10-22 02:07:24 -04:00
viliusle
bb002c70dc Merge branch 'master' of https://github.com/viliusle/miniPaint into master 2020-10-21 12:51:28 +03:00
Vilius
46232e3f1e
Merge pull request #180 from Giwayume/feature/pen-pressure
Add pen presure to brush
2020-10-21 12:51:07 +03:00
acer
978f355dcf Explain why 0.5 2020-10-20 21:10:33 -04:00
acer
f2f973b157 Add pen presure to brush 2020-10-20 21:02:08 -04:00
Giwayume
48567464fc
Merge pull request #6 from viliusle/master
Backfill
2020-10-20 18:22:42 -04:00
acer
ee4731cb09 Implement section hiding 2020-10-20 18:21:23 -04:00
viliusle
3dc2620589 borders layer selection 2020-10-20 23:50:59 +03:00
viliusle
d8dca59255 #179 - pressure test code (not activated) 2020-10-20 23:00:53 +03:00
acer
6c984cc2d7 Coded gradient pickers 2020-10-19 02:44:42 -04:00
Giwayume
70553a1aaa
Merge pull request #5 from viliusle/master
Backfill
2020-10-17 23:27:27 -04:00
viliusle
a787cb748c version update to 4.2.5 2020-10-17 23:51:21 +03:00
viliusle
cc0ed4762a CSS fix for help > about > name 2020-10-17 23:50:32 +03:00
viliusle
597064a18f CSS changes (simplified logo hover) 2020-10-17 23:36:50 +03:00
Vilius
3ce06e1cac
Merge pull request #177 from Giwayume/feature/dark-theme-color-contrast
Make dark theme higher contrast
2020-10-17 22:57:37 +03:00
viliusle
1e818bb3de #178 logo link fix 2020-10-14 21:29:53 +03:00
acer
9e0d116af8 Fix external link icon missing in dark theme 2020-10-14 01:46:21 -04:00
acer
9ac7ae1330 Match menu hover color to active color 2020-10-14 00:52:44 -04:00
acer
481f1d853e Make dark theme higher contrast 2020-10-14 00:48:42 -04:00
Giwayume
833f6282b5
Merge pull request #4 from viliusle/master
Backfill
2020-10-13 21:47:30 -04:00
viliusle
2019fca31d center canvas if it is much smaller than screen. 2020-10-13 23:53:39 +03:00
viliusle
6057c8a437 fixed ability to focus main menu 2020-10-13 23:29:23 +03:00
viliusle
0282138e58 updated browser support, removed IE11 2020-10-13 23:28:18 +03:00
Vilius
57ed526b22
Merge pull request #175 from Giwayume/feature/mobile-friendly-main-menu
Rewrite menu from scratch to support mobile sized screens and keyboard controls
2020-10-13 23:26:12 +03:00
acer
4ac667b336 Remove tagged convert to raster verbiage 2020-10-12 02:30:51 -04:00
acer
91657a924a Make translations work with new menu, update verbiage 2020-10-12 02:27:50 -04:00
acer
0a00993580 Remove remaining ddsmoothmenu references 2020-10-12 01:57:06 -04:00
acer
bedc3f579a Add home/end key control 2020-10-12 01:42:17 -04:00
acer
20dadfb75f Resolve merge conflict with master 2020-10-12 01:26:48 -04:00
Giwayume
a9ad8c783c
Merge pull request #3 from viliusle/master
Upstream
2020-10-12 01:25:04 -04:00
acer
fb91088a7e Handle tab in dropdown item 2020-10-12 01:23:24 -04:00
acer
a5b84b9d0f Rewrite menu from scratch to support mobile screen sizes and keyboard controls 2020-10-12 01:17:56 -04:00
viliusle
5ce675c5b3 left tools scroll on mobile, menu styles 2020-10-11 23:30:39 +03:00
viliusle
aa7ce82940 additional menu fix 2020-10-11 23:13:38 +03:00
viliusle
5dfa5ee4c6 menu weird bug temp fix 2020-10-11 23:00:39 +03:00
Vilius
77b80265ac
Merge pull request #173 from Giwayume/feature/mobile-popups
Fix sizing/positioning issues with popups on small screens
2020-10-11 22:42:16 +03:00
www.viliusl@gmail.com
49bfae9d3d effects list improvements 2020-10-11 22:25:52 +03:00
acer
6b3a102051 Make popup sizing responsive on small screens 2020-10-11 15:14:29 -04:00
Giwayume
bfb85aa8e5
Merge pull request #2 from viliusle/master
Upstream
2020-10-11 15:11:30 -04:00
www.viliusl@gmail.com
780b0f87b8 #166 - additional links 2020-10-11 22:03:18 +03:00
www.viliusl@gmail.com
5ddd3202a2 fixed small issues after PR (GUI improvements) 2020-10-11 21:39:14 +03:00
Giwayume
59f7310356
Merge pull request #1 from viliusle/master
update
2020-10-11 14:25:25 -04:00
www.viliusl@gmail.com
73624be3f2 npm audit 2020-10-11 16:04:54 +03:00
Vilius
4fd65f7beb
Merge pull request #171 from Giwayume/feature/mobile-compatibility
Adjust CSS to be more flexible on mobile devices and small windows
2020-10-11 15:09:56 +03:00
acer
ed8105a604 Wrong grid row for right sidebar on ms 2020-10-11 02:18:08 -04:00
acer
a363ceb5ac Adjust CSS to be more flexible on mobile devices and small windows 2020-10-11 02:05:00 -04:00
Vilius
947d5f151b git audit 2020-09-13 21:05:54 +03:00
Vilius
ff0b800527
Merge pull request #164 from fishergisdldt/patch-4
Update gui-details.js
2020-08-23 16:10:30 +03:00
fishergisdldt
f610662539
Update gui-details.js
some element has not translated
2020-08-21 10:48:28 +08:00
Vilius
9acb8788f3
Merge pull request #160 from fishergisdldt/patch-1
Update zh.json
2020-08-10 20:56:07 +03:00
fishergisdldt
f5461c6d33
Update zh.json
the chinese are not accurate
2020-08-10 14:40:01 +08:00
Vilius
0c0640bda8 libs update 2020-07-05 17:53:09 +03:00
Vilius
473bb25455 #157 - CORS fix 2020-07-05 17:51:14 +03:00
Vilius
c4d07556a5 npm audit 2020-04-08 22:19:41 +03:00
Vilius
879e2d4063 #153 - https://pixabay.com image library fix 2020-04-08 22:06:08 +03:00
Vilius
726502b446 added warning if trying to crop rotated layers (not supported) 2019-10-22 23:31:46 +03:00
Vilius
e193769b36 #144 - when changing 1 of HSL values, others should not be changed (fix) 2019-10-22 23:13:01 +03:00
Vilius
4cd3455591 fix: undo should not reset color 2019-10-22 22:47:33 +03:00
Vilius
db1fe400f8 undo color fix 2019-10-22 22:40:01 +03:00
Vilius
95ab2ed7ea npm update 2019-09-17 16:22:49 +03:00
Vilius
4e49179d0a npm update (fixed vulnerabilities) 2019-06-22 21:13:11 +03:00
Vilius
97f6c2f83b npm update 2019-05-02 22:37:01 +03:00
Vilius
d86f2a5502 #139 - fixed colorpicker 2019-04-22 22:36:18 +03:00
Vilius
b23601527d grammar fixes 2019-04-08 00:21:49 +03:00
Vilius
b766caf185 version update: 4.2.0 2019-03-31 18:41:13 +03:00
Vilius
8a15590907 better color picker 2019-03-31 18:38:15 +03:00
Vilius
da485e7ac9 #130 disabled some actions on SVG layers 2019-03-31 17:41:38 +03:00
Vilius
7d3a4b15da fix for: imported svg are marked as vectors 2019-03-31 17:39:18 +03:00
Vilius
2baa17b31b images can be converted to raster (rotated example) 2019-03-31 17:33:13 +03:00
Vilius
8a5692642b resize can be done on images, text and vectors 2019-03-31 17:30:32 +03:00
Vilius
3336c95791 imported svg are marked as vectors 2019-03-31 17:29:54 +03:00
Vilius
7db2e3630e radial gradients are vectors 2019-03-31 17:28:30 +03:00
Vilius
61f06f8232 text bugfix 2019-03-31 17:27:39 +03:00
Vilius
6ce6267133 updated test image (some layers are marked as vectors) 2019-03-31 17:16:24 +03:00
Vilius
21189ca797 #99 - google fonts 2019-03-31 16:29:34 +03:00
Vilius
353c6f6276 tabs support in text 2019-03-30 22:20:51 +02:00
Vilius
b88329d583 draw selected object borders, unless its starts from top-left corner and ends in bottom-right corner. 2019-03-30 22:17:27 +02:00
Vilius
67d279c858 #91 - text wrap 2019-03-26 00:26:45 +02:00
Vilius
c3d7126380 updated save method - layers with negative width/height can be saved as separate layer 2019-03-25 22:44:02 +02:00
Vilius
b777dadd52 fixed selction with low opacity from last layer 2019-03-25 22:02:25 +02:00
Vilius
4fc75e09f5 resize update 2019-03-25 00:32:01 +02:00
Vilius
45f39f92dc ability to save multiple files, better save dialog 2019-03-24 20:34:16 +02:00
Vilius
260a008c42 popup lib fix 2019-03-24 19:24:39 +02:00
Vilius
09ffe60e38 resize update, Lanczos by default (best quality) 2019-03-24 18:42:13 +02:00
Vilius
4a2e438102 #132 - maintain aspect ratio on resize 2019-02-19 23:45:50 +02:00
Vilius
0c34d0a385 #134 - json support in auto-open 2019-02-10 22:16:43 +02:00
Vilius
9c18709c27 #123 - two columns on the left sidebar, if windows height is small 2019-02-03 19:52:39 +02:00
Vilius
af14e89640 122 - ability to start app in other language, by adding "?lang=fr" to URL 2019-02-03 18:29:15 +02:00
Vilius
ec830c6ad8 close icon on popup dialog, grammar fix 2019-02-03 18:05:12 +02:00
Vilius
e9bff70fde fixed bug - webcam cancel 2019-02-03 17:46:04 +02:00
Vilius
c168533065 external compress link on tools 2019-02-03 17:36:59 +02:00
Vilius
645fef54bb npm update 2019-02-03 14:28:48 +02:00
Vilius
1210b1841a version update 2018-10-20 20:35:32 +03:00
Vilius
d09eb1ea5a fixed search with ctrl+f not working, also similar shortcuts. 2018-10-20 20:16:10 +03:00
Vilius
1400f2e7f7 replaced http urls to https 2018-08-17 14:23:04 +03:00
Vilius
bc3f07288a test image url fix 2018-08-16 22:51:24 +03:00
Vilius
3aa3ccf337 vulnerabilities fix, old dependencies cleanup 2018-08-16 20:20:31 +03:00
Vilius
a791130bcf version fix, build 2018-08-16 20:08:06 +03:00
Vilius
2c73dd5d76 anti-aliasing improvements on fill and magic wand tools 2018-07-29 23:28:14 +03:00
Vilius
b7448b0b89 crop update - on CTRL key, it will keep global ratio 2018-07-29 23:11:26 +03:00
Vilius
dd3b48836b open image from webcam 2018-07-28 22:51:05 +03:00
Vilius
7e240e1be0 version update - 4.1.0 2018-07-27 22:15:42 +03:00
Vilius
1ed0fa8f0e blueprint effect 2018-07-27 22:14:18 +03:00
Vilius
bfcd4cb0db night vision effect 2018-07-27 20:14:44 +03:00
Vilius
02288b3e4d pencil effect 2018-07-27 19:50:42 +03:00
Vilius
f989ba8b99 duplicate update - offset + 10 2018-07-27 17:50:42 +03:00
Vilius
845ee4ac61 rounded rectangles 2018-07-27 17:38:24 +03:00
Vilius
66f9df4ff5 bugfix - pencil, brush and undo 2018-07-27 17:36:11 +03:00
Vilius
92f1586200 test template (file > open) 2018-07-27 15:48:03 +03:00
Vilius
bae1ef1292 ability to change #1 color change for gradient 2018-07-27 14:10:59 +03:00
Vilius
af95ace5dd added new layer attribute - is_vector (bool) 2018-07-27 13:19:43 +03:00
Vilius
3e74aafb95 hsl update - user should see 0-360, 0-100, 0-100 values, not 0-255 2018-07-23 22:52:14 +03:00
Vilius
a1d0b23ad4 themes update - layers visibility icon fix 2018-07-23 20:24:05 +03:00
Vilius
e866b3dcb3 themes update - menu, alertify colors 2018-07-23 20:12:31 +03:00
Vilius
7dac8c1272 themes support 2018-07-23 17:47:37 +03:00
Vilius
048e423b03 flatten layers bug - sort was not working. 2018-07-18 20:39:19 +03:00
Vilius
ae5c5db10e color picker icon update 2018-07-18 20:29:07 +03:00
Vilius
d9aadf1115 allow pencil to have opacity in sharp mode 2018-07-18 20:13:14 +03:00
Vilius
8fbe31d0fe webpack update to 4 version, build update. IMPORTANT - please check https://github.com/viliusle/miniPaint/wiki/Build-instructions how to build. 2018-06-18 00:45:26 +03:00
Vilius
1b9bd8e010
Merge pull request #102 from Bartheyrman22/master
Fix: Touch scrolling and image rendering.
2018-05-14 21:43:03 +03:00
Bart Heyrman
ab4aecdae9 Merge branch 'viliusle-master' into new-master
# Conflicts:
#	src/js/core/base-tools.js
2018-05-14 16:15:41 +02:00
Bart Heyrman
b30d4aab68 Change spaces into tabs. 2018-05-14 16:01:01 +02:00
Bart Heyrman
9695207702 Fix: Image was not rendered after cloneNode-image load.
This happened when inserting a layer of type 'image'.
2018-05-14 15:34:35 +02:00
Bart Heyrman
28bcb5e507 Fix: Prevent scrolling on newer browsers where passive-mode for touch is enabled by default. 2018-05-14 13:53:31 +02:00
Vilius
ea88fe4d11 code reformat after pull request. 2018-05-10 23:56:56 +03:00
Vilius
b082102b20 Merge branch 'Bartheyrman22-master' 2018-05-10 23:53:16 +03:00
Vilius
2d817c3b79 Merge branch 'master' of git://github.com/Bartheyrman22/miniPaint into Bartheyrman22-master 2018-05-10 23:49:02 +03:00
Vilius
aee84806bf German language update (contributed by Paul H.) 2018-05-10 23:21:35 +03:00
Vilius
6b7d1002d0 resize with aspect ratio 2018-05-10 23:02:09 +03:00
Bart Heyrman
cc3662a76f Implement touch support for tools. 2018-05-07 16:24:00 +02:00
Bart Heyrman
25fb1ecde4 Prevent scrolling while dragging on canvas on touch device. 2018-05-07 16:23:25 +02:00
Bart Heyrman
022299de23 #98 - Support mobile touch events (base implementation) 2018-04-28 16:45:50 +02:00
Vilius
f736445b3a zoom demo, helping functions: zoom_to_position(), set_size(), get_visible_area_size() 2018-02-07 22:40:42 +02:00
Vilius
0326654d8b #87 - Layers.insert can be async (example in /examples/add-edit-imgData.html),
better error messages
2018-02-02 22:07:37 +02:00
Vilius
80869ed818 npm update 2018-01-30 21:51:09 +02:00
Vilius
9b41a81057
license update 2018-01-18 12:19:02 +02:00
Vilius
0d75cc08a0 #77 - example with edit image on page load without clicking. (still need to uncomment line 75 to enable it.) 2018-01-06 16:17:38 +02:00
Vilius
5f7a91d797 documentation update 2017-12-29 22:21:23 +02:00
Vilius
bc5657c88d documentation, added wiki - https://github.com/viliusle/miniPaint/wiki 2017-12-29 18:14:16 +02:00
Vilius
844a2295d7 devDependencies update 2017-12-29 15:19:08 +02:00
Vilius
f7184bf453 button styles for mac 2017-12-06 22:39:37 +02:00
Vilius
e926711645 fix for composition with destination out save as jpg 2017-12-05 21:30:03 +02:00
Vilius
2a489c43f3 #71 all include paths now are relative 2017-12-05 21:10:13 +02:00
Vilius
93cf774cfd fixed version in about, documentation update 2017-12-05 20:35:45 +02:00
302 changed files with 41424 additions and 14801 deletions

8
.babelrc Normal file
View File

@ -0,0 +1,8 @@
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-transform-runtime", {
"regenerator": true
}]
]
}

4
.gitignore vendored
View File

@ -3,13 +3,15 @@
.DS_Store?
._*
.Trashes
Icon?
ehthumbs.db
Thumbs.db
nbproject/
.idea/
.git/
.vscode
/.project
*.log
/node_modules/
*.js.ignore

View File

@ -1,13 +1,11 @@
# miniPaint
Online graphics editing tool lets create, edit images using HTML5 technologies.
No need to buy, download, install or have obsolete flash.
Key features: layers, drag & drop, transparency, filters, no-flash, open source.
Online image editor lets you create and edit images using HTML5 technologies. No need to buy, download, install, or have outdated flash. No ads. Key features: layers, filters, open source Photoshop alternative.
miniPaint operates directly in the browser. You can create images, paste from clipboard (ctrl+v) or upload from computer (using menu or drag & drop). Nothing will be sent to any server. Everything stays in your browser.
miniPaint operates directly in the browser. You can create images by pasting from the clipboard (ctrl+v) or uploading from the computer (_using menu or drag & drop_). Nothing will be sent to any server. Everything stays in your browser.
## URL:
**http://viliusle.github.io/miniPaint/**
**https://viliusle.github.io/miniPaint/**
## Preview:
![miniPaint](https://raw.githubusercontent.com/viliusle/miniPaint/master/images/preview.gif)
@ -16,42 +14,47 @@ miniPaint operates directly in the browser. You can create images, paste from cl
**Change log:** [/miniPaint/releases](https://github.com/viliusle/miniPaint/releases)
## Browser Support
- Firefox
- Chrome
- Firefox
- Opera
- Edge
- Safari
- IE 11 (?)
- Yandex
## Features
- **Files**: open images, directories, URL, drag and drop, save (PNG, JPG, BMP, WEBP, animated GIF, JSON (layers data), print.
- **Edit**: Undo, cut, copy, paste, selection, paste from clipboard.
- **Image**: information, EXIF, trim, zoom, resize (Hermite resample, default resize), rotate, flip, color corrections (brightness, contrast, hue, saturation, luminance), auto adjust colors, grid, histogram, negative.
- **Layers**: multiple layers system, differences, merge, flatten, Transparency support.
- **Effects**: Black and White, Blur (box, Gaussian, stack, zoom), Bulge/Pinch, Denoise, Desaturate, Dither, Dot Screen, Edge, Emboss, Enrich, Gamma, Grains, GrayScale, Heatmap, JPG Compression, Mosaic, Oil, Sepia, Sharpen, Solarize, Tilt Shift, Vignette, Vibrance, Vintage,
- **Tools**: pencil, brush, magic wand, erase, fill, color picker, letters, crop, blur, sharpen, desaturate, clone, borders, sprites, key-points, color to alpha, color zoom, replace color, restore alpha, content fill.
- **Help**: keyboard shortcuts, translations.
**Files**: open images, directories, URLs, data URLs, drag and drop, save (PNG, JPG, BMP, WEBP, animated GIF, TIFF, JSON (layers data), print.
### Embed
**Edit**: undo, cut, copy, paste, selection, paste from the clipboard.
To embed this app in other page, use this HTML code:
**Image**: information, EXIF, trim, zoom, resize (Hermite resample, default resize), rotate, flip, color corrections (brightness, contrast, hue, saturation, luminance), automatic color adjustment, grid, histogram, negative.
<iframe style="width:100%; height:35vw;" src="https://viliusle.github.io/miniPaint/"></iframe>
**Layers**: multi-layer system, differences, merging, flattening, transparency support.
**Effects**: black and white, blur (box, gaussian, stack, zoom), bulge/pinch, denoise, desaturation, dither, dot screen, edge, emboss, enrich, gamma, grains, grayscale, heatmap, jpg compression, mosaic, oil, sepia, sharpen, solarize, tilt shift, vignette, vibrance, vintage, blueprint, night vision, pencil, also instagram filters: 1977, aden, clarendon, gingham, inkwell, lo-fi, toaster, valencia, x-pro ii.
**Tools**: pencil, brush, magic wand, eraser, fill, color picker, letter, crop, blur, sharpener, desaturation, clone, borders, sprites, keypoints, color zoom, change color, restore transparency, content fill.
**Help**: keyboard shortcuts, translation.
## Embed
To embed this app on another page, use the following HTML code:
<iframe style="box-sizing:border-box; width:100%; height:100vh;" id="miniPaint" src="https://viliusle.github.io/miniPaint/" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
## Build instructions
See [Wiki > Build instructions](https://github.com/viliusle/miniPaint/wiki/Build-instructions)
- git clone https://github.com/viliusle/miniPaint.git
- cd [miniPaint directory]
- npm install
- webpack-dev-server (using http://localhost:8080/ with live reload, require: npm install -g webpack-dev-server)
- edit files...
- webpack -p (build for production)
## Wiki
See [Wiki](https://github.com/viliusle/miniPaint/wiki)
### License
## Contributors
<a align="center" href="https://github.com/viliusle/miniPaint/graphs/contributors">
<img src="https://contrib.rocks/image?repo=viliusle/miniPaint" />
</a>
## License
MIT License
## Support
Please use the GitHub issues for support, features, issues or use mail www.viliusl@gmail.com for contacts.
Please use the GitHub issues for support, feature requests and bug reports, or contact us by sending an email to www.viliusl@gmail.com.

15
SECURITY.md Normal file
View File

@ -0,0 +1,15 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| latest | :white_check_mark: |
| < latest | :x: |
## Reporting a Vulnerability
Please send details to www.viliusl@gmail.com

63
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

47
dist/bundle.js.LICENSE.txt vendored Normal file
View File

@ -0,0 +1,47 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*!
pica
https://github.com/nodeca/pica
*/
/*!
* Block below copied from Protovis: http://mbostock.github.com/protovis/
* Copyright 2010 Stanford Visualization Group
* Licensed under the BSD License: http://www.opensource.org/licenses/bsd-license.php
* @license
*/
/*!
* jQuery JavaScript Library v3.7.1
* https://jquery.com/
*
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2023-08-28T13:37Z
*/
/*!
* quantize.js Copyright 2008 Nick Rabinowitz.
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
* @license
*/
/*! alertifyjs - v1.13.1 - Mohammad Younes <Mohammad@alertifyjs.com> (http://alertifyjs.com) */
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* hermite-resize - Canvas image resize/resample using Hermite filter with JavaScript.
* @version v2.2.10
* @link https://github.com/viliusle/miniPaint
* @license MIT
*/

2
dist/bundle.js.map vendored
View File

@ -1 +1 @@
{"version":3,"file":"dist/bundle.js","sources":["webpack:///dist/bundle.js"],"mappings":"AAAA;AAwsCA;;;;;;;;;;;;;AAqjJA;;;;;;;;;;AAuhBA;;;;;;;;;;;;;;;;;;AA8xyBA;;;;;;;;;;;AAyKA;;;;;;AA2uBA","sourceRoot":""}
{"version":3,"file":"bundle.js","sources":["webpack://miniPaint/bundle.js"],"mappings":";AAAA","sourceRoot":""}

View File

@ -0,0 +1,76 @@
<html>
<body style="margin:0;">
<iframe id="myFrame" style="width:100%;height:100vh;border:0;" src="../" allow="camera"></iframe>
<script>
window.addEventListener('load', function (e) {
draw_various();
}, false);
async function draw_various() {
var Layers = document.getElementById('myFrame').contentWindow.Layers;
//add layer
var canvas = document.createElement('canvas');
canvas.width = 50;
canvas.height = 50;
var ctx = canvas.getContext("2d");
cross_X(ctx, 25, 25);
var params = {
type: 'image',
data: canvas.toDataURL("image/png"),
x: 50,
y: 50,
width: canvas.width,
height: canvas.height,
};
await Layers.insert(params);
//add new layer
var canvas = document.createElement('canvas');
canvas.width = 400;
canvas.height = 400;
var ctx = canvas.getContext("2d");
cross_X(ctx, 200, 200, null, '#00cc00');
var params = {
type: 'image',
data: canvas.toDataURL("image/png"),
width: canvas.width,
height: canvas.height,
};
await Layers.insert(params);
//update last layer
var canvas = Layers.convert_layer_to_canvas(null, true); //no trim
var ctx = canvas.getContext("2d");
cross_X(ctx, 300, 300, null, '#00cc00');
Layers.update_layer_image(canvas);
//also update layer
var link = Layers.get_layer();
link.x = parseInt(canvas.dataset.x);
link.y = parseInt(canvas.dataset.y);
link.width = canvas.width;
link.height = canvas.height;
}
function cross_X(ctx, x, y, size = 20, col = '#ff0000') {
if(size == null)
size = 20;
x = parseFloat(x);
y = parseFloat(y);
size = parseInt(size);
var lw = parseInt(5);
ctx.beginPath();
ctx.moveTo(x - size, y - size);
ctx.lineTo(x + size, y + size);
ctx.lineWidth = lw;
ctx.strokeStyle = col;
ctx.stroke();
ctx.moveTo(x + size, y - size);
ctx.lineTo(x - size, y + size);
ctx.lineWidth = lw;
ctx.strokeStyle = col;
ctx.stroke();
}
</script>

View File

@ -1,16 +1,23 @@
<html>
<body style="margin:0;">
<iframe id="myFrame" style="width:100%;height:70vh;" src="../"></iframe>
<iframe id="myFrame" style="width:100%;height:70vh;border:0;" src="../" allow="camera"></iframe>
<div style="height:20vh;margin:10px;">
Click on image to edit.
<br /><br />
<button onclick="my_update()">Update</button>
<button onclick="my_save()">Save</button>
<button onclick="open_image()">Open image</button>
<button onclick="update_image()">Update image</button>
<button onclick="save_image()">Save image</button>
OR
<button onclick="open_json()">Open JSON</button>
<button onclick="save_json()">Save JSON</button>
<br /><br />
<img style="max-height:100%" id="testImage" alt="" src="../images/logo.png" onclick="open_image(this)" />
<img style="max-height:100%" id="testImage" alt="" src="../images/logo-colors.png" onclick="open_image(this)" />
<textarea rows="8" style="width:500px;" id="testJson"></textarea>
</div>
<script>
@ -20,6 +27,8 @@
* @param {string|image} image image or image id
*/
function open_image(image){
if(image == undefined)
image = document.getElementById('testImage');
if(typeof image == 'string'){
image = document.getElementById(image);
}
@ -37,7 +46,20 @@ function open_image(image){
Layers.insert(new_layer);
}
function my_save(){
function open_json(){
var miniPaint = document.getElementById('myFrame').contentWindow;
var miniPaint_FileOpen = miniPaint.FileOpen;
window.fetch("../images/test-collection.json").then(function(response) {
return response.json();
}).then(function(json) {
miniPaint_FileOpen.load_json(json, false);
}).catch(function(ex) {
alert('Sorry, image could not be loaded.');
});
}
function save_image(){
var Layers = document.getElementById('myFrame').contentWindow.Layers;
var tempCanvas = document.createElement("canvas");
var tempCtx = tempCanvas.getContext("2d");
@ -45,14 +67,32 @@ function my_save(){
tempCanvas.width = dim.width;
tempCanvas.height = dim.height;
Layers.convert_layers_to_canvas(tempCtx);
tempCanvas.toBlob(function(blob) {
//image data here
alert('Data length: ' + blob.size);
console.log(blob);
});
if(is_edge_or_ie() == false){
//update image using blob (faster)
tempCanvas.toBlob(function (blob) {
alert('Data length: ' + blob.size);
console.log(blob);
}, 'image/png');
}
else{
//slow way for IE, Edge
var data = tempCanvas.toDataURL();
alert('Data length: ' + data.length);
console.log(data);
}
}
function my_update(){
function save_json(){
var miniPaint = document.getElementById('myFrame').contentWindow;
var miniPaint_FileSave = miniPaint.FileSave;
var data_json = miniPaint_FileSave.export_as_json();
document.getElementById('testJson').value = data_json;
}
function update_image(){
var target = document.getElementById('testImage');
var Layers = document.getElementById('myFrame').contentWindow.Layers;
@ -67,4 +107,22 @@ function my_update(){
target.height = dim.height;
target.src = tempCanvas.toDataURL();
}
/**
* will auto load image on page load. Uncomment line below to make it work
*/
window.onload = function () {
//open_image(document.getElementById('testImage')); //uncomment me
};
//if IE 11 or Edge
function is_edge_or_ie() {
//ie11
if( !(window.ActiveXObject) && "ActiveXObject" in window )
return true;
//edge
if( navigator.userAgent.indexOf('Edge/') != -1 )
return true;
return false;
}
</script>

71
examples/zoom.html Normal file
View File

@ -0,0 +1,71 @@
<html>
<body style="margin:0;">
<iframe id="myFrame" style="width:100%;height:100vh;border:0;" src="../" allow="camera"></iframe>
<script>
window.addEventListener('load', function (e) {
main();
}, false);
async function main() {
var Layers = document.getElementById('myFrame').contentWindow.Layers;
var config = document.getElementById('myFrame').contentWindow.AppConfig;
var canvas_width = 800;
var canvas_height = 600;
//set size
Layers.Base_gui.set_size(canvas_width, canvas_height);
//add rectangle
this.layer = {
name: 'layer1',
type: 'rectangle',
params: {
fill: true,
square: false,
border_size: 2,
border: false,
border_color: "#1b1bd8",
fill_color: "#1b1bd8"
},
color: '#ff0000',
render_function: ['rectangle', 'render'],
x: canvas_width/2 - 25,
y: canvas_height/2 - 25,
width: 50,
height: 50,
};
await Layers.insert(this.layer);
//zoom to 500%
setTimeout(function () {
Layers.Base_gui.GUI_preview.zoom_to_position(0, 0);
Layers.Base_gui.GUI_preview.zoom(500);
}, 100);
//do this after system changed zoom position
setTimeout(function () {
//move visible area to begin of rectangle
Layers.Base_gui.GUI_preview.zoom_to_position(500, 500); //change zoom position
}, 500);
//action after 1 s - for preview purpose
setTimeout(function () {
//move visible area so rect is in center
var visible_area = Layers.Base_gui.get_visible_area_size();
//center of rect
var cx = canvas_width/2;
var cy = canvas_height/2;
//calc needed coords
var x = cx - visible_area.width / 2;
var y = cy - visible_area.height / 2;
Layers.Base_gui.GUI_preview.zoom_to_position(x, y); //change zoom position
}, 1000);
}
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

After

Width:  |  Height:  |  Size: 4.5 KiB

13
images/favicon.svg Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 298.73 298.73" style="enable-background:new 0 0 298.73 298.73;" xml:space="preserve">
<g>
<path style="fill:#010002;" d="M264.959,9.35H33.787C15.153,9.35,0,24.498,0,43.154v212.461c0,18.634,15.153,33.766,33.787,33.766
h231.171c18.634,0,33.771-15.132,33.771-33.766V43.154C298.73,24.498,283.593,9.35,264.959,9.35z M193.174,59.623
c18.02,0,32.634,14.615,32.634,32.634s-14.615,32.634-32.634,32.634c-18.025,0-32.634-14.615-32.634-32.634
S175.149,59.623,193.174,59.623z M254.363,258.149H149.362H49.039c-9.013,0-13.027-6.521-8.964-14.566l56.006-110.93
c4.058-8.044,11.792-8.762,17.269-1.605l56.316,73.596c5.477,7.158,15.05,7.767,21.386,1.354l13.777-13.951
c6.331-6.413,15.659-5.619,20.826,1.762l35.675,50.959C266.487,252.16,263.376,258.149,254.363,258.149z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30.051 30.051" style="enable-background:new 0 0 30.051 30.051;" xml:space="preserve">
<g>
<path d="M19.982,14.438l-6.24-4.536c-0.229-0.166-0.533-0.191-0.784-0.062c-0.253,0.128-0.411,0.388-0.411,0.669v9.069
c0,0.284,0.158,0.543,0.411,0.671c0.107,0.054,0.224,0.081,0.342,0.081c0.154,0,0.31-0.049,0.442-0.146l6.24-4.532
c0.197-0.145,0.312-0.369,0.312-0.607C20.295,14.803,20.177,14.58,19.982,14.438z"/>
<path d="M15.026,0.002C6.726,0.002,0,6.728,0,15.028c0,8.297,6.726,15.021,15.026,15.021c8.298,0,15.025-6.725,15.025-15.021
C30.052,6.728,23.324,0.002,15.026,0.002z M15.026,27.542c-6.912,0-12.516-5.601-12.516-12.514c0-6.91,5.604-12.518,12.516-12.518
c6.911,0,12.514,5.607,12.514,12.518C27.541,21.941,21.937,27.542,15.026,27.542z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,5 @@
<svg width="124" height="150" viewBox="0 0 124 150" xmlns="http://www.w3.org/2000/svg">
<rect x="55" y="14" width="14" height="63"/>
<rect x="116" width="14" height="61" transform="rotate(90 116 0)"/>
<path d="M62 150L8.30643 75L115.694 75L62 150Z"/>
</svg>

After

Width:  |  Height:  |  Size: 258 B

28
images/icons/blur.svg Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M264.574,4.675C262.697,1.761,259.467,0,256,0c-3.467,0-6.697,1.761-8.574,4.675
c-6.532,10.14-159.966,249.362-159.966,338.784C87.459,436.393,163.066,512,256,512s168.541-75.607,168.541-168.541
C424.541,254.037,271.106,14.815,264.574,4.675z M256,491.602c-81.686,0-148.142-66.456-148.142-148.143
c0-34.037,26.926-101.269,77.865-194.427C213.83,97.626,242.219,51.324,256,29.29c13.77,22.016,42.123,68.259,70.223,119.64
c50.976,93.212,77.92,160.478,77.92,194.529C404.142,425.146,337.686,491.602,256,491.602z"/>
</g>
</g>
<g>
<g>
<path d="M375.907,332.939c-5.633,0-10.199,4.566-10.199,10.199c0,43.197-25.482,82.521-64.919,100.181
c-5.141,2.301-7.442,8.335-5.14,13.476c1.695,3.788,5.416,6.034,9.314,6.034c1.393,0,2.809-0.287,4.163-0.893
c46.764-20.941,76.981-67.572,76.981-118.797C386.106,337.505,381.54,332.939,375.907,332.939z"/>
</g>
</g>
<g>
<g>
<path d="M281.818,460.702c-0.729-5.586-5.85-9.519-11.435-8.791c-4.736,0.619-9.574,0.933-14.383,0.933
c-5.633,0-10.199,4.566-10.199,10.199c0,5.633,4.566,10.199,10.199,10.199c5.69,0,11.419-0.372,17.028-1.106
C278.613,471.407,282.548,466.287,281.818,460.702z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

4
images/icons/bold.svg Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M8.21 13c2.106 0 3.412-1.087 3.412-2.823 0-1.306-.984-2.283-2.324-2.386v-.055a2.176 2.176 0 0 0 1.852-2.14c0-1.51-1.162-2.46-3.014-2.46H3.843V13H8.21zM5.908 4.674h1.696c.963 0 1.517.451 1.517 1.244 0 .834-.629 1.32-1.73 1.32H5.908V4.673zm0 6.788V8.598h1.73c1.217 0 1.88.492 1.88 1.415 0 .943-.643 1.449-1.832 1.449H5.907z"/>
</svg>

After

Width:  |  Height:  |  Size: 491 B

1
images/icons/brush.svg Normal file
View File

@ -0,0 +1 @@
<svg height="443pt" viewBox="0 0 443.06138 443" width="443pt" xmlns="http://www.w3.org/2000/svg"><path d="m431.328125 25.894531-14.136719-14.136719c-8.070312-8.078124-19.210937-12.320312-30.613281-11.6601558-11.402344.6601558-21.976563 6.1640628-29.058594 15.1249998l-117.023437 164.839844c-4.089844 5.761719-10.511719 9.425781-17.554688 10.019531-7.039062.59375-13.984375-1.945312-18.980468-6.941406l-34.234376-34.207031c-9.480468-9.109375-24.46875-9.109375-33.949218 0l-11.296875 11.304687 158.398437 158.398438 11.304688-11.304688c4.527344-4.488281 7.070312-10.597656 7.070312-16.96875 0-6.375-2.542968-12.484375-7.070312-16.972656l-34.222656-34.234375c-4.996094-4.996094-7.535157-11.941406-6.941407-18.980469.59375-7.042969 4.257813-13.464843 10.019531-17.554687l165-117.183594c8.890626-7.109375 14.332032-17.671875 14.960938-29.035156.628906-11.367188-3.617188-22.464844-11.671875-30.507813zm-24 43.808594c-9.375 9.371094-24.570313 9.371094-33.945313 0-9.371093-9.375-9.371093-24.574219 0-33.945313 9.496094-9.0625 24.441407-9.0625 33.9375 0 9.375 9.371094 9.378907 24.570313.007813 33.945313zm0 0"/><path d="m390.351562 44.734375c-3.234374 0-6.152343 1.949219-7.390624 4.9375-1.234376 2.988281-.550782 6.429687 1.734374 8.71875 3.160157 3.03125 8.148438 3.03125 11.304688 0 2.289062-2.289063 2.972656-5.730469 1.734375-8.71875s-4.15625-4.9375-7.390625-4.9375zm0 0"/><path d="m135.792969 420.429688 22.65625 22.65625 113.085937-113.167969-158.398437-158.402344-113.136719 113.121094 22.65625 22.65625 84.847656-84.855469c2.007813-2.078125 4.984375-2.914062 7.78125-2.183594 2.796875.734375 4.980469 2.917969 5.710938 5.714844.734375 2.796875-.101563 5.773438-2.179688 7.78125l-84.847656 84.855469 22.632812 22.625 50.902344-50.90625c3.140625-3.03125 8.128906-2.988281 11.214844.097656s3.128906 8.078125.097656 11.214844l-50.90625 50.921875 22.617188 22.621094 62.214844-62.222657c3.125-3.125 8.191406-3.128906 11.316406-.003906 3.128906 3.125 3.128906 8.191406.003906 11.316406l-62.222656 62.222657 22.625 22.625 73.535156-73.535157c3.140625-3.03125 8.128906-2.988281 11.214844.097657 3.085937 3.085937 3.128906 8.074218.097656 11.214843zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 402.56 402.56" style="enable-background:new 0 0 402.56 402.56;" xml:space="preserve">
<g>
<g>
<polygon points="38.613,234.88 38.4,274.56 96.64,274.56 116.693,265.173 9.6,372.48 39.68,402.56 147.2,295.253 137.813,316.587
137.813,373.76 177.493,374.187 177.493,234.88 "/>
</g>
</g>
<g>
<g>
<polygon points="306.987,128.213 285.653,137.6 392.96,30.08 362.88,0 255.573,107.307 264.96,87.04 264.96,28.8 225.28,29.013
225.28,167.893 364.587,167.893 364.16,128.213 "/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 778 B

21
images/icons/clone.svg Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 540.721 540.721" style="enable-background:new 0 0 540.721 540.721;" xml:space="preserve">
<g>
<g>
<path d="M521.858,465.271H18.862c-7.545,0-12.575,5.03-12.575,12.575v50.3c0,7.545,5.03,12.575,12.575,12.575h502.996
c7.545,0,12.575-5.03,12.575-12.575v-50.3C534.433,470.301,529.403,465.271,521.858,465.271z"/>
<path d="M227.606,98.084c5.03-5.03,20.12-12.575,30.18-12.575c7.545,0,12.575-5.03,12.575-12.575c0-7.545-5.03-10.06-12.575-10.06
l0,0c-17.605,0-37.725,7.545-47.785,17.605c-12.575,10.06-22.635,27.665-22.635,47.785c0,7.545,5.03,10.06,12.575,10.06l0,0
c7.545,0,12.575-2.515,12.575-10.06C212.516,118.204,220.061,103.114,227.606,98.084z"/>
<path d="M18.862,440.121h502.996c5.03,0,7.545-2.515,10.06-5.03c2.515-2.515,2.515-7.545,0-12.575l-47.785-100.599
c0-5.03-5.03-7.545-10.06-7.545H333.235v-77.964c25.15-20.12,60.359-60.36,60.359-110.659C393.594,55.33,338.265,0,270.36,0
S147.126,57.845,147.126,125.749c-2.515,47.785,35.21,88.024,60.36,110.659v77.964H66.647c-5.03,0-10.06,2.515-10.06,7.545
L8.802,422.517c-2.515,5.03-2.515,7.545,0,12.575C11.317,440.121,13.832,440.121,18.862,440.121z M169.761,125.749
c0-55.33,45.27-100.599,98.084-100.599c52.815,0,98.084,45.27,98.084,100.599c0,37.725-27.665,75.449-55.33,93.054
c-2.515,2.515-5.03,5.03-5.03,10.06v123.234c0,2.515-12.575,10.06-22.635,10.06h-37.725c-7.545,0-15.09-7.545-15.09-10.06V228.863
c0-5.03-2.515-7.545-5.03-10.06C207.486,206.228,169.761,168.504,169.761,125.749z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

17
images/icons/crop.svg Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="956.815px" height="956.815px" viewBox="0 0 956.815 956.815" style="enable-background:new 0 0 956.815 956.815;"
xml:space="preserve">
<g>
<path d="M137.621,162.622H20c-11.046,0-20,8.954-20,20v72.919c0,11.046,8.954,20,20,20h117.622L137.621,162.622L137.621,162.622z"
/>
<path d="M774.193,956.815c11.046,0,20-8.954,20-20V819.193H681.274v117.621c0,11.046,8.954,20,20,20L774.193,956.815
L774.193,956.815z"/>
<path d="M794.193,656.275V182.622c0-11.046-8.954-20-20-20H300.54v112.919h380.734v380.734H794.193z"/>
<path d="M936.814,681.275H794.193H681.274H275.54V275.541V162.622V20c0-11.046-8.954-20-20-20h-72.918c-11.046,0-20,8.954-20,20
v142.622v112.919v498.653c0,11.046,8.954,20,20,20h498.653h112.918h142.622c11.045,0,20-8.954,20-20v-72.918
C956.814,690.229,947.86,681.275,936.814,681.275z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

6
images/icons/delete.svg Normal file
View File

@ -0,0 +1,6 @@
<svg height="365pt" viewBox="0 0 365.71733 365" width="365pt" xmlns="http://www.w3.org/2000/svg">
<g fill="#f44336">
<path d="m356.339844 296.347656-286.613282-286.613281c-12.5-12.5-32.765624-12.5-45.246093 0l-15.105469 15.082031c-12.5 12.503906-12.5 32.769532 0 45.25l286.613281 286.613282c12.503907 12.5 32.769531 12.5 45.25 0l15.082031-15.082032c12.523438-12.480468 12.523438-32.75.019532-45.25zm0 0"/>
<path d="m295.988281 9.734375-286.613281 286.613281c-12.5 12.5-12.5 32.769532 0 45.25l15.082031 15.082032c12.503907 12.5 32.769531 12.5 45.25 0l286.632813-286.59375c12.503906-12.5 12.503906-32.765626 0-45.246094l-15.082032-15.082032c-12.5-12.523437-32.765624-12.523437-45.269531-.023437zm0 0"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 719 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><g transform="translate(0.000000,511.000000) scale(0.100000,-0.100000)"><path d="M2646.5,3789.8c-1040.2-119.8-2106-953.5-2445-1917.3l-91.8-260.1L102,355.5c-5.1-1081-2.5-1279.9,33.1-1415c155.5-609.4,578.8-986.7,1282.4-1139.7c300.9-66.3,670.5-96.9,1534.8-127.5c400.3-12.7,831.2-43.3,961.2-63.7c464-76.5,836.3-229.5,1448.1-599.2c698.6-420.7,1063.2-550.7,1682.7-599.2c234.6-17.9,645,20.4,866.9,81.6c494.6,132.6,1007.1,476.8,1341.1,902.6c318.7,405.4,484.4,749.6,589,1223.8c53.5,255,56.1,313.6,58.6,1527.2c0,1155-5.1,1274.8-45.9,1415c-186.1,596.6-609.4,917.9-1374.2,1045.3c-135.1,22.9-550.7,51-963.7,63.7c-1560.3,53.5-1828,112.2-2957.5,662.9c-685.8,334-928,415.6-1328.3,458.9C2944.8,3820.4,2919.3,3820.4,2646.5,3789.8z M3378.2,3165.2c255-51,461.5-135.1,1014.7-413c543.1-270.3,821-382.4,1213.6-487c311-84.2,798-155.5,1042.8-155.5c142.8,0,158.1-5.1,234.6-91.8c112.2-124.9,214.2-163.2,420.7-163.2c193.8,0,359.5,61.2,423.2,153c40.8,56.1,48.5,58.6,328.9,43.3c894.9-51,1249.3-328.9,1246.7-971.4c0-117.3-7.6-247.3-17.8-288.1c-30.6-147.9-94.3-331.4-168.3-494.6l-76.5-168.3l-158.1-12.7c-379.9-30.6-563.4-270.3-372.2-487l73.9-86.7l-81.6-76.5c-211.6-198.9-527.8-359.5-843.9-428.3c-160.6-35.7-272.8-43.3-560.9-30.6c-555.8,20.4-777.6,99.4-1494,525.2C5111.9-174.8,4857-52.4,4482.2,70c-410.5,137.7-685.8,175.9-1402.3,206.5c-1287.5,51-1596,86.7-1891.8,219.3c-191.2,84.1-379.9,288.1-443.6,471.7c-66.3,193.8-58.6,471.7,17.9,696l61.2,175.9l155.5,5.1c226.9,5.1,402.8,119.8,433.4,280.5c20.4,107.1,0,168.3-84.1,249.9l-66.3,66.3l61.2,66.3c249.9,267.7,808.2,571.1,1200.8,657.8C2745.9,3213.6,3143.6,3213.6,3378.2,3165.2z M3391-391.5c221.8-112.2,397.7-351.8,362-492.1c-51-211.6-418.1-183.6-657.8,51C2972.8-712.8,2921.8-610.8,2932-496c5.1,79.1,22.9,102,96.9,137.7C3130.9-307.4,3240.5-317.6,3391-391.5z M1328.3-414.5c140.2-86.7,221.8-209.1,221.8-323.8c0-216.7-392.6-153-573.7,91.8C792.9-394.1,1040.2-230.9,1328.3-414.5z M5550.4-1273.7c135.1-84.1,244.8-257.5,221.8-349.3c-23-89.2-145.3-132.6-267.7-96.9c-137.7,43.4-293.2,163.2-341.7,267.7c-56.1,117.3-53.5,160.6,10.2,224.4C5244.5-1156.4,5387.3-1174.2,5550.4-1273.7z M2682.2-1339.9c293.2-165.7,341.6-476.8,73.9-476.8c-196.3,0-466.6,232-466.6,397.8C2289.5-1278.7,2503.7-1238,2682.2-1339.9z M6659.5-2446.5c209-107.1,372.2-308.5,372.2-461.5c0-68.8-79-150.4-163.2-173.4c-168.3-40.8-517.6,158.1-617,351.8C6111.3-2459.2,6353.6-2290.9,6659.5-2446.5z"/><path d="M3013.6,2639.9c-135.1-45.9-221.8-130-221.8-219.3c0-160.6,181-270.3,453.8-270.3c418.1-2.5,599.2,288.1,280.5,453.8C3408.8,2665.4,3138.5,2683.3,3013.6,2639.9z"/><path d="M2213,1490.1c-168.3-48.5-295.8-132.6-334-226.9c-28-68.8-25.5-89.2,17.9-168.3c188.7-351.9,1106.5-288.1,1106.5,79c0,48.5-22.9,114.7-51,150.4C2837.7,1472.2,2450.2,1556.4,2213,1490.1z"/><path d="M5693.2,1492.6c-119.8-40.8-216.7-145.3-216.7-232c0-267.7,594-372.2,846.5-147.9c201.4,181-17.9,410.5-387.5,407.9C5843.6,1520.7,5736.6,1507.9,5693.2,1492.6z"/><path d="M8051.6,1278.5c-124.9-53.5-178.5-109.6-178.5-188.7c0-137.7,165.7-229.5,415.6-229.5c175.9,0,341.7,73.9,377.3,168.3C8737.4,1227.5,8321.8,1395.8,8051.6,1278.5z"/><path d="M4321.5,1013.3c-147.9-28-234.6-102-234.6-204c0-124.9,96.9-186.1,313.6-198.9c204-12.7,346.7,35.7,392.6,132.6C4869.7,916.4,4609.6,1064.3,4321.5,1013.3z"/><path d="M6662.1,225.5c-196.3-48.4-344.2-181-344.2-311c0-323.8,775.1-453.8,1070.8-175.9C7671.7,3.7,7161.8,345.3,6662.1,225.5z"/></g></g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

14
images/icons/erase.svg Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="548.157px" height="548.157px" viewBox="0 0 548.157 548.157" style="enable-background:new 0 0 548.157 548.157;"
xml:space="preserve">
<g>
<path d="M545.027,112.765c-3.046-6.471-7.57-11.657-13.565-15.555c-5.996-3.9-12.614-5.852-19.846-5.852H292.351
c-11.04,0-20.175,4.184-27.408,12.56L9.13,396.279c-4.758,5.328-7.661,11.56-8.708,18.698c-1.049,7.139-0.144,13.941,2.712,20.417
c3.044,6.468,7.564,11.652,13.561,15.553c5.997,3.898,12.612,5.853,19.845,5.853h219.268c11.042,0,20.177-4.179,27.41-12.56
l255.813-292.363c4.75-5.33,7.655-11.561,8.699-18.699C548.788,126.039,547.877,119.238,545.027,112.765z M255.811,420.254H36.54
l95.93-109.632h219.27L255.811,420.254z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
images/icons/external.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

19
images/icons/fill.svg Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<path d="M494.412,245.154L371.59,122.507l93.792-93.934L437.07,0.304L343.28,94.237l-56.613-56.532L37.714,286.659
l207.754,207.459c11.699,11.699,27.069,17.549,42.436,17.549c15.367,0,30.735-5.849,42.436-17.549l164.082-164.082
c11.389-11.388,17.632-26.53,17.578-42.635C511.946,271.446,505.704,256.446,494.412,245.154z M466.131,301.745L302.048,465.828
c-7.799,7.8-20.489,7.8-28.3-0.01L94.314,286.638L286.687,94.266l28.324,28.283L211.272,226.445l28.312,28.269L343.322,150.82
l122.811,122.636c3.761,3.761,5.842,8.761,5.859,14.079C472.009,292.902,469.928,297.948,466.131,301.745z"/>
</g>
<g>
<path d="M95.137,398.966c-10.179-15.198-20.245-27.482-20.669-27.997l-15.455-18.808l-15.455,18.808
c-0.424,0.516-10.49,12.799-20.669,27.997C2.372,429.596,0,444.293,0,452.684c0,32.54,26.474,59.012,59.012,59.012
c32.539,0,59.012-26.473,59.012-59.012C118.025,444.293,115.652,429.596,95.137,398.966z M59.012,471.688
c-10.479,0-19.004-8.525-19.005-18.956c0.004-0.08,0.526-8.271,16.291-31.757c0.907-1.35,1.813-2.678,2.714-3.972
c0.899,1.294,1.806,2.622,2.714,3.972c15.491,23.079,16.265,31.388,16.29,31.745C77.996,463.182,69.48,471.688,59.012,471.688z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
images/icons/gradient.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

View File

Before

Width:  |  Height:  |  Size: 84 B

After

Width:  |  Height:  |  Size: 84 B

2
images/icons/italic.svg Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-type-italic" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M7.991 11.674L9.53 4.455c.123-.595.246-.71 1.347-.807l.11-.52H7.211l-.11.52c1.06.096 1.128.212 1.005.807L6.57 11.674c-.123.595-.246.71-1.346.806l-.11.52h3.774l.11-.52c-1.06-.095-1.129-.211-1.006-.806z"/></svg>

After

Width:  |  Height:  |  Size: 393 B

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g id="XMLID_1_">
<path id="XMLID_12_" d="M128.4,96.2L64.2,32H32.6v31.6l64.2,64.2L128.4,96.2z M160,0.4h31.6v64.2H160V0.4z M287.5,160.4h64.2V192
h-64.2V160.4z M320,64.6V33h-31.6l-64.2,64.2l31.6,31.6L320,64.6z M0,160.4h64.2V192H0V160.4z M160,287.9h31.6v64.2H160V287.9z
M31.6,287.9v31.6h31.6l64.2-64.2l-31.6-31.6L31.6,287.9z M504.2,441.4L187,123.2c-9.3-9.3-24.2-9.3-33.5,0L123.7,153
c-9.3,9.3-9.3,24.2,0,33.5l318.2,318.2c9.3,9.3,24.2,9.3,33.5,0l29.8-29.8C514.4,465.5,514.4,450.7,504.2,441.4z M240,272
l-95.8-95.8l31.6-31.6l95.8,95.8L240,272z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 913 B

24
images/icons/media.svg Normal file
View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="548.176px" height="548.176px" viewBox="0 0 548.176 548.176" style="enable-background:new 0 0 548.176 548.176;"
xml:space="preserve">
<g>
<g>
<path d="M534.75,68.238c-8.945-8.945-19.694-13.417-32.261-13.417H45.681c-12.562,0-23.313,4.471-32.264,13.417
C4.471,77.185,0,87.936,0,100.499v347.173c0,12.566,4.471,23.318,13.417,32.264c8.951,8.946,19.702,13.419,32.264,13.419h456.815
c12.56,0,23.312-4.473,32.258-13.419c8.945-8.945,13.422-19.697,13.422-32.264V100.499
C548.176,87.936,543.699,77.185,534.75,68.238z M511.623,447.672c0,2.478-0.899,4.613-2.707,6.427
c-1.81,1.8-3.952,2.703-6.427,2.703H45.681c-2.473,0-4.615-0.903-6.423-2.703c-1.807-1.813-2.712-3.949-2.712-6.427V100.495
c0-2.474,0.902-4.611,2.712-6.423c1.809-1.803,3.951-2.708,6.423-2.708h456.815c2.471,0,4.613,0.905,6.42,2.708
c1.801,1.812,2.707,3.949,2.707,6.423V447.672L511.623,447.672z"/>
<path d="M127.91,237.541c15.229,0,28.171-5.327,38.831-15.987c10.657-10.66,15.987-23.601,15.987-38.826
c0-15.23-5.333-28.171-15.987-38.832c-10.66-10.656-23.603-15.986-38.831-15.986c-15.227,0-28.168,5.33-38.828,15.986
c-10.656,10.66-15.986,23.601-15.986,38.832c0,15.225,5.327,28.169,15.986,38.826C99.742,232.211,112.683,237.541,127.91,237.541z
"/>
<polygon points="210.134,319.765 164.452,274.088 73.092,365.447 73.092,420.267 475.085,420.267 475.085,292.36 356.315,173.587
"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

11
images/icons/menu.svg Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="124px" height="124px" viewBox="0 0 124 124" style="enable-background:new 0 0 124 124;" xml:space="preserve">
<g>
<path d="M112,6H12C5.4,6,0,11.4,0,18s5.4,12,12,12h100c6.6,0,12-5.4,12-12S118.6,6,112,6z"/>
<path d="M112,50H12C5.4,50,0,55.4,0,62c0,6.6,5.4,12,12,12h100c6.6,0,12-5.4,12-12C124,55.4,118.6,50,112,50z"/>
<path d="M112,94H12c-6.6,0-12,5.4-12,12s5.4,12,12,12h100c6.6,0,12-5.4,12-12S118.6,94,112,94z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 797 B

22
images/icons/pencil.svg Normal file
View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<polygon points="51.2,353.28 0,512 158.72,460.8 "/>
</g>
</g>
<g>
<g>
<rect x="89.73" y="169.097" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -95.8575 260.3719)" width="353.277" height="153.599"/>
</g>
</g>
<g>
<g>
<path d="M504.32,79.36L432.64,7.68c-10.24-10.24-25.6-10.24-35.84,0l-23.04,23.04l107.52,107.52l23.04-23.04
C514.56,104.96,514.56,89.6,504.32,79.36z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 767 B

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 296.135 296.135" style="enable-background:new 0 0 296.135 296.135;" xml:space="preserve">
<path d="M284.5,11.635C276.997,4.132,267.021,0,256.411,0s-20.586,4.132-28.089,11.635l-64.681,64.68l-6.658-6.658
c-2.777-2.777-6.2-4.512-9.786-5.206c-0.598-0.116-1.2-0.202-1.804-0.26s-1.211-0.087-1.817-0.087s-1.213,0.029-1.817,0.087
s-1.206,0.145-1.804,0.26c-3.585,0.694-7.009,2.43-9.786,5.206v0c-1.388,1.388-2.516,2.938-3.384,4.59
c-0.289,0.55-0.55,1.112-0.781,1.683c-0.694,1.712-1.128,3.505-1.302,5.317c-0.058,0.604-0.087,1.211-0.087,1.817
c0,1.213,0.116,2.426,0.347,3.621c0.347,1.793,0.954,3.545,1.822,5.196c0.868,1.651,1.996,3.201,3.384,4.59l4.319,4.319
L21.468,213.811c-1.434,1.434-2.563,3.143-3.316,5.025l-16.19,40.387c-3.326,8.298-2.338,17.648,2.644,25.013
c5.04,7.451,13.356,11.899,22.244,11.899c3.432,0,6.817-0.659,10.063-1.961L77.3,277.984c1.882-0.754,3.592-1.883,5.025-3.316
l113.021-113.021l4.318,4.318c0.463,0.463,0.944,0.897,1.44,1.302c0.993,0.81,2.049,1.504,3.15,2.083
c2.752,1.446,5.785,2.169,8.818,2.169l0,0c0.029,0,0.058-0.004,0.087-0.004c1.791-0.008,3.58-0.264,5.312-0.777
c2.345-0.694,4.583-1.851,6.569-3.471c0.497-0.405,0.977-0.839,1.44-1.302v0c2.314-2.314,3.905-5.077,4.772-8.009
c0.694-2.345,0.926-4.798,0.694-7.216c-0.116-1.209-0.347-2.408-0.694-3.581s-0.81-2.318-1.388-3.419
c-0.868-1.651-1.996-3.201-3.384-4.59l-6.658-6.658l64.68-64.68C299.988,52.326,299.988,27.124,284.5,11.635z M63.285,251.282
l-30.764,12.331l12.332-30.763l110.848-110.848l18.432,18.432L63.285,251.282z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

15
images/icons/refresh.svg Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M403.678,272c0,40.005-15.615,77.651-43.989,106.011C331.33,406.385,293.683,422,253.678,422
c-40.005,0-77.651-15.615-106.011-43.989c-28.374-28.359-43.989-66.006-43.989-106.011s15.615-77.651,43.989-106.011
C176.027,137.615,213.673,122,253.678,122c25.298,0,49.849,6.343,71.88,18.472L267.023,212h231.299L440.49,0l-57.393,70.13
C344.323,45.14,299.865,32,253.678,32c-64.116,0-124.395,24.961-169.702,70.298C38.639,147.605,13.678,207.884,13.678,272
s24.961,124.395,70.298,169.702C129.284,487.039,189.562,512,253.678,512s124.395-24.961,169.702-70.298
c45.337-45.308,70.298-105.586,70.298-169.702v-15h-90V272z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1008 B

14
images/icons/select.svg Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 262.474 262.474" style="enable-background:new 0 0 262.474 262.474;" xml:space="preserve">
<g id="XMLID_351_">
<path id="XMLID_352_" d="M217.327,210.541l-38.815-71.507l31.813-17.271c4.652-2.525,7.628-7.315,7.833-12.604
c0.204-5.289-2.395-10.294-6.837-13.17L66.756,2.408c-4.609-2.984-10.481-3.211-15.308-0.591c-4.826,2.62-7.835,7.667-7.844,13.159
l-0.277,172.206c-0.008,5.293,2.773,10.198,7.32,12.909c4.545,2.709,10.185,2.824,14.836,0.298l31.811-17.268l38.816,71.506
c2.718,5.007,7.873,7.847,13.196,7.847c2.417,0,4.869-0.586,7.143-1.82l54.849-29.774
C218.58,226.928,221.279,217.822,217.327,210.541z M155.321,227.132l-38.816-71.507c-1.898-3.496-5.107-6.095-8.922-7.225
c-1.395-0.414-2.831-0.618-4.261-0.618c-2.478,0-4.94,0.614-7.157,1.817l-22.797,12.376L73.56,42.55l100.255,64.898l-22.799,12.377
c-7.281,3.952-9.979,13.058-6.027,20.338l38.815,71.507L155.321,227.132z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 511.997 511.997" style="enable-background:new 0 0 511.997 511.997;" xml:space="preserve">
<g>
<g>
<rect x="137.809" y="471.577" width="89.817" height="39.919"/>
</g>
</g>
<g>
<g>
<rect x="283.463" y="471.577" width="89.817" height="39.919"/>
</g>
</g>
<g>
<g>
<path d="M60.963,471.581c-11.579,0-21-9.421-21-21.001v-19.959H0.044v19.959c0,33.592,27.327,60.92,60.919,60.92h19.959v-39.919
H60.963z"/>
</g>
</g>
<g>
<g>
<path d="M471.083,430.621v19.959c0,11.58-9.42,21.001-21,21.001h-19.959V511.5h19.959c33.592,0,60.919-27.328,60.919-60.92
v-19.959H471.083z"/>
</g>
</g>
<g>
<g>
<rect x="137.809" y="0.497" width="89.817" height="39.919"/>
</g>
</g>
<g>
<g>
<rect x="283.463" y="0.497" width="89.817" height="39.919"/>
</g>
</g>
<g>
<g>
<path d="M60.963,0.497c-33.592,0-60.92,27.328-60.92,60.92v19.959h39.919h0.001V61.417c0-11.58,9.42-21.001,21-21.001h19.959
V0.497H60.963z"/>
</g>
</g>
<g>
<g>
<path d="M450.083,0.497h-19.959v39.919h19.959c11.579,0,21,9.421,21,21.001v19.959h39.919V61.417
C511.002,27.825,483.675,0.497,450.083,0.497z"/>
</g>
</g>
<g>
<g>
<rect y="288.909" width="39.919" height="89.817"/>
</g>
</g>
<g>
<g>
<rect y="143.246" width="39.919" height="89.817"/>
</g>
</g>
<g>
<g>
<rect x="472.078" y="288.909" width="39.919" height="89.817"/>
</g>
</g>
<g>
<g>
<rect x="472.078" y="143.246" width="39.919" height="89.817"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

6
images/icons/shape.svg Normal file
View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="1 2 31 27" x="0px" y="0px">
<title>shapes</title>
<g>
<path d="M30.87,16.33l-7.5-13a1,1,0,0,0-1.73,0l-5,8.69a8.15,8.15,0,0,0-1.61,0V7a1,1,0,0,0-1-1H2A1,1,0,0,0,1,7V19a1,1,0,0,0,1,1H8a8,8,0,1,0,15.69-2.17H30a1,1,0,0,0,.87-1.5ZM3,18V8H13v4.58l0,0A8,8,0,0,0,8.28,18H3Zm13,8a6,6,0,0,1-6-6,4.62,4.62,0,0,1,.07-.86,6,6,0,0,1,4.22-4.89A5.92,5.92,0,0,1,16,14a5.29,5.29,0,0,1,1,.09A6,6,0,0,1,16,26Zm6.83-10.17h0a8,8,0,0,0-4.12-3.34l0,0L22.5,5.84l5.77,10Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 514 B

13
images/icons/sharpen.svg Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M508.867,190.394l-111-143.568C394.996,43.113,390.52,41,386,41H126c-4.498,0-8.98,2.092-11.867,5.825l-111,143.568
c-4.509,5.832-4.112,14.076,0.937,19.447l241,256.432c2.655,2.824,6.568,4.728,10.93,4.728c4.3,0,8.221-1.845,10.93-4.728
l241-256.432C512.979,204.469,513.376,196.226,508.867,190.394z M241,418.137L34.694,198.62l93.584-121.043L241,172.957V418.137z
M256,146.351L166.949,71h178.102L256,146.351z M271,418.137v-245.18l112.722-95.38l93.585,121.043L271,418.137z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 867 B

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg width="1em" height="1em" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M8.527 13.164c-2.153 0-3.589-1.107-3.705-2.81h1.23c.144 1.06 1.129 1.703 2.544 1.703 1.34 0 2.31-.705 2.31-1.675 0-.827-.547-1.374-1.914-1.675L8.046 8.5h3.45c.468.437.675.994.675 1.697 0 1.826-1.436 2.967-3.644 2.967zM6.602 6.5H5.167a2.776 2.776 0 0 1-.099-.76c0-1.627 1.436-2.768 3.48-2.768 1.969 0 3.39 1.175 3.445 2.85h-1.23c-.11-1.08-.964-1.743-2.25-1.743-1.23 0-2.18.602-2.18 1.607 0 .31.083.581.27.814z"/><path fill-rule="evenodd" d="M15 8.5H1v-1h14v1z"/>
</svg>

After

Width:  |  Height:  |  Size: 608 B

14
images/icons/text.svg Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="977.7px" height="977.7px" viewBox="0 0 977.7 977.7" style="enable-background:new 0 0 977.7 977.7;" xml:space="preserve"
>
<g>
<path d="M770.7,930.6v-35.301c0-23.398-18-42.898-41.3-44.799c-17.9-1.5-35.8-3.1-53.7-5c-34.5-3.6-72.5-7.4-72.5-50.301L603,131.7
c136-2,210.5,76.7,250,193.2c6.3,18.7,23.8,31.3,43.5,31.3h36.2c24.9,0,45-20.1,45-45V47.1c0-24.9-20.1-45-45-45H488.9h-0.2H45
c-24.9,0-45,20.1-45,45v264.1c0,24.9,20.1,45,45,45h36.2c19.7,0,37.2-12.6,43.5-31.3c39.4-116.5,114-195.2,250-193.2l-0.3,663.5
c0,42.9-38,46.701-72.5,50.301c-17.9,1.9-35.8,3.5-53.7,5c-23.3,1.9-41.3,21.4-41.3,44.799V930.6c0,24.9,20.1,45,45,45h236.8h0.3
h236.7C750.5,975.6,770.7,955.401,770.7,930.6z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-type-underline" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M5.313 3.136h-1.23V9.54c0 2.105 1.47 3.623 3.917 3.623s3.917-1.518 3.917-3.623V3.136h-1.23v6.323c0 1.49-.978 2.57-2.687 2.57-1.709 0-2.687-1.08-2.687-2.57V3.136z"/><path fill-rule="evenodd" d="M12.5 15h-9v-1h9v1z"/></svg>

After

Width:  |  Height:  |  Size: 408 B

1
images/icons/undo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18.885 3.515c-4.617-4.618-12.056-4.676-16.756-.195l-2.129-2.258v7.938h7.484l-2.066-2.191c2.82-2.706 7.297-2.676 10.073.1 4.341 4.341 1.737 12.291-5.491 12.291v4.8c3.708 0 6.614-1.244 8.885-3.515 4.686-4.686 4.686-12.284 0-16.97z"/></svg>

After

Width:  |  Height:  |  Size: 330 B

20
images/icons/view.svg Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 461.312 461.312" style="enable-background:new 0 0 461.312 461.312;" xml:space="preserve">
<g>
<g>
<path d="M230.656,156.416c-40.96,0-74.24,33.28-74.24,74.24s33.28,74.24,74.24,74.24s74.24-33.28,74.24-74.24
S271.616,156.416,230.656,156.416z M225.024,208.64c-9.216,0-16.896,7.68-16.896,16.896h-24.576
c0.512-23.04,18.944-41.472,41.472-41.472V208.64z"/>
</g>
</g>
<g>
<g>
<path d="M455.936,215.296c-25.088-31.232-114.688-133.12-225.28-133.12S30.464,184.064,5.376,215.296
c-7.168,8.704-7.168,21.504,0,30.72c25.088,31.232,114.688,133.12,225.28,133.12s200.192-101.888,225.28-133.12
C463.104,237.312,463.104,224.512,455.936,215.296z M230.656,338.176c-59.392,0-107.52-48.128-107.52-107.52
s48.128-107.52,107.52-107.52s107.52,48.128,107.52,107.52S290.048,338.176,230.656,338.176z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

8
images/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 33 KiB

BIN
images/manifest/144x144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
images/manifest/168x168.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

BIN
images/manifest/192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
images/manifest/48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/manifest/72x72.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
images/manifest/96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

1809
images/test-collection.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -5,24 +5,25 @@
<meta http-equiv="x-ua-compatible" content="IE=edge" />
<title>miniPaint - image editor</title>
<meta name="description" content="miniPaint is free online image editor using HTML5. Edit, adjust your images, add effects online in your browser, without installing anything..." />
<meta name="keywords" content="photo, image, picture, transparent, layers, free, edit, html5, canvas, javascript, online, photoshop, gimp, effects, sharpen, blur, magic wand tool, clone tool, rotate, resize, photoshop online, online tools, tilt shift, sprites, keypoints" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="images/favicon.png?v2" />
<meta name="keywords" content="photo, image, picture, transparent, layers, free, edit, html5, canvas, javascript, online, photoshop, gimp, effects, sharpen, blur, magic eraser tool, clone tool, rotate, resize, photoshop online, online tools, tilt shift, sprites, keypoints" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=0" />
<link rel="icon" sizes="192x192" href="images/favicon.png">
<!-- <link rel="manifest" href="dist/manifest.json"> -->
<!-- Google -->
<meta itemprop="name" content="miniPaint" />
<meta itemprop="description" content="miniPaint is free online image editor using HTML5. Edit, adjust your images, add effects online in your browser, without installing anything..." />
<meta itemprop="image" content="http://viliusle.github.io/miniPaint/images/preview.jpg" />
<meta itemprop="image" content="https://viliusle.github.io/miniPaint/images/preview.jpg" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="miniPaint" />
<meta name="twitter:description" content="miniPaint is free online image editor using HTML5. Edit, adjust your images, add effects online in your browser, without installing anything..." />
<meta name="twitter:image" content="http://viliusle.github.io/miniPaint/images/preview.jpg" />
<meta name="twitter:image" content="https://viliusle.github.io/miniPaint/images/preview.jpg" />
<meta name="twitter:image:alt" content="miniPaint is free online image editor using HTML5. Edit, adjust your images, add effects online in your browser, without installing anything..." />
<!-- Facebook, Pinterest -->
<meta property="og:title" content="miniPaint" />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://viliusle.github.io/miniPaint/" />
<meta property="og:image" content="http://viliusle.github.io/miniPaint/images/preview.jpg" />
<meta property="og:url" content="https://viliusle.github.io/miniPaint/" />
<meta property="og:image" content="https://viliusle.github.io/miniPaint/images/preview.jpg" />
<meta property="og:description" content="miniPaint is free online image editor using HTML5. Edit, adjust your images, add effects online in your browser, without installing anything..." />
<meta property="og:site_name" content="miniPaint" />
@ -30,24 +31,35 @@
</head>
<body>
<div class="wrapper">
<nav aria-label="Main Menu" class="main_menu" id="main_menu"></nav>
<div class="submenu">
<a class="logo" href="">miniPaint</a>
<a class="logo" href="#">miniPaint</a>
<div class="block attributes" id="action_attributes"></div>
<div class="clear"></div>
<button class="undo_button" id="undo_button" type="button">
<span class="sr_only">Undo</span>
</button>
</div>
<div class="sidebar_left" id="tools_container"></div>
<div class="main_wrapper" id="main_wrapper">
<div class="canvas_wrapper" id="canvas_wrapper">
<div id="mouse"></div>
<div class="transparent-grid" id="canvas_minipaint_background"></div>
<canvas id="canvas_minipaint">
<div class="trn error">
Your browser does not support canvas or JavaScript is not enabled.
</div>
</canvas>
<div class="middle_area" id="middle_area">
<canvas class="ruler_left" id="ruler_left"></canvas>
<canvas class="ruler_top" id="ruler_top"></canvas>
<div class="main_wrapper" id="main_wrapper">
<div class="canvas_wrapper" id="canvas_wrapper">
<div id="mouse"></div>
<div class="transparent-grid" id="canvas_minipaint_background"></div>
<canvas id="canvas_minipaint">
<div class="trn error">
Your browser does not support canvas or JavaScript is not enabled.
</div>
</canvas>
</div>
</div>
</div>
@ -59,12 +71,6 @@
<div class="colors block">
<h2 class="trn toggle" data-target="toggle_colors">Colors</h2>
<input
title="Click to change color"
type="color"
class="color_area"
id="main_color"
value="#0000ff" />
<div class="content" id="toggle_colors"></div>
</div>
@ -75,7 +81,7 @@
<div class="details block" id="details_base">
<h2 class="trn toggle toggle-full" data-target="toggle_details">Layer details</h2>
<div class="content" id="toggle_details"></div>
<div class="content details-content" id="toggle_details"></div>
</div>
<div class="layers block">
@ -85,10 +91,14 @@
</div>
</div>
<div class="mobile_menu">
<button class="right_mobile_menu" id="mobile_menu_button" type="button"></button>
<button class="left_mobile_menu" id="left_mobile_menu_button" type="button">
<span class="sr_only">Toggle Menu</span>
</button>
<button class="right_mobile_menu" id="mobile_menu_button" type="button">
<span class="sr_only">Toggle Menu</span>
</button>
</div>
<div class="ddsmoothmenu" id="main_menu"></div>
<div class="hidden" id="tmp"></div>
<div id="popup"></div>
<div id="popups"></div>
</body>
</html>

41
manifest-disabled.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "miniPaint",
"short_name": "miniPaint",
"start_url": "/",
"display": "standalone",
"orientation": "landscape",
"background_color": "#666d6f",
"description": "miniPaint is free online image editor using HTML5.",
"icons": [
{
"src": "images/manifest/48x48.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "images/manifest/72x72.png",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "images/manifest/96x96.png",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "images/manifest/144x144.png",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "images/manifest/168x168.png",
"sizes": "168x168",
"type": "image/png"
},
{
"src": "images/manifest/192x192.png",
"sizes": "192x192",
"type": "image/png"
}
]
}

15577
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "miniPaint",
"version": "4.0.1",
"version": "4.14.2",
"author": "Vilius L.",
"description": "Online graphics editing tool lets create, edit images using HTML5 technologies.",
"keywords": [
@ -10,31 +10,42 @@
"layers",
"effects"
],
"scripts": {
"server": "webpack serve --mode development --env development --open",
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
"repository": {
"type": "git",
"url": "https://github.com/viliusle/miniPaint"
},
"homepage": "https://github.com/viliusle/miniPaint",
"license": "GPL-3.0",
"license": "MIT",
"devDependencies": {
"amd-optimize": "^0.6.1",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.2",
"source-map-loader": "^0.2.3",
"style-loader": "^0.19.0",
"webpack": "^3.9.1",
"webpack-dev-server": "^2.9.5"
"@babel/core": "^7.14.5",
"@babel/plugin-transform-runtime": "^7.14.5",
"@babel/preset-env": "^7.14.5",
"babel-loader": "^8.2.2",
"css-loader": "^5.2.6",
"source-map-loader": "^3.0.0",
"style-loader": "^2.0.0",
"webpack": "^5.76.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^4.3.1"
},
"dependencies": {
"alertifyjs": "^1.11.0",
"blueimp-canvas-to-blob": "^3.14.0",
"@babel/runtime": "^7.14.5",
"alertifyjs": "^1.13.1",
"blueimp-canvas-to-blob": "^3.28.0",
"exif-js": "^2.3.0",
"file-saver": "^1.3.3",
"file-saver": "^2.0.5",
"fuzzysort": "^1.1.4",
"gif.js.optimized": "^1.0.1",
"hermite-resize": "git+https://github.com/viliusle/Hermite-resize.git",
"jquery": "^3.2.1"
"jquery": "^3.5.1",
"pica": "^7.0.0",
"semver-compare": "^1.0.0",
"uuid": "^8.3.2",
"webfontloader": "^1.6.28"
}
}

68
service-worker.js Normal file
View File

@ -0,0 +1,68 @@
//IMPORTANT - this file is not used !!!
// use a cacheName for cache versioning
var cacheName = 'v1:static';
// during the install phase you usually want to cache static assets
self.addEventListener('install', function(e) {
// once the SW is installed, go ahead and fetch the resources to make this work offline
e.waitUntil(
caches.open(cacheName).then(function(cache) {
return cache.addAll([
'./',
'./dist/bundle.js',
'./images/favicon.png',
'./images/logo.svg',
'./images/logo-colors.png',
'./images/icons/animation.svg',
'./images/icons/blur.svg',
'./images/icons/bold.svg',
'./images/icons/brush.svg',
'./images/icons/bulge_pinch.svg',
'./images/icons/clone.svg',
'./images/icons/crop.svg',
'./images/icons/delete.svg',
'./images/icons/desaturate.svg',
'./images/icons/erase.svg',
'./images/icons/external.png',
'./images/icons/fill.svg',
'./images/icons/gradient.png',
'./images/icons/grid.png',
'./images/icons/italic.svg',
'./images/icons/magic_erase.svg',
'./images/icons/media.svg',
'./images/icons/menu.svg',
'./images/icons/pencil.svg',
'./images/icons/pick_color.svg',
'./images/icons/refresh.svg',
'./images/icons/select.svg',
'./images/icons/selection.svg',
'./images/icons/shape.svg',
'./images/icons/sharpen.svg',
'./images/icons/strikethrough.svg',
'./images/icons/text.svg',
'./images/icons/underline.svg',
'./images/icons/view.svg'
]).then(function() {
self.skipWaiting();
});
})
);
});
// when the browser fetches a url
self.addEventListener('fetch', function(event) {
// either respond with the cached object or go ahead and fetch the actual url
event.respondWith(
caches.match(event.request).then(function(response) {
if (response) {
// retrieve from cache
return response;
}
// fetch as normal
return fetch(event.request);
})
);
});

732
src/css/component.css Normal file
View File

@ -0,0 +1,732 @@
/*****************\
| UI Button Group |
\*****************/
.ui_button_group {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.ui_button_group.no_wrap {
flex-wrap: nowrap;
}
.ui_button_group.stacked {
margin: .75rem 0;
}
.ui_button_group.stacked:first-child {
margin-top: 0;
}
.ui_button_group.stacked:last-child {
margin-bottom: 0;
}
.ui_button_group > button,
.ui_button_group > input[type="button"] {
border-radius: 0;
}
.ui_button_group > button:focus,
.ui_button_group > input[type="button"]:focus {
z-index: 1;
}
.ui_button_group > button + button,
.ui_button_group > button + input[type="button"],
.ui_button_group > input[type="button"] + button,
.ui_button_group > input[type="button"] + input[type="button"] {
margin-left: -1px;
}
.ui_button_group > button:first-child,
.ui_button_group > input[type="button"]:first-child {
border-radius: var(--button-border-radius) 0 0 var(--button-border-radius);
}
.ui_button_group > button:last-child,
.ui_button_group > input[type="button"]:last-child {
border-radius: 0 var(--button-border-radius) var(--button-border-radius) 0;
}
/****************\
| UI Color Input |
\****************/
.ui_color_input {
display: inline-block;
padding: 0;
margin: 0;
position: relative;
overflow: hidden;
vertical-align: middle;
}
.ui_color_input input[type="color"] {
display: block;
cursor: pointer;
padding: 0;
border: .2rem solid var(--input-background-color);
width: 3rem;
}
.ui_color_input .alpha_overlay {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw1AUhU9bRdGKiBlERDJUJwuiIo5ahSJUCLVCqw4mL/2DJg1Jiouj4Fpw8Gex6uDirKuDqyAI/oA4OTopukiJ9yWFFjFeeLyP8+45vHcfEKyVmGa1jQOabpvJeExMZ1bFjld0YxgBCOiTmWXMSVICvvV1T51Ud1Ge5d/3Z/WoWYsBAZF4lhmmTbxBPL1pG5z3iQVWkFXic+Ixky5I/Mh1xeM3znmXgzxTMFPJeWKBWMy3sNLCrGBqxFPEEVXTKT+Y9ljlvMVZK1VY4578heGsvrLMdVpDiGMRS5AgQkEFRZRgI0q7ToqFJJ3HfPyDrl8il0KuIhg5FlCGBtn1g//B79lauckJLykcA9pfHOdjBOjYBepVx/k+dpz6CRB6Bq70pr9cA2Y+Sa82tcgR0LsNXFw3NWUPuNwBBp4M2ZRdKUQrmMsB72f0TRmg/xboWvPm1jjH6QOQolklboCDQ2A0T9nrPu/ubJ3bvz2N+f0AL+pyjMZuudYAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfkCx4BHwaj7CMVAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAC5JREFUOMtjfPfuHQNuICgoiEeWiYECMKp5ZGhm/P//Px7p9+/fjwbYqGZKNAMAANAI7r7rfkQAAAAASUVORK5CYII=');
background-size: 100% 100%;
position: absolute;
top: 3px;
left: 3px;
right: 3px;
bottom: 3px;
pointer-events: none;
}
/**************************\
| UI Color Picker Gradient |
\**************************/
.ui_color_picker_gradient {
padding: 0 0 80% 0;
position: relative;
width: 100%;
}
.ui_color_picker_gradient .primary_pick {
position: absolute;
left: 86%;
right: 0;
top: 0;
bottom: 0;
background: white;
}
.ui_color_picker_gradient .secondary_pick {
position: absolute;
left: 0;
right: 17%;
top: 0;
bottom: 0;
border: 1px solid var(--border-color);
background: green;
}
.ui_color_picker_gradient .secondary_pick:focus {
outline: 0;
border: 1px solid var(--input-border-color-active);
}
.ui_color_picker_gradient .secondary_pick .saturation_gradient {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: linear-gradient(to right, #fff, rgba(204, 154, 129, 0));
}
.ui_color_picker_gradient .secondary_pick .value_gradient {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background: linear-gradient(to top, #000, rgba(204, 154, 129, 0));
}
.ui_color_picker_gradient .secondary_pick .handle {
position: absolute;
left: 0;
right: auto;
top: 0;
bottom: auto;
pointer-events: none;
}
.ui_color_picker_gradient .secondary_pick .handle:before {
content: '';
display: block;
position: absolute;
left: -.6rem;
top: -.6rem;
height: .3rem;
width: .3rem;
border: .4rem solid #999;
border-radius: 1000px;
}
.ui_color_picker_gradient .secondary_pick .handle:after {
content: '';
display: block;
position: absolute;
left: -.5rem;
top: -.5rem;
height: .5rem;
width: .5rem;
border: .2rem solid white;
border-radius: 1000px;
}
.ui_color_picker_gradient .primary_pick .ui_range {
border-color: rgba(1, 1, 1, 0.1);
}
.ui_color_picker_gradient .primary_pick .ui_range:focus {
border-color: var(--input-border-color-active);
}
/*****************\
| UI Color Sample |
\*****************/
.ui_color_sample {
border: 1px solid #999;
box-shadow: 0 0 0 1px #555 inset;
display: block;
height: 28px;
width: 28px;
}
/***************\
| UI Flex Group |
\***************/
.ui_flex_group {
display: flex;
flex-direction: row;
}
.ui_flex_group.stacked {
margin: .75rem 0;
}
.ui_flex_group.stacked:first-child {
margin-top: 0;
}
.ui_flex_group.stacked:last-child {
margin-bottom: 0;
}
.ui_flex_group.column {
flex-direction: column;
}
.ui_flex_group.justify_content_center {
justify-content: center;
}
.ui_flex_group.justify_content_start {
justify-content: flex-start;
}
.ui_flex_group.justify_content_end {
justify-content: flex-end;
}
.ui_flex_group.justify_content_space_around {
justify-content: space-around;
}
.ui_flex_group.justify_content_space_between {
justify-content: space-between;
}
.ui_flex_group.align_items_baseline {
align-items: baseline;
}
.ui_flex_group.align_items_center {
align-items: center;
}
.ui_flex_group.align_items_start {
align-items: flex-start;
}
.ui_flex_group.align_items_end {
align-items: flex-end;
}
.ui_flex_group.align_items_stretch {
align-items: stretch;
}
/****************\
| UI Icon Button |
\****************/
.ui_icon_button {
height: 2.8rem;
line-height: 2.8rem;
}
.ui_icon_button.input_height {
height: 2.4rem;
line-height: 2.4rem;
}
.ui_icon_button > svg {
display: block;
font-size: 1.6rem;
}
.ui_icon_button > img {
display: block;
margin: 0 auto;
}
button img{
filter: var(--menu-icons-filter);
}
/****************\
| UI Input Group |
\****************/
.ui_input_group {
display: flex;
flex-direction: row;
min-height: 2.4rem;
width: 100%;
}
.ui_input_group.stacked {
margin: .75rem 0;
}
.ui_input_group.stacked:first-child {
margin-top: 0;
}
.ui_input_group.stacked:last-child {
margin-bottom: 0;
}
.ui_input_group > input,
.ui_input_group > .ui_number_input,
.ui_input_group > .ui_range,
.ui_input_group > .ui_color_sample {
border-radius: 0;
height: auto;
min-width: 0;
}
.ui_input_group > .ui_color_sample {
border: none;
width: 100%;
}
.ui_input_group > :first-child {
border-radius: var(--input-border-radius) 0 0 var(--input-border-radius);
}
.ui_input_group > :last-child {
border-radius: 0 var(--input-border-radius) var(--input-border-radius) 0;
}
.ui_input_group > label {
display: flex;
align-items: center;
border: 1px solid var(--input-group-border-color);
border-right: 0;
margin: 0;
padding: 0 .75rem;
}
.ui_input_group > .ui_range + input,
.ui_input_group > .ui_range + .ui_number_input {
margin-left: -1px;
}
.ui_input_grid {
border-radius: var(--input-border-radius);
box-shadow: 0 1px 0 0 rgba(1, 1, 1, 0.1);
}
.ui_input_grid.stacked {
margin: .75rem 0;
}
.ui_input_grid.stacked:first-child {
margin-top: 0;
}
.ui_input_grid.stacked:last-child {
margin-bottom: 0;
}
:not(.ui_input_grid) > .ui_input_group {
border-radius: var(--input-border-radius);
box-shadow: 0 1px 0 0 rgba(1, 1, 1, 0.1);
}
.ui_input_grid > .ui_input_group {
margin: -1px 0;
}
.ui_input_grid > .ui_input_group > :first-child,
.ui_input_grid > .ui_input_group > :last-child {
border-radius: 0;
}
.ui_input_grid > .ui_input_group:first-child {
margin-top: 0;
}
.ui_input_grid > .ui_input_group:first-child > :first-child {
border-radius: var(--input-border-radius) 0 0 0;
}
.ui_input_grid > .ui_input_group:first-child > :last-child {
border-radius: 0 var(--input-border-radius) 0 0;
}
.ui_input_grid > .ui_input_group:last-child {
margin-bottom: 0;
}
.ui_input_grid > .ui_input_group:last-child > :first-child {
border-radius: 0 0 0 var(--input-border-radius);
}
.ui_input_grid > .ui_input_group:last-child > :last-child {
border-radius: 0 0 var(--input-border-radius) 0;
}
/*****************\
| UI Number Input |
\*****************/
.ui_number_input {
border: 1px solid var(--input-border-color);
border-radius: var(--input-border-radius);
display: inline-block;
padding: 0;
margin: 0;
position: relative;
overflow: hidden;
vertical-align: middle;
}
.ui_number_input > input[type="number"]::-webkit-outer-spin-button,
.ui_number_input > input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.ui_number_input > input[type="number"] {
border: none;
border-radius: 0;
-moz-appearance: textfield;
appearance: textfield;
padding-right: 2.5rem;
padding-right: calc(var(--number-input-arrow-width) + .5rem);
width: 100%;
}
.ui_number_input > .increase_number,
.ui_number_input > .decrease_number {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
width: 2rem;
width: var(--number-input-arrow-width);
border-radius: 0;
border: 1px solid var(--input-border-color);
border-right: none;
padding: 0;
margin: 0;
}
.ui_number_input > ::-moz-focus-inner {
border: 0;
}
.ui_number_input > .increase_number:focus,
.ui_number_input > .decrease_number:focus {
outline: 0;
}
.ui_number_input > .increase_number {
right: 0;
top: 0;
bottom: 50%;
border-top: none;
}
.ui_number_input > .increase_number::after {
content: '';
display: block;
width: 0;
height: 0;
border-left: 3px solid transparent;
border-right: 3px solid transparent;
border-bottom: 3px solid var(--input-text-color);
}
.ui_number_input > .decrease_number {
right: 0;
top: calc(50% - 1px);
bottom: 0;
border-bottom: none;
}
.ui_number_input > .decrease_number::after {
content: '';
display: block;
width: 0;
height: 0;
border-left: 3px solid transparent;
border-right: 3px solid transparent;
border-top: 3px solid var(--input-text-color);
}
/**********\
| UI Range |
\**********/
:root {
--range-handle-width: 18px;
}
.ui_range {
display: flex;
flex-direction: row;
background: var(--input-background-color);
border: 1px solid var(--input-border-color);
border-radius: 1000px;
height: 1.8rem;
overflow: visible;
outline: 0;
padding: 0 calc(var(--range-handle-width) / 2);
position: relative;
width: 100%;
}
.ui_range:focus {
border-color: var(--input-border-color-active);
z-index: 1;
}
.ui_range.active {
cursor: col-resize;
}
.ui_range .padded_track {
position: absolute;
left: calc(var(--range-handle-width) / 2);
right: calc(var(--range-handle-width) / 2);
top: 0;
bottom: 0;
}
.ui_range .bar {
overflow: visible;
position: relative;
width: 0%;
}
.ui_range .handle {
background: var(--input-text-color);
border: 1px solid var(--border-color);
border-radius: 1000px;
box-sizing: border-box;
cursor: col-resize;
display: block;
height: 1.8rem;
width: var(--range-handle-width);
position: absolute;
top: 50%;
right: 0;
transform: translate(50%, -50%);
}
.ui_range.color_picker .handle {
background: none;
border: none;
border-radius: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: auto;
top: 0;
bottom: 0;
transform: translateX(50%);
}
.ui_range.color_picker .handle::before {
content: '';
display: block;
width: 0;
height: 0;
border-left: .5rem solid transparent;
border-right: .5rem solid transparent;
border-top: .7rem solid white;
}
.ui_range.color_picker .handle::after {
content: '';
display: block;
width: 0;
height: 0;
border-left: .5rem solid transparent;
border-right: .5rem solid transparent;
border-bottom: .7rem solid black;
}
.ui_range.color_picker .handle:hover::before {
border-top-color: #eaeaea;
}
.ui_range.color_picker .handle:hover::after {
border-bottom-color: #222;
}
.ui_range.vertical {
flex-direction: column;
justify-content: flex-end;
height: 100%;
width: 1.8rem;
padding: calc(var(--range-handle-width) / 2) 0;
}
.ui_range.vertical.active {
cursor: row-resize;
}
.ui_range.vertical .padded_track {
left: 0;
right: 0;
top: calc(var(--range-handle-width) / 2);
bottom: calc(var(--range-handle-width) / 2);
}
.ui_range.vertical .bar {
width: 100%;
height: 0%;
}
.ui_range.vertical .handle {
transform: translate(50%, -50%);
top: 0;
right: 50%;
cursor: row-resize;
}
.ui_range.vertical.color_picker_thin {
padding: 1px 0;
border-radius: 0;
width: 100%;
}
.ui_range.vertical.color_picker_thin .padded_track {
top: 0;
bottom: 0;
}
.ui_range.vertical.color_picker_thin .handle {
border-radius: 0;
width: 100%;
height: .5rem;
}
/*************\
| UI Swatches |
\*************/
.ui_swatches {
display: flex;
justify-content: center;
}
.ui_swatches .swatch_group {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: auto;
border-radius: var(--input-border-radius);
border: 1px solid var(--border-color);
border-right: transparent;
box-shadow: 0 1px 0 0 rgba(1, 1, 1, 0.1);
overflow: hidden;
max-height: calc(2.3rem);
}
.ui_swatches .swatch_group:focus {
outline: 0;
box-shadow: 0 0 0 1px var(--input-border-color-active);
}
.ui_swatches .swatch_group.rows_2 {
max-height: calc(4.6rem - 1px);
}
.ui_swatches .swatch_group.rows_3 {
max-height: calc(6.9rem - 2px);
}
.ui_swatches .swatch_group.cols_1 .swatch {
width: 100%;
}
.ui_swatches .swatch_group.cols_2 .swatch {
width: 50%;
}
.ui_swatches .swatch_group.cols_3 .swatch {
width: 33.33%;
}
.ui_swatches .swatch_group.cols_4 .swatch {
width: 25%;
}
.ui_swatches .swatch_group.cols_5 .swatch {
width: 20%;
}
.ui_swatches .swatch_group.cols_6 .swatch {
width: 16.66%;
}
.ui_swatches .swatch_group.cols_7 .swatch {
width: 14.29%;
}
.ui_swatches .swatch_group.cols_8 .swatch {
width: 12.5%;
}
.ui_swatches .swatch {
background: white;
display: inline-block;
position: relative;
border: 1px solid var(--border-color);
border-radius: 0;
box-shadow: 0 0 0 1px white inset;
margin: -1px 0 0 -1px;
padding: 0;
height: 2.3rem;
min-width: 2.3rem;
flex-grow: 1;
}
.ui_swatches .swatch:hover,
.ui_swatches .swatch:focus {
background: white;
box-shadow: 0 0 0 2px white inset, 0 0 0 3px var(--border-color) inset;
}
.ui_swatches .swatch:hover:after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to bottom right, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.2) 50%, rgba(0, 0, 0, 0.1) 51%, rgba(0, 0, 0, 0.1) 100%);
}
.ui_swatches .swatch.active {
box-shadow: 0 0 0 3px var(--button-text-color-active) inset, 0 0 0 4px var(--border-color) inset;
}
/******************\
| UI Toggle Button |
\******************/
.ui_toggle_button {
padding-left: 2.6rem !important;
position: relative;
}
.ui_toggle_button:before {
background-color: var(--button-toggle-background-color);
background-image: url('data:image/svg+xml;utf8,<svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-x" fill="white" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/></svg>');
background-position: center;
background-repeat: no-repeat;
border-radius: var(--button-border-radius) 0 0 var(--button-border-radius);
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 1.8rem;
content: '';
}
.ui_toggle_button[aria-pressed="true"]:before {
background-color: var(--button-text-color-active);
background-image: url('data:image/svg+xml;utf8,<svg width="0.7em" height="1em" viewBox="0 0 16 16" class="bi bi-check2" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>');
}
/* media */
.media-paging{
width: 100%;
margin: 10px 0;
text-align: center;
}
.media-paging button{
background-color: var(--button-background-color);
color: var(--text-color);
}
.media-paging button.selected{
background-color: var(--background-color-active);
color: var(--text-color-active);
}
/* global search */
#global_search_results{
padding-top: 10px;
font-size: 14px;
}
#global_search_results .search-result {
padding: 3px 5px;
}
#global_search_results .search-result.active{
background-color: var(--background-color-active);
color: var(--text-color-active);
border-radius: 2px;
}
#global_search_results b{
color: var(--text-color-red);
}
.popup.shortcuts table{
line-height: 1;
}

View File

@ -1,8 +1,23 @@
.wrapper{
height: calc(100vh - 30px);
display: -ms-grid;
display: grid;
margin: 0;
position:relative;
position: fixed; /* dont change it, vh does not work on mobiles with bottom footer */
top: 30px;
right: 0;
left: 0;
bottom: 5px;
height: auto;
overflow: hidden;
-ms-grid-rows: auto 1fr;
grid-template-rows: auto 1fr;
-ms-grid-columns: auto 1fr auto;
grid-template-columns: auto 1fr auto;
grid-template-areas:
"submenu submenu submenu"
"sidebar_left main sidebar_right";
}
.trn{}
.toggle{
@ -11,6 +26,9 @@
.hidden{
display:none;
}
.center{
text-align: center;
}
.pointer{
cursor: pointer;
}
@ -32,18 +50,6 @@
.grey{
color:grey;
}
.external{
padding-right: 15px;
}
.external:after{
position:absolute;
content: "";
width:10px;
height:10px;
margin-left: 5px;
background: url(images/sprites.png) no-repeat -700px 0;
opacity: 0.3;
}
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
@ -53,36 +59,39 @@
user-select: none; /* Non-prefixed version */
}
.block{
position: relative;
background-color: rgba(255, 255, 255, 0.2);
background-color: var(--background-color-medium);
background-color: var(--block-background-color);
border: 1px solid rgba(0, 0, 0, 0.5);
border: 1px solid var(--background-color-border);
padding:5px;
border: 1px solid var(--border-color);
margin-bottom: 10px;
user-select: none;
border-radius: 4px;
}
.sidebar_right .block{
background-color: #68727b;
background-color: var(--block-background-color);
border-bottom: none;
box-shadow: 0 -2px 0 0 var(--header-background-color) inset;
}
.block:last-child{
margin-bottom: 0;
}
.block h2{
position: relative;
margin: -5px -5px 10px -5px;
padding: 2px 5px;
padding: 2px 5px 2px 6px;
margin: 0;
font-size: 110%;
background-color: rgba(255, 255, 255, 0.3);
background-color: var(--background-color-light);
background-color: var(--header-background-color);
border-bottom: #555;
border-radius: 4px 4px 0 0;
}
.block h2:after{
position:absolute;
content:'';
height:0;
left:0;
right:0;
bottom: -2px;
border-top: 1px solid #aaa;
.block.toggled h2, .block h2.toggled:after{
border: none;
}
.block h2.toggle:before{
/* icon */
position:absolute;
content:'';
width: 0;
@ -90,12 +99,25 @@
right: 10px;
top: 10px;
border-style: solid;
border-width: 0 5px 6px 5px;
border-color: transparent transparent #333333 transparent;
border-width: 0 4px 5px 4px;
border-color: transparent transparent var(--text-color-muted) transparent;
}
.block h2.toggled:before{
border-width: 6px 5px 0 5px;
border-color: #333333 transparent transparent transparent;
/* icon */
border-width: 5px 4px 0 4px;
border-color: var(--text-color-muted) transparent transparent transparent;
}
.block .content{
padding: 7.5px 5px;
}
.block_section {
margin: .75rem 0;
}
.block_section:first-child {
margin-top: 0;
}
.block_section:last-child {
margin-bottom: 0;
}
.error{
padding:20px;
@ -106,18 +128,30 @@
font-weight:bold;
}
/* color chooser */
body .sp-replacer{
width: 100%;
height: 40px;
}
body .sp-preview{
width: calc(100% - 20px);
height: 100%;
}
/* ========== header ======================================================== */
.logo{
position: relative;
display: inline-block;
float: left;
height: 30px;
width: 110px;
padding: 5px 5px 5px 36px;
margin: 5px;
font-size: 14px;
text-decoration: none;
font-weight: bold;
color: #ffffff;
color: var(--text-color);
}
.logo:after{
position:absolute;
@ -126,126 +160,167 @@
top: 0;
width: 31px;
height: 30px;
background: url(images/sprites.png) -50px -100px no-repeat;
background: url('images/logo.svg') no-repeat center center;
background-size: auto 28px;
filter: var(--mobile-menu-toggle-filter);
}
.logo:hover:after{
animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97);
left: 2px;
}
.about-logo{
margin-left:22%;
animation:shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97);;
}
.about-name{
font-size:15px;
color:#006900;
font-weight:bold;
}
@keyframes shake{
10%, 90%{
transform: translate(2px, 0px);
}
20%, 80%{
transform: translate(5px 0px);
}
30%, 50%, 70%{
transform: translate(0px 0px;);
}
40%, 60%{
transform: translate(6px 0px);
.undo_button {
display: none;
width: 50px;
height: 50px;
top: 0;
border: 0;
outline: none;
cursor: pointer;
filter: var(--mobile-menu-toggle-filter);
background: url(images/icons/undo.svg) no-repeat center center;
background-size: auto 25px;
margin-left: 10px;
}
.undo_button:hover {
background-color: transparent;
}
@media screen and (max-width: 700px){
.undo_button {
display: block;
}
}
/* ========== sub-header ==================================================== */
.submenu{
height:40px;
-ms-grid-row: 1;
-ms-grid-column: 1;
-ms-grid-column-span: 3;
grid-area: submenu;
display: flex;
flex-direction: row;
align-items: center;
background-color: rgba(255, 255, 255, 0.2);
background-color: var(--background-color-medium);
background-color: var(--section-background-color);
overflow: hidden;
margin-bottom: 5px;
}
.attributes{
float: left;
width: calc(100% - 115px);
height: 30px;
display: flex;
flex-wrap: nowrap;
background-color: var(--area-background-color);
width: calc(100% - 125px);
margin-top: 5px;
padding: 3px 10px 0 10px;
margin-bottom: 5px !important;
padding: 3px 10px 3px 10px;
border: 0;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
min-height: 30px;
}
.attributes .item{
display: inline-block;
display: inline-flex;
align-items: center;
margin-right: 20px;
}
.attributes .item > label {
margin: 0 .5rem 0 0;
}
.attributes input[type="number"]{
width: 60px;
margin-right: 5px;
}
.attributes button{
.attributes input[type="color"] {
cursor: pointer;
padding: 0;
border: .2rem solid var(--input-background-color);
width: 3rem;
}
.attributes .item > button:not(.ui_icon_button){
display: inline-block;
padding: 3px 10px;
border: 1px solid #444;
background-color: transparent;
margin-right: 5px;
}
.attributes button:hover{
background-color: rgba(255, 255, 255, 0.3);
background-color: var(--background-color-light);
}
.attributes button.active{
background-color: #419147;
background-color: var(--background-color-active);
}
/* ========== left sidebar ================================================== */
.sidebar_left{
position: absolute;
left:0px;
top: 45px;
-ms-grid-row: 2;
-ms-grid-column: 1;
grid-area: sidebar_left;
display: flex;
flex-direction: row;
flex-wrap: wrap;
background-color: var(--section-background-color);
padding: 0 5px 5px 0;
margin-right: 5px;
overflow: hidden;
align-self: start;
width: 40px;
padding: 0 5px;
background-color: var(--background-color-medium);
overflow-y: auto;
max-height: 100%;
}
.sidebar_left .item{
position: relative;
display:block;
background-color: rgba(255, 255, 255, 0.2);
background-color: var(--background-color-medium);
background-image: url(images/sprites.png);
background-repeat: no-repeat;
background-color: var(--area-background-color);
height: 25px;
margin: 5px 0 5px 0;
width: 30px;
margin: 5px 0 0 5px;
overflow: hidden;
cursor: pointer;
/*filter: grayscale(1);*/
}
.sidebar_left .item:after{
position: absolute;
content: '';
left:0;
top:0;
bottom:0;
right:0;
filter: var(--menu-icons-filter);
background-position: center center;
background-repeat: no-repeat;
background-size: 20px 20px;
}
.sidebar_left .item:hover{
background-color: rgba(255, 255, 255, 0.5);
background-color: var(--background-color-lightest);
background-color: var(--background-color-hover);
}
.sidebar_left .item.active{
background-color: #419147;
background-color: var(--background-color-active);
color: var(--text-color-active);
}
.sidebar_left .item.active:after{
filter: var(--menu-icons-filter-active);
}
.sidebar_left .select{ background-position: -342px 2px; }
.sidebar_left .selection{ background-position: -43px -47px; }
.sidebar_left .magic_wand{ background-position: -294px -48px; }
.sidebar_left .brush{ background-position: 5px 3px; }
.sidebar_left .erase{ background-position: -444px 3px; }
.sidebar_left .fill{ background-position: -145px 2px; }
.sidebar_left .pick_color{ background-position: -644px 3px; }
.sidebar_left .pencil{ background-position: -594px 3px; }
.sidebar_left .line{ background-position: -193px -46px; }
.sidebar_left .text{ background-position: -394px 4px; }
.sidebar_left .rectangle{ background-position: -94px -45px; }
.sidebar_left .circle{ background-position: -547px 2px; }
.sidebar_left .blur{ background-position: -41px 2px; }
.sidebar_left .sharpen{ background-position: 6px -47px; }
.sidebar_left .desaturate{ background-position: -195px 3px; }
.sidebar_left .bulge_pinch{ background-position: -93px 5px; }
.sidebar_left .clone{ background-position: -493px 2px; }
.sidebar_left .gradient{ background-position: -243px 5px; }
.sidebar_left .crop{ background-position: -294px 3px; }
.sidebar_left .animation{ background-position: -244px -47px; }
.sidebar_left .media{ background-position: -145px -47px; }
/*
IMPORTANT: any new icon should also must be added on /service-worker.js + its version should be updated - FEATURE DISABLED
*/
.sidebar_left .select:after{ background-image: url('images/icons/select.svg'); }
.sidebar_left .selection:after{ background-image: url('images/icons/selection.svg'); }
.sidebar_left .brush:after{ background-image: url('images/icons/brush.svg'); }
.sidebar_left .pencil:after{ background-image: url('images/icons/pencil.svg'); }
.sidebar_left .pick_color:after{ background-image: url('images/icons/pick_color.svg'); }
.sidebar_left .erase:after{ background-image: url('images/icons/erase.svg'); }
.sidebar_left .magic_erase:after{ background-image: url('images/icons/magic_erase.svg'); }
.sidebar_left .fill:after{ background-image: url('images/icons/fill.svg'); }
.sidebar_left .media:after{ background-image: url('images/icons/media.svg'); }
.sidebar_left .shape:after{ background-image: url('images/icons/shape.svg'); }
.sidebar_left .text:after{ background-image: url('images/icons/text.svg'); background-size: 16px auto; }
.sidebar_left .gradient:after{ background-image: url('images/icons/gradient.png'); background-size: 18px 12px; filter: none; }
.sidebar_left .clone:after{ background-image: url('images/icons/clone.svg'); }
.sidebar_left .crop:after{ background-image: url('images/icons/crop.svg'); }
.sidebar_left .blur:after{ background-image: url('images/icons/blur.svg'); }
.sidebar_left .sharpen:after{ background-image: url('images/icons/sharpen.svg'); }
.sidebar_left .desaturate:after{ background-image: url('images/icons/desaturate.svg'); }
.sidebar_left .bulge_pinch:after{ background-image: url('images/icons/bulge_pinch.svg'); }
.sidebar_left .animation:after{ background-image: url('images/icons/animation.svg'); }
@media screen and (max-width:550px){
#sidebar_left{
@ -256,31 +331,39 @@
/* ========== right sidebar ================================================= */
.sidebar_right{
position: absolute;
-ms-grid-row: 2;
-ms-grid-column: 3;
grid-area: sidebar_right;
z-index: 2;
display: flex;
flex-direction: column;
right: 5px;
top: 45px;
width: 200px;
height: calc(100vh - 80px);
background-color: #424F5A;
background-color: var(--background-color);
transition: 0.2s;
overflow-x: hidden;
overflow-y: scroll;
margin: 0 5px;
width: 200px;
}
.sidebar_right.active{
right:0 !important;
right: 0 !important;
}
.sidebar_right .block.layers{
flex: 1;
overflow-y: auto;
}
.sidebar_right .block.layers .content{
padding-bottom: 25px;
}
/* preview */
.canvas_preview_wrapper{
position:relative;
height:100px;
margin-bottom:10px;
margin: 5px 5px 10px 5px;
}
.canvas_preview_details{
padding: 0 5px;
}
.canvas_preview_details button{
margin: 0;
}
.preview canvas{
cursor: pointer;
@ -292,46 +375,10 @@
/* color */
.color_area{
border: 1px solid #444;
width: 100%;
width: calc(100% - 10px);
height: 40px;
cursor: pointer;
}
.colors .content{
margin-top: 10px;
}
.main_color_alt{
border:1px solid #393939;
margin-top:10px;
width:100%;
height:40px;
}
.main_color_rgb{
margin-top:10px;
}
.main_color_rgb div{
display: inline-block;
width: calc(50% - 3px);
vertical-align: top;
}
.main_color_rgb span, .hex{
display: inline-block;
font-weight: bold;
width: 35px;
}
.main_color_rgb input{
width:50px;
}
.main_color_rgb .red{ color:#aa0000; }
.main_color_rgb .green{ color:#00aa00; }
.main_color_rgb .blue{ color:#0000aa; }
.main_color_rgb .alpha{ color: #333333; }
.color_hex{
width: calc(100% - 41px);
}
#all_colors{
margin-top:10px;
padding:3px 0px 3px 3px;
margin: 5px;
}
/* layers */
@ -343,19 +390,21 @@
float:right;
margin-left:5px;
padding:1px 8px;
background-color: rgba(255, 255, 255, 0.2);
background-color: var(--background-color-medium);
border:1px solid #444;
border-color: var(--border-color);
text-decoration:none;
color:#000000;
color:var(--text-color);
font-size:12px;
}
.layer_add{
display:inline-block;
padding:1px 8px;
margin-right: 10px;
background-color: #419147;
background-color: var(--background-color-active);
border:1px solid #444;
border-color: var(--border-color);
color: var(--text-color-active);
cursor:pointer;
text-decoration:none;
}
@ -366,29 +415,69 @@
display:block;
padding:1px 5px 3px 5px;
height:19px;
width: calc(100% - 44px);
text-align: left;
overflow:hidden;
background-color:#989898;
background-color: var(--area-background-color);
border:1px solid #393939;
border-color: var(--border-color);
border-radius:3px;
cursor:pointer;
overflow:hidden;
font-size: 12px;
color:#333333;
color:var(--text-color);
white-space: nowrap;
}
.layers_list .item.shorter .layer_name{
width: calc(100% - 63px);
}
.layers_list .item.active .layer_name{
background-color: #419147;
background-color: var(--background-color-active);
color: var(--text-color-active);
}
.layers_list .arrow_down{
position: relative;
float:left;
margin-right: 5px;
width:10px;
height:19px;
opacity: 0.4;
}
.layers_list .arrow_down:after{
position: absolute;
content: '';
left:0;
top:0;
bottom:0;
right:0;
filter: var(--menu-icons-filter);
background: url('images/icons/arrow-down.svg') no-repeat center center;
background-size: 12px auto;
}
.layers_list .visibility{
position: relative;
float:left;
cursor:pointer;
padding:0px 3px 0px 3px;
margin-right: 5px;
width:20px;
height:19px;
background: url('images/sprites.png') no-repeat -148px -99px;
opacity:0.1;
border: none;
background: transparent;
box-shadow: none;
}
.layers_list .visibility:after{
position: absolute;
content: '';
left:0;
top:0;
bottom:0;
right:0;
filter: var(--menu-icons-filter);
background: url('images/icons/view.svg') no-repeat center center;
background-size: 18px auto;
}
.layers_list .visible{ opacity:0.4; }
.layers_list .delete{
@ -398,7 +487,10 @@
width:12px;
height:19px;
margin-left: 5px;
background: url('images/sprites.png') no-repeat -100px -96px;
background: transparent url(images/icons/delete.svg) no-repeat center center;
background-size: 10px 10px;
border: none;
box-shadow: none;
}
/* filters */
.layers_list .filters{
@ -420,74 +512,150 @@
bottom:0;
width: 20px;
}
.sidebar_right .label{
display: inline-block;
width: 60px;
}
.sidebar_right button.extra{
border: 1px solid #444;
background-color: var(--background-color-medium);
}
.info .toggle.toggled{
margin-bottom: -3px;
}
.toggle-full.toggle.toggled{
margin-bottom: -3px;
}
.block.details .row{
clear:both;
margin-bottom: 2px;
margin-bottom: 4px;
min-height: 23px;
}
.block.details input{
.block.details input[type="number"]{
width: 70px;
padding: 3px 5px;
float: right;
}
.block.details .ui_color_input{
width: 70px;
float: right;
}
.block.details .ui_color_input input{
width: 100%;
height: 23px;
}
.block.details button.ui_toggle_button{
width: 90px;
float: right;
}
.block.details select{
width: calc(100% - 70px);
height: 23px;
float: right;
}
.block.details button{
width: calc(100% - 70px);
height: 23px;
border: 1px solid #444;
background-color: var(--background-color-medium);
}
.block.details button.reset{
position: relative;
width: 25px;
float: right;
margin-right: 3px;
overflow: hidden;
opacity: 0.3;
background-image: url(images/sprites.png);
background-repeat: no-repeat;
background-position: -747px 2px;
opacity: 0.5;
color: transparent;
}
.block.details button.reset:after{
position: absolute;
content: '';
left:0;
top:0;
bottom:0;
right:0;
background: url(images/icons/refresh.svg) no-repeat center center;
background-size: auto 14px;
filter: var(--menu-icons-filter);
}
.block.details button.active{
background-color: var(--background-color-active);
background-color: var(--background-color-active);
color: var(--text-color-active);
}
.details-content{
height: 206px;
overflow-y: auto;
}
@media screen and (max-width:700px){
body{
padding-top:50px;
}
.wrapper{
top: 50px;
}
.sidebar_left{
position: absolute;
left: -90px;
background: var(--background);
}
.sidebar_left.active{
box-shadow: -5px 0px 10px 0px rgba(0,0,0,0.75);
left: 0;
z-index: 3;
}
.sidebar_right{
right: -200px;
position: absolute;
height: 100%;
right: -210px;
background: var(--background);
}
.sidebar_right.active{
box-shadow: -5px 0px 10px 0px rgba(0,0,0,0.75);
right: 0;
margin-right: 0;
}
}
/* ========== content ======================================================= */
.ruler_left{
display: none;
position: absolute;
left:0;
top: 20px;
background-color: #ccc;
}
.ruler_top{
display: none;
position: absolute;
left: 20px;
top:0;
background-color: #ccc;
}
.middle_area{
position: relative;
-ms-grid-row: 2;
-ms-grid-column: 2;
grid-area: main;
}
.main_wrapper{
height: calc(100vh - 80px);
margin: 5px 210px 5px 45px;
position:absolute;
top:0;
right:0;
bottom:0;
left:0;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
.middle_area.has-ruler .main_wrapper{
top: 20px;
left: 20px;
}
.canvas_wrapper{
position:relative;
}
.canvas_wrapper canvas{
position: absolute;
border: 1px solid #393939;
box-sizing: content-box;
font-kerning: normal !important;
}
.loaded .canvas_wrapper canvas{
border: 1px solid var(--border-color);
}
#mouse{
position:absolute;
@ -508,16 +676,10 @@
height: 100%;
position: absolute;
pointer-events: none;
/*background: url(images/grid.png) repeat top left;*/
/*background: url(images/icons/grid.png) repeat top left;*/
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAQElEQVQ4T2N89+7dfwYigKCgIBGqGBgYRw3EGU6jYYgzaIZAsvn//z9ROeX9+/fE5ZRRA3GG02gY4s4pgz7ZAAAnSWvHPkHXaAAAAABJRU5ErkJggg==') repeat top left;
z-index:1;
/* disable antialiasing */
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: -o-crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
image-rendering: pixelated; /* disable antialiasing */
}
.transparent-grid.white{
background:white;
@ -541,7 +703,7 @@ canvas{
pointer-events:none;
}
.group{
border:1px solid #888888;
border:1px solid #999999;
margin: 5px 0px 5px 0px;
padding:5px 8px;
}
@ -558,17 +720,50 @@ canvas{
height: 0;
border: none;
}
@media screen and (max-width:700px){
body{
padding-top:50px;
}
.main_wrapper{
margin-right: 5px;
}
.alertify-notifier{
color: black;
}
.effectsPreview{
cursor: pointer;
background-color: #ddd;
}
@media screen and (max-width:550px){
.canvas_wrapper{
margin-left: 0px;
}
}
@media screen and (max-height: 690px){
.sidebar_left{
width: 75px;
}
}
@media screen and (max-height:450px){
.sidebar_left{
width: 88px;
}
}
/* ========== dialogs ======================================================= */
#dialog_color_picker_group {
width: 60%;
}
#dialog_color_channel_group {
width: 40%;
margin-left: 1rem;
}
@media screen and (max-width: 450px) {
#dialog_color_picker .ui_flex_group {
flex-wrap: wrap;
}
#dialog_color_picker_group {
width: 100%;
}
#dialog_color_channel_group {
width: 100%;
margin-left: 0;
margin-top: 1rem;
}
}

View File

@ -1,214 +1,202 @@
.mobile_menu{
display:none;
position: absolute;
width:100%;
top: 0;
:root {
--menu-dropdown-background-color: #ffffff;
--menu-dropdown-border-color: #49844d;
--menu-dropdown-text-color: #2d2b2b;
--menu-dropdown-text-muted-color: #aaaaaa;
--menu-dropdown-hover-background-color: #adecab;
--menu-dropdown-hover-text-color: #2d2d2d;
--menu-dropdown-divider-color: #e5e5e5;
}
.left_mobile_menu, .right_mobile_menu{
position:absolute;
width:50px;
height:50px;
background: url("images/sprites.png") no-repeat 11px -86px;
filter: invert(1);
display:block;
top:0;
z-index:200;
border:0;
outline:0;
cursor: pointer;
}
.left_mobile_menu{left:0;}
.right_mobile_menu{right:0;}
.ddsmoothmenu{
position:fixed;
top:0;
left:0;
width:100%;
font:12px Arial,sans-serif;
background: #2D2D2D;
width: 100%;
padding-left:10px;
z-index:100;
}
.ddsmoothmenu ul{
z-index:100;
margin: 0;
.sr_only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
list-style-type: none;
height:30px;
}
.ddsmoothmenu ul li{
position: relative;
display: inline-block;
float: left;
color: #2d2b2b;
height:100%;
}
.ddsmoothmenu ul ul li a{
width:100%;
}
.ddsmoothmenu .rightarrowclass{
display:none !important;
}
.ddsmoothmenu ul li a{
display: inline-block;
color: #2D2D2D;
text-decoration: none;
color: #cccccc;
text-align:center;
padding: 7px 10px 8px 10px !important;
}
.ddsmoothmenu ul ul li a{
padding-right: 25px !important;
}
.ddsmoothmenu ul li a.selected{
background-color: #FFFFFF !important;
color: #2d2b2b;
}
.ddsmoothmenu ul li ul li a.selected{
background-color:#E4EBF8 !important;
}
.ddsmoothmenu ul li a:hover{
background-color: #E4EBF8;
color: #2D2D2D;
}
.ddsmoothmenu .hide_ul{
position: absolute;
left: -3000px;
display: none;
visibility: hidden;
border:1px solid #5680C1;
border-top:0px;
}
.ddsmoothmenu ul li ul{
position: absolute;
left: -3000px;
display: none;
visibility: hidden;
border:1px solid #5680C1;
border-top:0px;
margin-left: -1px;
height:auto;
min-width:140px;
width:auto !important;
top:30px !important;
}
.ddsmoothmenu ul li ul li{
display: list-item;
background: #ffffff;
float: none;
height:auto;
width:100%;
}
.ddsmoothmenu ul li ul li a{
text-align:left;
}
.ddsmoothmenu ul li ul li ul{
top: 0;
border-top:1px solid #5680C1;
}
.ddsmoothmenu ul li ul li a{
padding-left: 5px;
padding-right:5px;
margin: 0;
color: #2D2D2D;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.ddsmoothmenu ul li ul li ul{
top:0 !important;
}
.ddsmoothmenu .downarrowclass{
position: absolute;
top: 12px;
right: 7px;
}
.ddsmoothmenu .ddshadow{
position: absolute;
left: 0;
.main_menu {
position: fixed;
top: 0;
width: 0;
height: 0;
background-color: #ccc;
left: 0;
right: 0;
z-index: 100;
}
.ddsmoothmenu .mid-line{
background-color:#ff0000;
border-top:1px solid #e5e5e5;
font-size:0;
padding:0 8px 0 8px;
.main_menu > ul.menu_bar {
display: flex;
flex-direction: row;
list-style: none;
padding: 0;
margin: 0;
height: 30px;
padding-left: 10px;
background: var(--menu-background-color);
}
.ddsmoothmenu ul li ul li.more > a{
position:relative;
.main_menu > ul.menu_bar > li {
padding: 0;
overflow: hidden;
height: 100%;
}
.ddsmoothmenu ul li ul li.more > a:before{
.main_menu > ul.menu_bar > li > a {
display: flex;
align-items: center;
font-size: 12px;
color: var(--menu-text-color);
text-decoration: none;
padding: 0 10px;
height: 100%;
}
.main_menu > ul.menu_bar > li > a::-moz-focus-inner {
border: 0;
}
.main_menu > ul.menu_bar > li > a:focus {
outline: none;
box-shadow: 0 -3px var(--menu-dropdown-background-color) inset;
}
.main_menu > ul.menu_bar > li > a:hover {
background: var(--menu-dropdown-hover-background-color);
box-shadow: none;
color: var(--menu-dropdown-hover-text-color);
}
.main_menu > ul.menu_bar > li > a[aria-expanded="true"] {
background: var(--menu-dropdown-background-color);
box-shadow: none;
color: var(--menu-dropdown-text-color);
}
.main_menu > ul.menu_bar > li > a > * {
pointer-events: none;
}
.main_menu > ul.menu_dropdown {
display: flex;
flex-direction: column;
position: fixed;
top: 0;
left: 0;
list-style: none;
padding: 0;
margin: 0;
overflow-x: hidden;
overflow-y: auto;
min-width: 150px;
box-shadow: 0 0 0 1px var(--menu-dropdown-border-color);
background: var(--menu-dropdown-background-color);
}
.main_menu > ul.menu_dropdown > li {
padding: 0;
}
.main_menu > ul.menu_dropdown > li > hr {
background: none;
border: 1px solid var(--menu-dropdown-divider-color);
border-bottom: none;
margin: 0;
}
.main_menu > ul.menu_dropdown > li > a {
display: flex;
flex-direction: row;
align-items: center;
position: relative;
height: 30px;
padding: 0 10px;
font-size: 12px;
line-height: 30px;
text-decoration: none;
color: var(--menu-dropdown-text-color);
}
.main_menu > ul.menu_dropdown > li > ::-moz-focus-inner {
border: 0;
}
.main_menu > ul.menu_dropdown > li > a:focus {
outline: none;
box-shadow: 0 0 0 2px var(--menu-dropdown-hover-background-color) inset;
}
.main_menu > ul.menu_dropdown > li > a:hover {
background: var(--menu-dropdown-hover-background-color);
box-shadow: none;
color: var(--menu-dropdown-hover-text-color);
}
.main_menu > ul.menu_dropdown > li > a[aria-expanded="true"] {
background: var(--menu-dropdown-hover-background-color);
box-shadow: none;
color: var(--menu-dropdown-hover-text-color);
}
.main_menu > ul.menu_dropdown > li > a[aria-haspopup="true"]::after {
position: absolute;
content:">";
content: ">";
right: 9px;
width: 5px;
height: 14px;
transform: scaleY(2);
color: #808080;
}
.ddsmoothmenu ul li ul li ul{
left: calc(100% + 1px) !important;
.main_menu > ul.menu_dropdown > li > a[aria-haspopup="true"] > .name {
margin-right: 8px;
}
.ddsmoothmenu .dots::after{
content: " ...";
.main_menu > ul.menu_dropdown > li > a[target="_blank"]::after {
content: "";
width: 10px;
height: 10px;
margin-left: 5px;
background: url('images/icons/external.png') no-repeat center center;
background-size: auto 8px;
opacity: 0.3;
}
.ddsmoothmenu a[data-key]:after{
position: absolute;
content: attr(data-key) " ";
color: #aaa;
font-size: 12px;
margin-left: 8px;
right:10px;
.main_menu > ul.menu_dropdown > li > a > * {
pointer-events: none;
}
.main_menu > ul.menu_dropdown > li > a > .name {
flex-grow: 1;
overflow: hidden;
white-space: nowrap;
}
.main_menu > ul.menu_dropdown > li > a > .shortcut {
flex-shrink: 1;
color: var(--menu-dropdown-text-muted-color);
}
@media screen and (max-width:700px){
.mobile_menu{
display:block;
}
.left_mobile_menu{
display:none;
}
.ddsmoothmenu{
height:50px;
}
.ddsmoothmenu ul{
width: calc(100% - 50px);
height:50px;
}
.ddsmoothmenu > ul > li > a{
height:50px;
padding-top: 15px !important;
}
.ddsmoothmenu ul li ul{
top:50px !important;
}
.ddsmoothmenu ul li ul li{
height:auto;
}
.ddsmoothmenu ul li ul li a{
height:30px;
}
.mobile_menu {
display: none;
position: absolute;
width: 100%;
top: 0;
}
@media screen and (max-width:550px){
.ddsmoothmenu{
padding-left:0;
}
.ddsmoothmenu ul{
width: calc(100% - 50px);
}
.ddsmoothmenu > ul > li{
width: calc(100% / 7);
}
.ddsmoothmenu > ul > li > a{
width:100%;
padding-left: 3px !important;
padding-right: 3px !important;
overflow: hidden;
}
.left_mobile_menu{
display:block;
}
.left_mobile_menu, .right_mobile_menu {
position: absolute;
width: 50px;
height: 50px;
display: block;
top: 0;
z-index: 200;
border: 0;
outline: 0;
cursor: pointer;
background-color: transparent;
}
.left_mobile_menu:after, .right_mobile_menu:after {
position: absolute;
content: '';
left:0;
top:0;
bottom:0;
right:0;
filter: var(--mobile-menu-toggle-filter);
background: url('images/icons/menu.svg') no-repeat center center;
background-size: auto 26px;
}
.left_mobile_menu { left:0; }
.right_mobile_menu { right:0; }
@media screen and (max-width:700px) {
.mobile_menu {
display: block;
}
.main_menu > ul.menu_bar {
height: 50px;
padding-left: 50px;
padding-right: 50px;
}
}

View File

@ -1,101 +1,271 @@
#popup{
#popups:not(:empty) {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#popups .popup {
position:fixed;
display:none;
top: 20vh;
left: calc(50% - 500px / 2);
top: 15vh;
left: calc(100vw / 2);
transform: translate(-50%, 0);
background-color: #7A838B;
background-color: var(--block-background-color);
border: 1px solid rgba(0, 0, 0, 0.5);
border: 1px solid var(--background-color-border);
width:500px;
max-width: 100%;
border: 1px solid var(--border-color);
width: 90vw;
max-width: 500px;
max-height: calc(80vh);
margin:0px auto 0px auto;
padding:10px;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
padding: 4rem 0 5rem 0;
box-shadow: 0 0 0 4000px rgba(0,0,0,0.3), 0 0 20px rgba(0,0,0,0.5);
z-index: 100;
overflow-y: auto;
font-size: 13px;
overflow-y: scroll;
overflow: hidden;
}
#popup.wide{
top: 15vh;
width: 800px;
left: calc(50% - 800px / 2);
#popups .popup.wide{
max-width: 840px;
}
#popup a{
color: #000080;
#popups .popup a{
color: var(--link-color);
}
#popup h2{
margin: -10px -10px 5px -10px;
padding: 6px 10px;
font-size: 18px;
#popups .popup h2{
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
margin: 0;
height: 4rem;
line-height: 4rem;
padding: 0 1rem;
font-size: 1.8rem;
background-color: rgba(255, 255, 255, 0.3);
background-color: var(--background-color-light);
/*cursor:move;*/
background-color: var(--header-background-color);
z-index: 0;
cursor:move;
}
#popup .buttons{
text-align:center;
margin-top:20px;
margin-bottom:5px;
#popups .popup .dialog_content {
overflow-y: auto;
max-height: calc(80vh - 11rem);
padding: 1rem;
}
#popup td, #popup th{
#popups .popup .buttons{
position: absolute;
background-color: var(--block-background-color);
bottom: 0;
left: 0;
right: 0;
height: 5rem;
line-height: 4rem;
margin: 0;
padding: .5rem 0;
text-align: center;
border-top: 1px solid var(--header-background-color);
z-index: 3;
}
#popups .popup .close{
position: absolute;
right: 0;
top: 0;
min-width: 0;
padding: 5px;
line-height: 0.5;
font-size: 16px;
margin-top: 10px;
margin-right: 10px;
border: none;
background: none;
z-index: 1;
}
#popups .popup input[type="range"]{
margin:0;
width: 100%;
}
#popups .popup table{
box-sizing: border-box;
width: 100%;
}
#popups .popup td, #popups .popup th{
height: 25px;
}
#popup td{
#popups .popup td{
vertical-align: middle;
}
#popup th{
#popups .popup th{
text-align:left;
padding: 5px 5px 5px 0;
width: 130px;
}
#popup textarea{
color:#000000;
#popups .popup textarea{
color: var(--input-text-color);
width:100%;
border:1px solid #393939;
padding-left:5px;
}
#popup .button{
#popups .popup .button{
margin: 0 3px;
background-color: rgba(255, 255, 255, 0.2);
background-color: var(--background-color-medium);
background-color: var(--button-background-color);
min-width:60px;
border:1px solid rgba(0, 0, 0, 0.5);
border:1px solid var(--background-color-border);
border:1px solid var(--border-color);
padding: 5px 10px;
}
#popup input[type="text"], #popup input[type="number"], #popup textarea{
#popups .popup input[type="text"], #popups .popup input[type="number"], #popups .popup textarea{
width:100%;
}
#popup input[type="number"]{
#popups .popup input[type="number"]{
width:100px;
}
#popup input[type="radio"], #popup input[type="checkbox"]{
#popups .popup input[type="radio"], #popups .popup input[type="checkbox"]{
margin-left: 0;
}
#popup label span{
color:#444444;
#popups .popup label span{
color:var(--text-color-muted);
}
#popup .checkbox label{
#popups .popup .checkbox label{
margin-top: 5px;
color:#444444;
color:var(--text-color-muted);
}
@media screen and (max-width:500px){
#popup{
left: 0;
width: 100%;
}
#canvas_preview_container{
clear:both;
}
#popups .popup .preview_container{
margin-top:10px;
margin-bottom:15px;
text-align: center;
}
@media screen and (max-height:650px){
#popup{
top: 0;
max-height: 100vh;
}
#canvas_preview_container{
clear:both;
}
#popups .popup .preview_canvas_left{
position:relative;
margin:0 5px 5px 0;
border:1px solid #393939;
display: inline-block;
vertical-align: top;
}
#popups .popup .preview_canvas_post_back{
position:absolute;
border:1px solid #393939;
background-color:#ffffff;
}
#popups .popup .preview_canvas_post{
position:relative;
border:1px solid #393939;
}
#popups .popup .canvas_preview_container{
position:relative;
display: inline-block;
vertical-align: top;
}
#popups .popup .radios label{
display: inline-block;
margin-right: 10px;
}
#popups .popup .range_value{
padding-left:10px;
width:50px;
}
#popups .popup .long_text_value{
font-size: 12px;
}
#popups .popup .preview-item-title{
text-align: center;
max-width: 150px;
}
#popups .popup .field_comment{
display: inline-block;
margin-left: 10px;
opacity: 0.5;
}
#popups .popup .selection_card {
background: var(--input-background-color);
display: block;
width: 100%;
padding: 0;
border-bottom: 0.1rem solid var(--input-border-color);
overflow: hidden;
position: relative;
}
#popups .popup .selection_card:first-child {
margin-top: 1rem;
border-radius: var(--input-border-radius) var(--input-border-radius) 0 0;
}
#popups .popup .selection_card:last-child {
border-radius: 0 0 var(--input-border-radius) var(--input-border-radius);
border-bottom: none;
}
#popups .popup .selection_card > input[type="checkbox"] {
flex-grow: 0;
flex-shrink: 0;
margin: 0;
cursor: pointer;
position: absolute;
top: 50%;
left: 1.5rem;
transform: translateY(-50%) scale(1.5);
}
#popups .popup .selection_card > input[type="checkbox"] + label {
display: block;
width: 100%;
flex-grow: 1;
flex-shrink: 1;
margin: 0;
padding: 1rem 0.5rem 1rem 5.5rem;
cursor: pointer;
}
#popups .popup .selection_card > input[type="checkbox"] + label:hover {
background: var(--input-background-color-hover);
}
#popups .popup .selection_card .font_preview {
font-size: 1.6rem;
height: 2.5rem;
line-height: 2.5rem;
white-space: nowrap;
}
#popups .popup .pagination {
display: flex;
text-align: center;
margin: 1rem 0 0 0;
}
#popups .popup .pagination button {
flex-grow: 0;
height: 2.8rem;
line-height: 2.8rem;
border-radius: 0;
margin-left: -1px;
min-width: 3.3rem;
}
#popups .popup .pagination button:first-child {
border-radius: var(--button-border-radius) 0 0 var(--button-border-radius);
margin-left: auto;
}
#popups .popup .pagination button:last-child {
border-radius: 0 var(--button-border-radius) var(--button-border-radius) 0;
margin-right: auto;
}
@media screen and (max-width:500px){
#popups .popup {
max-height: calc(80vh - 20px); /* mobile phones has bottom menu */
}
#popups .popup tr{
display: block;
margin-bottom: 10px;
}
#popups .popup td, #popups .popup th{
display: block;
width: 100%;
height: auto;
padding: 5px;
}
#popups .popup th{
padding: 5px 5px 0px 5px;
}
#popups .popup td{
padding: 5px 5px 5px 5px;
}
#popups .popup .range_value{
display: none;
}
}

View File

@ -13,7 +13,7 @@
.sidebar_left,
.sidebar_right,
.submenu,
.ddsmoothmenu{
.main_menu{
display: none;
height: 0;
width: 0;
@ -31,4 +31,4 @@
.canvas_wrapper canvas{
border:0;
}
}
}

View File

@ -1,26 +1,131 @@
:root {
/* original - default */
--background: #666d6f;
--text-color: #f4f3f3;
--text-color-muted: #c1c1c1;
--text-color-red: #e38282;
--text-color-green: #8bdb8b;
--text-color-blue: #a4a4ff;
--link-color: #9ffda5;
--section-background-color: #323a3c;
--area-background-color: #464d4f;
--block-background-color: #464d4f;
--header-background-color: #373d3f;
--button-background-color: #2f3739;
--button-background-color-hover: #75df72;
--button-background-color-active: #4d5153;
--button-shadow-color: rgba(0, 0, 0, 0.3);
--button-text-color-active: #adecab;
--button-border-radius: .4rem;
--button-toggle-background-color: #575f62;
--button-toggle-background-color-hover: #575f62;
--input-background-color: #2f3739;
--input-background-color-hover: #383f44;
--input-text-color: #f4f3f3;
--input-border-color: #0f0f0f;
--input-border-color-active: #70996e;
--input-border-radius: .4rem;
--input-group-border-color: #323a3c;
--menu-background-color: #222;
--menu-icons-filter: invert(1);
--menu-icons-filter-active: none;
--menu-text-color: #cccccc;
--number-input-arrow-width: 2rem;
--background-color-active: #adecab;
--background-color-hover: #575f62;
--text-color-active: #215b2a;
--border-color: #727677;
--scrollbar-track-color: #464d4f;
--scrollbar-thumb-color: #2f3739;
--mobile-menu-toggle-filter: invert(1);
}
body.theme-light{
/* light */
--background: #f9f9fa;
--text-color: #0c0c0d;
--text-color-muted: #444444;
--text-color-red: #bb2424;
--text-color-green: #2b882b;
--text-color-blue: #5454ca;
--link-color: #000080;
--section-background-color: #eaeaea;
--area-background-color: #d9d9d9;
--block-background-color: #eaeaea;
--header-background-color: #dbdbdb;
--button-background-color: #f9f9fa;
--button-background-color-hover: #ddd;
--button-background-color-active: #f3f3f3;
--button-text-color-active: #59aed8;
--button-shadow-color: rgba(0, 0, 0, 0.1);
--button-toggle-background-color: #b7b7b7;
--button-toggle-background-color-hover: #b7b7b7;
--input-background-color: #ffffff;
--input-background-color-hover: #ddd;
--input-text-color: #0c0c0d;
--input-border-color: #ccc;
--input-border-color-active: #59aed8;
--input-group-border-color: #c4c4c4;
--menu-background-color: #eaeaea;
--menu-icons-filter: none;
--menu-icons-filter-active: invert(1);
--menu-text-color: #333333;
--menu-dropdown-hover-background-color: #a3dbf7;
--menu-dropdown-border-color: #15439b;
--background-color-active: #a3dbf7;
--background-color-hover: #c4c4c4;
--text-color-active: #15439b;
--border-color: #c1c1c1;
--scrollbar-track-color: #f9f9fa;
--scrollbar-thumb-color: #919090;
--mobile-menu-toggle-filter: none;
}
body.theme-green{
/* green */
--background: #050702;
--text-color: #acc3a9;
--text-color-muted: #80937d;
--link-color: #9ffda5;
--section-background-color: #1c2e04;
--area-background-color: #3b5f11;
--block-background-color: #3b5f11;
--header-background-color: #2b460f;
--button-background-color: #2e4a0d;
--button-background-color-hover: #58960e;
--button-background-color-active:#2b460f;
--button-text-color-active: #ccc;
--button-toggle-background-color: #243e05;
--button-toggle-background-color-hover: #243e05;
--input-background-color: #ffffff;
--input-background-color-hover: #ddd;
--input-text-color: #0c0c0d;
--input-border-color: #ccc;
--menu-background-color: #1c2e04;
--menu-icons-filter: invert(1);
--menu-icons-filter-active: none;
--menu-text-color: #acc3a9;
--background-color-active: #58960e;
--background-color-hover: #58960e;
--text-color-active: #acc3a9;
--border-color: #4d6b1e;
--scrollbar-track-color: #050702;
--scrollbar-thumb-color: #80937d;
--mobile-menu-toggle-filter: invert(1);
}
*{
box-sizing: border-box;
background-repeat: no-repeat;
}
:root {
/* default */
--background-color: #424F5A;
--background-color-medium: rgba(255, 255, 255, 0.2);
--background-color-light: rgba(255, 255, 255, 0.3);
--background-color-lightest: rgba(255, 255, 255, 0.5);
--background-color-border: rgba(0, 0, 0, 0.5);
--background-color-active: #419147;
--text-color: #000000;
html {
font-size: 10px; /* Base is 10px for easy REM calculation */
}
body{
margin: 0px;
padding: 0px;
padding-top: 30px;
margin: 0;
padding: 30px 0 0 0;
background-color: #424F5A;
background-color: var(--background-color);
font-size: 13px;
background: var(--background);
font-size: 1.3rem;
font-family: Arial, Helvetica, sans-serif;
color: #000000;
color: var(--text-color);
line-height: 1.4;
font-weight: normal;
@ -30,19 +135,9 @@ canvas{
outline: none;
/* disable select canvas */
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
/* disable antialiasing */
image-rendering: optimizeSpeed;
image-rendering: -moz-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: -o-crisp-edges;
image-rendering: pixelated;
-ms-interpolation-mode: nearest-neighbor;
}
img{
border: none;
@ -63,8 +158,11 @@ hr{
border-color: rgba(0,0,0,0.3);
border-bottom: 0;
}
input[type="text"], input[type="button"], select, input[type="number"], textarea{
border:1px solid #393939;
input[type="text"], select, input[type="number"], textarea{
background: var(--input-background-color);
border: 1px solid var(--input-border-color);
border-radius: var(--input-border-radius);
color: var(--input-text-color);
padding: 3px 5px;
font-size: 13px;
}
@ -75,17 +173,33 @@ select{
padding: 2px 4px;
}
input[type="range"]{
margin-left:0px;
margin-left: 0;
width:100%;
}
input[type="button"]{
background: #dddddd;
button, input[type="button"]{
border-radius: var(--button-border-radius);
box-shadow: 0 1px 2px 0 var(--button-shadow-color), 0 1px 0 0 rgba(255, 255, 255, 0.1) inset;
cursor: pointer;
border: 1px solid var(--border-color);
background-color: var(--button-background-color);
color: var(--text-color);
}
input[type="button"]:disabled{
button:hover, input[type="button"]:hover{
background-color: var(--button-background-color-hover);
}
button:disabled, input[type="button"]:disabled{
visibility:hidden;
}
button{
cursor: pointer;
button[aria-pressed="true"], input[type="button"][aria-pressed="true"]{
background-color: var(--button-background-color-active);
color: var(--button-text-color-active);
box-shadow: 0 1px 2px 0 var(--button-shadow-color), 0 1px 1px 1.5px rgba(58, 40, 40, 0.1) inset, 0 -1px 0 0 var(--button-text-color-active) inset;
}
button[aria-pressed="true"]:hover, input[type="button"][aria-pressed="true"]:hover{
background-color: var(--button-background-color-hover);
}
button.ui_toggle_button:hover{
background-color: var(--button-toggle-background-color-hover);
}
label{
display: inline-block;
@ -110,6 +224,7 @@ label{
@supports not (zoom:2) {
input[type="radio"], input[type=checkbox]{
transform: scale(1.5);
margin: 8px;
transform-origin: left center;
margin: 8px 12px 8px 0;
}
}
}

81
src/css/utility.css Normal file
View File

@ -0,0 +1,81 @@
/* Common input label sizes */
.label_width_character {
width: 100%;
max-width: 2.88rem;
overflow: hidden;
flex-shrink: 0;
}
.label_width_small {
width: 100%;
max-width: 6.4rem;
overflow: hidden;
}
.label_width_medium {
width: 100%;
max-width: 10.4rem;
overflow: hidden;
}
/* Font color utility */
.text_red { color: var(--text-color-red); }
.text_green { color: var(--text-color-green); }
.text_blue { color: var(--text-color-blue); }
.text_muted { color: var(--text-color-muted); }
/*
Size inputs based on the number of "w" characters that could fit in the input. "w" is usually the widest character.
This is a rough estimate since all characters vary in width. For example an input with numbers
usually fits way more characters than an input with letters.
"cw" means character width
*/
.input_cw_1, .input_cw_2, .input_cw_3, .input_cw_4, .input_cw_5,
.input_cw_6, .input_cw_7, .input_cw_8, .input_cw_9, .input_cw_10
.input_cw_11, .input_cw_12, .input_cw_13, .input_cw_14, .input_cw_15 {
width: 100%;
}
.input_cw_1 { max-width: 2.25rem; }
.input_cw_2 { max-width: 3.25rem; }
.input_cw_3 { max-width: 4.25rem; }
.input_cw_4 { max-width: 5.25rem; }
.input_cw_5 { max-width: 6.25rem; }
.input_cw_6 { max-width: 7.25rem; }
.input_cw_7 { max-width: 8.25rem; }
.input_cw_8 { max-width: 9.25rem; }
.input_cw_9 { max-width: 10.25rem; }
.input_cw_10 { max-width: 11.25rem; }
.input_cw_11 { max-width: 12.25rem; }
.input_cw_12 { max-width: 13.25rem; }
.input_cw_13 { max-width: 14.25rem; }
.input_cw_14 { max-width: 15.25rem; }
.input_cw_15 { max-width: 16.25rem; }
input[type="number"].input_cw_1 { max-width: 4.25rem; }
input[type="number"].input_cw_2 { max-width: 5.25rem; }
input[type="number"].input_cw_3 { max-width: 6.25rem; }
input[type="number"].input_cw_4 { max-width: 7.25rem; }
input[type="number"].input_cw_5 { max-width: 8.25rem; }
input[type="number"].input_cw_6 { max-width: 9.25rem; }
input[type="number"].input_cw_7 { max-width: 10.25rem; }
input[type="number"].input_cw_8 { max-width: 11.25rem; }
input[type="number"].input_cw_9 { max-width: 12.25rem; }
input[type="number"].input_cw_10 { max-width: 13.25rem; }
input[type="number"].input_cw_11 { max-width: 14.25rem; }
input[type="number"].input_cw_12 { max-width: 15.25rem; }
input[type="number"].input_cw_13 { max-width: 16.25rem; }
input[type="number"].input_cw_14 { max-width: 17.25rem; }
input[type="number"].input_cw_15 { max-width: 18.25rem; }
.ui_number_input.input_cw_1 { max-width: calc(2.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_2 { max-width: calc(3.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_3 { max-width: calc(4.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_4 { max-width: calc(5.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_5 { max-width: calc(6.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_6 { max-width: calc(7.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_7 { max-width: calc(8.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_8 { max-width: calc(9.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_9 { max-width: calc(10.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_10 { max-width: calc(11.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_11 { max-width: calc(12.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_12 { max-width: calc(13.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_13 { max-width: calc(14.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_14 { max-width: calc(15.25rem + var(--number-input-arrow-width)); }
.ui_number_input.input_cw_15 { max-width: calc(16.25rem + var(--number-input-arrow-width)); }

View File

@ -0,0 +1,5 @@
# Managing Undo History with Actions
More information on wiki page:
https://github.com/viliusle/miniPaint/wiki/Undo-Redo-system

View File

@ -0,0 +1,145 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
export class Activate_tool_action extends Base_action {
/**
* Groups multiple actions together in the undo/redo history, runs them all at once.
*/
constructor(key, ignore_same_tool) {
super('activate_tool', 'Activate Tool');
this.ignore_same_tool = !!ignore_same_tool;
this.key = key;
this.old_key = null;
this.tool_leave_actions = null;
this.tool_activate_actions = null;
}
async do() {
super.do();
const key = this.key;
this.old_key = app.GUI.GUI_tools.active_tool;
if (this.key !== this.old_key || this.ignore_same_tool) {
//reset last
document.querySelector('#tools_container .' + this.old_key).classList.remove("active");
//send exit event to old previous tool
if (config.TOOL.on_leave != undefined) {
var moduleKey = config.TOOL.name;
var functionName = config.TOOL.on_leave;
this.tool_leave_actions = app.GUI.GUI_tools.tools_modules[moduleKey].object[functionName]();
if (this.tool_leave_actions) {
for (let action of this.tool_leave_actions) {
await action.do();
}
}
}
//change active
app.GUI.GUI_tools.active_tool = key;
document.querySelector('#tools_container .' + app.GUI.GUI_tools.active_tool)
.classList.add("active");
for (let i in config.TOOLS) {
if (config.TOOLS[i].name == app.GUI.GUI_tools.active_tool) {
config.TOOL = config.TOOLS[i];
}
}
//check module
if (app.GUI.GUI_tools.tools_modules[key] == undefined) {
alertify.error('Tools class not found: ' + key);
return;
}
//set default cursor
const mainWrapper = document.getElementById('main_wrapper');
const defaultCursor = config.TOOL && config.TOOL.name === 'text' ? 'text' : 'default';
if (mainWrapper.style.cursor != defaultCursor) {
mainWrapper.style.cursor = defaultCursor;
}
app.GUI.GUI_tools.show_action_attributes();
app.GUI.GUI_tools.Helper.setCookie('active_tool', app.GUI.GUI_tools.active_tool);
}
//send activate event to new tool
if (config.TOOL.on_activate != undefined) {
var moduleKey = config.TOOL.name;
var functionName = config.TOOL.on_activate;
this.tool_activate_actions = app.GUI.GUI_tools.tools_modules[moduleKey].object[functionName]();
if (this.tool_activate_actions) {
for (let action of this.tool_activate_actions) {
await action.do();
}
}
}
config.need_render = true;
}
async undo() {
super.undo();
// Undo activate actions
if (this.tool_activate_actions) {
for (let action of this.tool_activate_actions) {
await action.undo();
action.free();
}
this.tool_activate_actions = null;
}
//reset last
document.querySelector('#tools_container .' + this.key)
.classList.remove("active");
//change active
app.GUI.GUI_tools.active_tool = this.old_key;
document.querySelector('#tools_container .' + app.GUI.GUI_tools.active_tool)
.classList.add("active");
for (let i in config.TOOLS) {
if (config.TOOLS[i].name == app.GUI.GUI_tools.active_tool) {
config.TOOL = config.TOOLS[i];
}
}
app.GUI.GUI_tools.show_action_attributes();
app.GUI.GUI_tools.Helper.setCookie('active_tool', app.GUI.GUI_tools.active_tool);
//set default cursor
const mainWrapper = document.getElementById('main_wrapper');
const defaultCursor = config.TOOL && config.TOOL.name === 'text' ? 'text' : 'default';
if (mainWrapper.style.cursor != defaultCursor) {
mainWrapper.style.cursor = defaultCursor;
}
// Undo leave actions
if (this.tool_leave_actions) {
for (let action of this.tool_leave_actions) {
await action.undo();
action.free();
}
this.tool_leave_actions = null;
}
config.need_render = true;
}
free() {
if (this.tool_activate_actions) {
for (let action of this.tool_activate_actions) {
action.free();
}
this.tool_activate_actions = null;
}
if (this.tool_leave_actions) {
for (let action of this.tool_leave_actions) {
action.free();
}
this.tool_leave_actions = null;
}
}
}

View File

@ -0,0 +1,67 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Add_layer_filter_action extends Base_action {
/**
* register new live filter
*
* @param {int} layer_id
* @param {string} name
* @param {object} params
*/
constructor(layer_id, name, params, filter_id) {
super('add_layer_filter', 'Add Layer Filter');
if (layer_id == null)
layer_id = config.layer.id;
this.layer_id = parseInt(layer_id);
this.name = name;
this.params = params;
this.filter_id = filter_id;
this.reference_layer = null;
}
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
var filter = {
id: this.filter_id,
name: this.name,
params: this.params,
};
if(this.filter_id) {
//update
for(var i in this.reference_layer.filters) {
if(this.reference_layer.filters[i].id == this.filter_id){
this.reference_layer.filters[i] = filter;
break;
}
}
}
else{
//insert
filter.id = Math.floor(Math.random() * 999999999) + 1; // A good UUID library would
this.reference_layer.filters.push(filter);
}
config.need_render = true;
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
if (this.reference_layer) {
this.reference_layer.filters.pop();
this.reference_layer = null;
}
config.need_render = true;
app.GUI.GUI_layers.render_layers();
}
free() {
this.reference_layer = null;
this.params = null;
}
}

View File

@ -0,0 +1,100 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
import Tools_settings_class from './../modules/tools/settings.js';
export class Autoresize_canvas_action extends Base_action {
/**
* autoresize canvas to layer size, based on dimensions, up - always, if 1 layer - down.
*
* @param {int} width
* @param {int} height
* @param {int} layer_id
* @param {boolean} can_automate
*/
constructor(width, height, layer_id, can_automate = true, ignore_same_size = false) {
super('autoresize_canvas', 'Auto-resize Canvas');
this.Tools_settings = new Tools_settings_class();
this.width = width;
this.height = height;
this.layer_id = layer_id;
this.can_automate = can_automate;
this.ignore_same_size = ignore_same_size;
this.old_config_width = null;
this.old_config_height = null;
}
async do() {
super.do();
const width = this.width;
const height = this.height;
const can_automate = this.can_automate;
let need_fit = false;
let new_config_width = config.WIDTH;
let new_config_height = config.HEIGHT;
var enable_autoresize = this.Tools_settings.get_setting('enable_autoresize');
if(enable_autoresize == false){
return;
}
// Resize up
if (width > new_config_width || height > new_config_height) {
const wrapper = document.getElementById('main_wrapper');
const page_w = wrapper.clientWidth;
const page_h = wrapper.clientHeight;
if (width > page_w || height > page_h) {
need_fit = true;
}
if (width > new_config_width)
new_config_width = parseInt(width);
if (height > new_config_height)
new_config_height = parseInt(height);
}
// Resize down
if (config.layers.length == 1 && can_automate !== false) {
if (width < new_config_width)
new_config_width = parseInt(width);
if (height < new_config_height)
new_config_height = parseInt(height);
}
if (new_config_width !== config.WIDTH || new_config_height !== height) {
this.old_config_width = config.WIDTH;
this.old_config_height = config.HEIGHT;
config.WIDTH = new_config_width;
config.HEIGHT = new_config_height;
app.GUI.prepare_canvas();
} else if (!this.ignore_same_size) {
throw new Error('Aborted - Resize not necessary')
}
// Fit zoom when after short pause
// @todo - remove setTimeout
if (need_fit == true) {
await new Promise((resolve) => {
window.setTimeout(() => {
app.GUI.GUI_preview.zoom_auto();
resolve();
}, 100);
});
}
}
async undo() {
super.undo();
if (this.old_config_width != null) {
config.WIDTH = this.old_config_width;
}
if (this.old_config_height != null) {
config.HEIGHT = this.old_config_height;
}
if (this.old_config_width != null || this.old_config_height != null) {
app.GUI.prepare_canvas();
}
this.old_config_width = null;
this.old_config_height = null;
}
}

19
src/js/actions/base.js Normal file
View File

@ -0,0 +1,19 @@
export class Base_action {
constructor(action_id, action_description) {
this.action_id = action_id;
this.action_description = action_description;
this.is_done = false;
this.memory_estimate = 0; // Estimate of how much memory will be freed when the free() method is called (in bytes)
this.database_estimate = 0; // Estimate of how much database space will be freed when the free() method is called (in bytes)
}
do() {
this.is_done = true;
}
undo() {
this.is_done = false;
}
free() {
// Override if need to run tasks to free memory when action is discarded from history
}
}

59
src/js/actions/bundle.js Normal file
View File

@ -0,0 +1,59 @@
import config from '../config.js';
import { Base_action } from './base.js';
export class Bundle_action extends Base_action {
/**
* Groups multiple actions together in the undo/redo history, runs them all at once.
*/
constructor(bundle_id, bundle_name, actions_to_do) {
super(bundle_id, bundle_name);
this.actions_to_do = actions_to_do;
}
async do() {
super.do();
let error = null;
let i = 0;
this.memory_estimate = 0;
this.database_estimate = 0;
for (i = 0; i < this.actions_to_do.length; i++) {
try {
await this.actions_to_do[i].do();
this.memory_estimate += this.actions_to_do[i].memory_estimate;
this.database_estimate += this.actions_to_do[i].database_estimate;
} catch (e) {
error = e;
break;
}
}
// One of the actions aborted, undo all previous actions.
if (error) {
for (i--; i >= 0; i--) {
await this.actions_to_do[i].undo();
}
throw error;
}
config.need_render = true;
}
async undo() {
super.undo();
this.memory_estimate = 0;
this.database_estimate = 0;
for (let i = this.actions_to_do.length - 1; i >= 0; i--) {
await this.actions_to_do[i].undo();
this.memory_estimate += this.actions_to_do[i].memory_estimate;
this.database_estimate += this.actions_to_do[i].database_estimate;
}
config.need_render = true;
}
free() {
if (this.actions_to_do) {
for (let action of this.actions_to_do) {
action.free();
}
this.actions_to_do = null;
}
}
}

View File

@ -0,0 +1,82 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Clear_layer_action extends Base_action {
/**
* clear layer data
*
* @param {int} layer_id
*/
constructor(layer_id) {
super('clear_layer', 'Clear Layer');
this.layer_id = parseInt(layer_id);
this.update_layer_action = null;
this.delete_layer_settings_action = null;
}
async do() {
super.do();
let layer = app.Layers.get_layer(this.layer_id);
if (!layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
let new_settings = {
x: 0,
y: 0,
width: 0,
height: 0,
visible: true,
opacity: 100,
composition: null,
rotate: 0,
data: null,
params: {},
status: null,
render_function: null,
type: null
};
if (layer.type == 'image') {
//clean image
new_settings.link = null;
}
this.update_layer_action = new app.Actions.Update_layer_action(this.layer_id, new_settings);
await this.update_layer_action.do();
let delete_setting_names = [];
for (let prop_name in layer) {
//remove private attributes
if (prop_name[0] == '_') {
delete_setting_names.push(prop_name);
}
}
if (delete_setting_names.length > 0) {
this.delete_layer_settings_action = new app.Actions.Delete_layer_settings_action(this.layer_id, delete_setting_names);
await this.delete_layer_settings_action.do();
}
}
async undo() {
super.undo();
if (this.delete_layer_settings_action) {
await this.delete_layer_settings_action.undo();
this.delete_layer_settings_action.free();
this.delete_layer_settings_action = null;
}
if (this.update_layer_action) {
await this.update_layer_action.undo();
this.update_layer_action.free();
this.update_layer_action = null;
}
}
free() {
if (this.update_layer_action) {
this.update_layer_action.free();
this.update_layer_action = null;
}
if (this.delete_layer_settings_action) {
this.delete_layer_settings_action.free();
this.delete_layer_settings_action = null;
}
}
}

View File

@ -0,0 +1,60 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Delete_layer_filter_action extends Base_action {
/**
* delete live filter
*
* @param {int} layer_id
* @param {string} filter_id
*/
constructor(layer_id, filter_id) {
super('delete_layer_filter', 'Delete Layer Filter');
if (layer_id == null)
layer_id = config.layer.id;
this.layer_id = parseInt(layer_id);
this.filter_id = filter_id;
this.reference_layer = null;
this.filter_remove_index = null;
this.old_filter = null;
}
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
this.old_filter = null;
for (let i in this.reference_layer.filters) {
if (this.reference_layer.filters[i].id == this.filter_id) {
this.filter_remove_index = i;
this.old_filter = this.reference_layer.filters.splice(i, 1)[0];
break;
}
}
if (!this.old_filter) {
throw new Error('Aborted - filter with specified id doesn\'t exist in layer');
}
config.need_render = true;
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
if (this.reference_layer && this.old_filter) {
this.reference_layer.filters.splice(this.filter_remove_index, 0, this.old_filter);
}
this.reference_layer = null;
this.old_filter = null;
this.filter_remove_index = null;
config.need_render = true;
app.GUI.GUI_layers.render_layers();
}
free() {
this.reference_layer = null;
this.old_filter = null;
}
}

View File

@ -0,0 +1,50 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Delete_layer_settings_action extends Base_action {
/**
* Deletes the specified settings in a layer
*
* @param {int} layer_id
* @param {array} setting_names
*/
constructor(layer_id, setting_names) {
super('delete_layer_settings', 'Delete Layer Settings');
this.layer_id = parseInt(layer_id);
this.setting_names = setting_names;
this.reference_layer = null;
this.old_settings = {};
}
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
for (let name in this.setting_names) {
this.old_settings[name] = this.reference_layer[name];
delete this.reference_layer[name];
}
config.need_render = true;
}
async undo() {
super.undo();
if (this.reference_layer) {
for (let i in this.old_settings) {
this.reference_layer[i] = this.old_settings[i];
}
this.old_settings = {};
}
this.reference_layer = null;
config.need_render = true;
}
free() {
this.setting_names = null;
this.reference_layer = null;
this.old_settings = null;
}
}

View File

@ -0,0 +1,115 @@
import config from '../config.js';
import app from './../app.js';
import { Base_action } from './base.js';
export class Delete_layer_action extends Base_action {
/**
* removes layer
*
* @param {int} id
* @param {boolean} force - Force to delete first layer?
*/
constructor(layer_id, force) {
super('delete_layer', 'Delete Layer');
this.layer_id = parseInt(layer_id);
this.force = force || false;
this.insert_layer_action = null;
this.select_layer_action = null;
this.delete_index = null;
this.deleted_layer = null;
}
async do() {
super.do();
const id = this.layer_id;
const force = this.force;
// Determine if there is a layer to delete, abort if not
for (var i in config.layers) {
if (config.layers[i].id == id) {
this.delete_index = i;
}
}
if (this.delete_index === null) {
throw new Error('Aborted - Layer to delete not found');
}
if (config.layers.length == 1 && (force == undefined || force == false)) {
// Only 1 layer left
if (config.layer.type == null) {
//STOP
throw new Error('Aborted - Will not delete last layer');
}
else {
// Delete it, but before that - create new empty layer
this.insert_layer_action = new app.Actions.Insert_layer_action();
this.insert_layer_action.do();
}
}
if (config.layers.length > 1 && config.layer.id == id) {
// Select next or previous layer
try {
const select_action = new app.Actions.Select_next_layer_action(id);
await select_action.do();
this.select_layer_action = select_action;
} catch (error) {
const select_action = new app.Actions.Select_previous_layer_action(id);
await select_action.do();
this.select_layer_action = select_action;
}
}
// Remove layer from list
this.deleted_layer = config.layers.splice(this.delete_index, 1)[0];
// Estimate memory
if (this.deleted_layer.link && this.deleted_layer.link.src && typeof this.deleted_layer.link.src === 'string') {
this.memory_estimate = new Blob([this.deleted_layer.link.src]).size;
}
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
if (this.deleted_layer) {
config.layers.splice(this.delete_index, 0, this.deleted_layer);
this.delete_index = null;
this.deleted_layer = null;
}
if (this.select_layer_action) {
await this.select_layer_action.undo();
this.select_layer_action.free();
this.select_layer_action = null;
}
if (this.insert_layer_action) {
await this.insert_layer_action.undo();
this.insert_layer_action.free();
this.insert_layer_action = null;
}
// Estimate memory
this.memory_estimate = 0;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
free() {
if (this.deleted_layer) {
delete this.deleted_layer.link;
delete this.deleted_layer.data;
}
if (this.insert_layer_action) {
this.insert_layer_action.free();
this.insert_layer_action = null;
}
if (this.select_layer_action) {
this.select_layer_action.free();
this.select_layer_action = null;
}
this.deleted_layer = null;
}
}

26
src/js/actions/index.js Normal file
View File

@ -0,0 +1,26 @@
export { Activate_tool_action } from './activate-tool.js';
export { Add_layer_filter_action } from './add-layer-filter.js';
export { Autoresize_canvas_action } from './autoresize-canvas.js';
export { Bundle_action } from './bundle.js';
export { Clear_layer_action } from './clear-layer.js';
export { Delete_layer_action } from './delete-layer.js';
export { Delete_layer_filter_action } from './delete-layer-filter.js';
export { Delete_layer_settings_action } from './delete-layer-settings.js';
export { Init_canvas_zoom_action } from './init-canvas-zoom.js';
export { Insert_layer_action } from './insert-layer.js';
export { Prepare_canvas_action } from './prepare-canvas.js';
export { Reorder_layer_action } from './reorder-layer.js';
export { Reset_layers_action } from './reset-layers.js';
export { Refresh_action_attributes_action } from './refresh-action-attributes.js';
export { Refresh_layers_gui_action } from './refresh-layers-gui.js';
export { Reset_selection_action } from './reset-selection.js';
export { Select_layer_action } from './select-layer.js';
export { Select_next_layer_action } from './select-next-layer.js';
export { Select_previous_layer_action } from './select-previous-layer.js';
export { Set_object_property_action } from './set-object-property.js';
export { Set_selection_action } from './set-selection.js';
export { Stop_animation_action } from './stop-animation.js';
export { Toggle_layer_visibility_action } from './toggle-layer-visibility.js';
export { Update_config_action } from './update-config.js';
export { Update_layer_image_action } from './update-layer-image.js';
export { Update_layer_action } from './update-layer.js';

View File

@ -0,0 +1,45 @@
import app from '../app.js';
import config from '../config.js';
import zoomView from '../libs/zoomView.js';
import { Base_action } from './base.js';
export class Init_canvas_zoom_action extends Base_action {
/**
* Resets the canvas
*/
constructor() {
super('init_canvas_zoom', 'Initialize Canvas Zoom');
this.old_bounds = null;
this.old_context = null;
this.old_stable_dimensions = null;
}
async do() {
super.do();
this.old_bounds = zoomView.getBounds();
this.old_context = zoomView.getContext();
this.old_stable_dimensions = app.Layers.stable_dimensions;
zoomView.setBounds(0, 0, config.WIDTH, config.HEIGHT);
zoomView.setContext(app.Layers.ctx);
app.Layers.stable_dimensions = [
config.WIDTH,
config.HEIGHT
];
}
async undo() {
super.undo();
zoomView.setBounds(this.old_bounds.top, this.old_bounds.left, this.old_bounds.right, this.old_bounds.bottom);
zoomView.setContext(this.old_context);
app.Layers.stable_dimensions = this.old_stable_dimensions;
this.old_bounds = null;
this.old_context = null;
this.old_stable_dimensions = null;
}
free() {
this.old_bounds = null;
this.old_context = null;
this.old_stable_dimensions = null;
}
}

View File

@ -0,0 +1,214 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
export class Insert_layer_action extends Base_action {
/**
* Creates new layer
*
* @param {object} settings
* @param {boolean} can_automate
*/
constructor(settings, can_automate = true) {
super('insert_layer', 'Insert Layer');
this.settings = settings;
this.can_automate = can_automate;
this.previous_auto_increment = null;
this.previous_selected_layer = null;
this.inserted_layer_id = null;
this.update_layer_action = null;
this.delete_layer_action = null;
this.autoresize_canvas_action = null;
}
async do() {
super.do();
this.previous_auto_increment = app.Layers.auto_increment;
this.previous_selected_layer = config.layer;
let autoresize_as = null;
// Default data
const layer = {
id: app.Layers.auto_increment,
parent_id: 0,
name: config.TOOL.name.charAt(0).toUpperCase() + config.TOOL.name.slice(1) + ' #' + app.Layers.auto_increment,
type: null,
link: null,
x: 0,
y: 0,
width: null,
width_original: null,
height: null,
height_original: null,
visible: true,
is_vector: false,
hide_selection_if_active: false,
opacity: 100,
order: app.Layers.auto_increment,
composition: 'source-over',
rotate: 0,
data: null,
params: {},
status: null,
color: config.COLOR,
filters: [],
render_function: null,
};
// Build data
for (let i in this.settings) {
if (typeof layer[i] == "undefined" && !i.startsWith('_')) {
alertify.error('Error: wrong key: ' + i);
continue;
}
layer[i] = this.settings[i];
}
// Prepare image
let image_load_promise;
if (layer.type == 'image') {
if(layer.name.toLowerCase().indexOf('.svg') == layer.name.length - 4){
// We have svg
layer.is_vector = true;
}
if (config.layers.length == 1 && (config.layer.width == 0 || config.layer.width === null)
&& (config.layer.height == 0 || config.layer.height === null) && config.layer.data == null) {
// Remove first empty layer
this.delete_layer_action = new app.Actions.Delete_layer_action(config.layer.id, true);
await this.delete_layer_action.do();
}
if (layer.link == null) {
if (typeof layer.data == 'object') {
// Load actual image
if (layer.width == 0 || layer.width === null)
layer.width = layer.data.width;
if (layer.height == 0 || layer.height === null)
layer.height = layer.data.height;
layer.link = layer.data.cloneNode(true);
layer.link.onload = function () {
config.need_render = true;
};
layer.data = null;
autoresize_as = [layer.width, layer.height, null, true, true];
//need_autoresize = true;
}
else if (typeof layer.data == 'string') {
image_load_promise = new Promise((resolve, reject) => {
// Try loading as imageData
layer.link = new Image();
layer.link.onload = () => {
// Update dimensions
if (layer.width == 0 || layer.width === null)
layer.width = layer.link.width;
if (layer.height == 0 || layer.height === null)
layer.height = layer.link.height;
if (layer.width_original == null)
layer.width_original = layer.width;
if (layer.height_original == null)
layer.height_original = layer.height;
// Free data
layer.data = null;
autoresize_as = [layer.width, layer.height, layer.id, this.can_automate, true];
config.need_render = true;
resolve();
};
layer.link.onerror = (error) => {
resolve(error);
alertify.error('Sorry, image could not be loaded.');
};
layer.link.src = layer.data;
layer.link.crossOrigin = "Anonymous";
});
}
else {
alertify.error('Error: can not load image.');
}
}
}
if (this.settings != undefined && config.layers.length > 0
&& (config.layer.width == 0 || config.layer.width === null) && (config.layer.height == 0 || config.layer.height === null)
&& config.layer.data == null && layer.type != 'image' && this.can_automate !== false) {
// Update existing layer, because it's empty
this.update_layer_action = new app.Actions.Update_layer_action(config.layer.id, layer);
await this.update_layer_action.do();
}
else {
// Create new layer
config.layers.push(layer);
config.layer = app.Layers.get_layer(layer.id);
app.Layers.auto_increment++;
if (config.layer == null) {
config.layer = config.layers[0];
}
this.inserted_layer_id = layer.id;
}
if (layer.id >= app.Layers.auto_increment)
app.Layers.auto_increment = layer.id + 1;
if (image_load_promise) {
await image_load_promise;
}
if (autoresize_as) {
this.autoresize_canvas_action = new app.Actions.Autoresize_canvas_action(...autoresize_as);
try {
await this.autoresize_canvas_action.do();
} catch(error) {
this.autoresize_canvas_action = null;
}
}
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
app.Layers.auto_increment = this.previous_auto_increment;
if (this.autoresize_canvas_action) {
await this.autoresize_canvas_action.undo();
this.autoresize_canvas_action = null;
}
if (this.inserted_layer_id) {
config.layers.pop();
this.inserted_layer_id = null;
}
if (this.update_layer_action) {
await this.update_layer_action.undo();
this.update_layer_action.free();
this.update_layer_action = null;
}
if (this.delete_layer_action) {
await this.delete_layer_action.undo();
this.delete_layer_action.free();
this.delete_layer_action = null;
}
config.layer = this.previous_selected_layer;
this.previous_selected_layer = null;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
free() {
if (this.delete_layer_action) {
this.delete_layer_action.free();
this.delete_layer_action = null;
}
if (this.update_layer_action) {
this.update_layer_action.free();
this.update_layer_action = null;
}
this.previous_selected_layer = null;
}
}

View File

@ -0,0 +1,29 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Prepare_canvas_action extends Base_action {
/**
* Resizes/renders the canvas at the specified step. Usually used on both sides of a config update action.
*
* @param {boolean} call_when
*/
constructor(call_when = 'undo') {
super('prepare_canvas', 'Prepare Canvas');
this.call_when = call_when;
}
async do() {
super.do();
if (this.call_when === 'do') {
app.GUI.prepare_canvas();
}
}
async undo() {
super.undo();
if (this.call_when === 'undo') {
app.GUI.prepare_canvas();
}
}
}

View File

@ -0,0 +1,29 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Refresh_action_attributes_action extends Base_action {
/**
* Resizes/renders the canvas at the specified step. Usually used on both sides of a config update action.
*
* @param {boolean} call_when
*/
constructor(call_when = 'undo') {
super('refresh_action_attributes', 'Refresh Action Attributes');
this.call_when = call_when;
}
async do() {
super.do();
if (this.call_when === 'do') {
app.GUI.GUI_tools.show_action_attributes();
}
}
async undo() {
super.undo();
if (this.call_when === 'undo') {
app.GUI.GUI_tools.show_action_attributes();
}
}
}

View File

@ -0,0 +1,29 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Refresh_layers_gui_action extends Base_action {
/**
* Resizes/renders the canvas at the specified step. Usually used on both sides of a config update action.
*
* @param {boolean} call_when
*/
constructor(call_when = 'undo') {
super('refresh_gui', 'Refresh GUI');
this.call_when = call_when;
}
async do() {
super.do();
if (this.call_when === 'do') {
app.Layers.refresh_gui();
}
}
async undo() {
super.undo();
if (this.call_when === 'undo') {
app.Layers.refresh_gui();
}
}
}

View File

@ -0,0 +1,64 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Reorder_layer_action extends Base_action {
/**
* Reorder layer up or down in the layer stack
*
* @param {int} layer_id
* @param {int} direction
*/
constructor(layer_id, direction) {
super('reorder_layer', 'Reorder Layer');
this.layer_id = parseInt(layer_id);
this.direction = direction;
this.reference_layer = null;
this.reference_target = null;
this.old_layer_order = null;
this.old_target_order = null;
}
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
if (this.direction < 0) {
this.reference_target = app.Layers.find_previous(this.layer_id);
}
else {
this.reference_target = app.Layers.find_next(this.layer_id);
}
if (!this.reference_target) {
throw new Error('Aborted - layer has nowhere to move');
}
this.old_layer_order = this.reference_layer.order;
this.old_target_order = this.reference_target.order;
this.reference_layer.order = this.old_target_order;
this.reference_target.order = this.old_layer_order;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
if (this.reference_layer) {
this.reference_layer.order = this.old_layer_order;
this.reference_layer = null;
}
if (this.reference_target) {
this.reference_target.order = this.old_target_order;
this.reference_target = null;
}
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
free() {
this.reference_layer = null;
this.reference_target = null;
}
}

View File

@ -0,0 +1,66 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Reset_layers_action extends Base_action {
/*
* removes all layers
*/
constructor(auto_insert) {
super('reset_layers', 'Reset Layers');
this.auto_insert = auto_insert;
this.previous_auto_increment = null;
this.delete_actions = null;
this.insert_action = null;
}
async do() {
super.do();
const auto_insert = this.auto_insert;
this.previous_auto_increment = app.Layers.auto_increment;
this.delete_actions = [];
for (let i = config.layers.length - 1; i >= 0; i--) {
const delete_action = new app.Actions.Delete_layer_action(config.layers[i].id, true);
await delete_action.do();
this.delete_actions.push(delete_action);
}
app.Layers.auto_increment = 1;
if (auto_insert != undefined && auto_insert === true) {
const settings = {};
this.insert_action = new app.Actions.Insert_layer_action(settings);
await this.insert_action.do();
}
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
if (this.insert_action) {
await this.insert_action.undo();
this.insert_action.free();
this.insert_action = null;
}
for (let i = this.delete_actions.length - 1; i >= 0; i--) {
await this.delete_actions[i].undo();
this.delete_actions[i].free();
}
app.Layers.auto_increment = this.previous_auto_increment;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
free() {
if (this.insert_action) {
this.insert_action.free();
this.insert_action = null;
}
if (this.delete_actions) {
for (let action of this.delete_actions) {
action.free();
}
this.delete_actions = null;
}
}
}

View File

@ -0,0 +1,57 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Reset_selection_action extends Base_action {
/**
* Sets the selection to empty
*
* @prop {object} [mirror_selection_settings] - Optional object to also set to an empty selection object
*/
constructor(mirror_selection_settings) {
super('reset_selection', 'Reset Selection');
this.mirror_selection_settings = mirror_selection_settings;
this.settings_reference = null;
this.old_settings_data = null;
}
async do() {
super.do();
this.settings_reference = app.Layers.Base_selection.find_settings();
this.old_settings_data = JSON.parse(JSON.stringify(this.settings_reference.data));
this.settings_reference.data = {
x: null,
y: null,
width: null,
height: null
}
if (this.mirror_selection_settings) {
this.mirror_selection_settings.x = null;
this.mirror_selection_settings.y = null;
this.mirror_selection_settings.width = null;
this.mirror_selection_settings.height = null;
}
config.need_render = true;
}
async undo() {
super.undo();
if (this.old_settings_data) {
for (let prop of ['x', 'y', 'width', 'height']) {
this.settings_reference.data[prop] = this.old_settings_data[prop];
if (this.mirror_selection_settings) {
this.mirror_selection_settings[prop] = this.old_settings_data[prop];
}
}
}
this.settings_reference = null;
this.old_settings_data = null;
config.need_render = true;
}
free() {
this.settings_reference = null;
this.old_settings_data = null;
this.mirror_selection_settings = null;
}
}

View File

@ -0,0 +1,57 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Select_layer_action extends Base_action {
/**
* marks layer as selected, active
*
* @param {int} layer_id
*/
constructor(layer_id, ignore_same_selection = false) {
super('select_layer', 'Select Layer');
this.reset_selection_action = null;
this.layer_id = parseInt(layer_id);
this.ignore_same_selection = ignore_same_selection;
this.old_layer = null;
}
async do() {
super.do();
let old_layer = config.layer;
let new_layer = app.Layers.get_layer(this.layer_id);
if (old_layer !== new_layer) {
this.old_layer = old_layer;
config.layer = new_layer;
} else if (!this.ignore_same_selection) {
throw new Error('Aborted - Layer already selected');
}
this.reset_selection_action = new app.Actions.Reset_selection_action();
await this.reset_selection_action.do();
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
if (this.reset_selection_action) {
await this.reset_selection_action.undo();
this.reset_selection_action = null;
}
config.layer = this.old_layer;
this.old_layer = null;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
free() {
this.old_layer = null;
}
}

View File

@ -0,0 +1,33 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Select_next_layer_action extends Base_action {
constructor(reference_layer_id) {
super('select_next_layer', 'Select Next Layer');
this.reference_layer_id = reference_layer_id;
this.old_config_layer = null;
}
async do() {
super.do();
const next_layer = app.Layers.find_next(this.reference_layer_id);
if (!next_layer) {
throw new Error('Aborted - Next layer to select not found');
}
this.old_config_layer = config.layer;
config.layer = next_layer;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
config.layer = this.old_config_layer;
this.old_config_layer = null;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
}

View File

@ -0,0 +1,33 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Select_previous_layer_action extends Base_action {
constructor(reference_layer_id) {
super('select_previous_layer', 'Select Previous Layer');
this.reference_layer_id = reference_layer_id;
this.old_config_layer = null;
}
async do() {
super.do();
const previous_layer = app.Layers.find_previous(this.reference_layer_id);
if (!previous_layer) {
throw new Error('Aborted - Previous layer to select not found');
}
this.old_config_layer = config.layer;
config.layer = previous_layer;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
config.layer = this.old_config_layer;
this.old_config_layer = null;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
}

View File

@ -0,0 +1,35 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Set_object_property_action extends Base_action {
/**
* Sets a generic object property. I recommend against using this as it's generally a hack for edge cases.
*
* @param {string} layer_id
* @param {object} settings
*/
constructor(object, property_name, value) {
super('set_object_property', 'Set Object Property');
this.object = object;
this.property_name = property_name;
this.value = value;
this.old_value = null;
}
async do() {
super.do();
this.old_value = this.object[this.property_name];
this.object[this.property_name] = this.value;
}
async undo() {
super.undo();
this.object[this.property_name] = this.old_value;
this.old_value = null;
}
free() {
this.object = null;
}
}

View File

@ -0,0 +1,57 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Set_selection_action extends Base_action {
/**
* Sets the selection to the specified position and dimensions
*/
constructor(x, y, width, height, old_settings_override) {
super('set_selection', 'Set Selection');
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.settings_reference = null;
this.old_settings_data = null;
this.old_settings_override = old_settings_override ? JSON.parse(JSON.stringify(old_settings_override)) || null : null;
}
async do() {
super.do();
this.settings_reference = app.Layers.Base_selection.find_settings();
this.old_settings_data = JSON.parse(JSON.stringify(this.settings_reference.data));
if (this.x != null)
this.settings_reference.data.x = this.x;
if (this.y != null)
this.settings_reference.data.y = this.y;
if (this.width != null)
this.settings_reference.data.width = this.width;
if (this.height != null)
this.settings_reference.data.height = this.height;
config.need_render = true;
}
async undo() {
super.undo()
if (this.old_settings_override) {
for (let prop in this.old_settings_override) {
this.settings_reference.data[prop] = this.old_settings_override[prop];
}
} else {
for (let prop in this.old_settings_data) {
this.settings_reference.data[prop] = this.old_settings_data[prop];
}
}
this.settings_reference = null;
this.old_settings_data = null;
config.need_render = true;
}
free() {
this.settings_reference = null;
this.old_settings_override = null;
this.old_settings_data = null;
}
}

View File

@ -0,0 +1,59 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Stop_animation_action extends Base_action {
/**
* Stops the currently playing animation, both do and undo states will stop animation
*/
constructor(reset_layer_visibility) {
super('stop_animation', 'Stop Animation');
this.reset_layer_visibility = !!reset_layer_visibility;
}
async do() {
super.do();
const animation_tool = app.GUI.GUI_tools.tools_modules.animation.object;
var params = animation_tool.getParams();
if (animation_tool.intervalID == null)
return;
clearInterval(animation_tool.intervalID);
params.play = false;
animation_tool.index = 0;
animation_tool.GUI_tools.show_action_attributes();
// make all visible
if (this.reset_layer_visibility) {
for (let i in config.layers) {
config.layers[i].visible = true;
}
}
animation_tool.Base_gui.GUI_layers.render_layers();
config.need_render = true;
}
async undo() {
super.undo();
const animation_tool = app.GUI.GUI_tools.tools_modules.animation.object;
var params = animation_tool.getParams();
if (animation_tool.intervalID == null)
return;
clearInterval(animation_tool.intervalID);
params.play = false;
animation_tool.index = 0;
animation_tool.GUI_tools.show_action_attributes();
// make all visible
if (this.reset_layer_visibility) {
for (let i in config.layers) {
config.layers[i].visible = true;
}
}
animation_tool.Base_gui.GUI_layers.render_layers();
config.need_render = true;
}
}

View File

@ -0,0 +1,222 @@
import { v4 as uuidv4 } from 'uuid';
// Get a unique id to identify this tab's history in the database
let tabUuid;
try {
tabUuid = sessionStorage.getItem('history_tab_uuid');
} catch (error) {}
if (!tabUuid) {
tabUuid = uuidv4();
try {
sessionStorage.setItem('history_tab_uuid', tabUuid);
} catch (error) {}
}
let imageIdCounter = 0;
let database = null;
let databaseInitPromise = null;
const tabPingInterval = 60000;
const assumeTabIsClosedTimeout = 300000; // Inactive tabs setInterval is slowed down in most browsers, this should be significantly higher than tabPingInterval
export default {
/**
* Initializes the database
*/
async init() {
if (!databaseInitPromise) {
databaseInitPromise = new Promise(async (resolveInit) => {
try {
if (window.indexedDB) {
// Delete database from a previous page load, if no other tabs have notified that they're open in a while
let shouldDeleteDatabase = true;
try {
let lastDatabaseTabPing = localStorage.getItem('history_usage_ping');
shouldDeleteDatabase = (!lastDatabaseTabPing || parseInt(lastDatabaseTabPing, 10) < new Date().getTime() - assumeTabIsClosedTimeout);
} catch (error) {}
if (shouldDeleteDatabase) {
await new Promise((resolve, reject) => {
let deleteRequest = window.indexedDB.deleteDatabase('undoHistoryImageStore');
deleteRequest.onerror = () => {
reject(deleteRequest.error);
};
deleteRequest.onsuccess = () => {
resolve();
};
});
}
// Initialize database
await new Promise((resolve, reject) => {
let openRequest = window.indexedDB.open('undoHistoryImageStore', 1);
openRequest.onupgradeneeded = function(event) {
database = openRequest.result;
switch (event.oldVersion) {
case 0:
database.createObjectStore('images', { keyPath: 'id' });
break;
}
};
openRequest.onerror = () => {
reject(openRequest.error);
}
openRequest.onsuccess = () => {
resolve();
database = openRequest.result;
}
});
if (!database) {
throw new Error('indexedDB not initialized');
}
// Delete history from previous session
try {
await this.delete_all();
} catch (error) {}
// Ping localStorage for as long as this browser tab is open
localStorage.setItem('history_usage_ping', new Date().getTime() + '');
setInterval(() => {
localStorage.setItem('history_usage_ping', new Date().getTime() + '');
}, tabPingInterval);
}
} catch (error) {
database = {
isMemory: true,
images: {}
};
}
resolveInit();
});
await databaseInitPromise;
} else if (!database) {
await databaseInitPromise;
}
},
/**
* Adds the specified image to the database. Returns a promise that is resolved with an id that can be used to retrieve it again.
*
* @param {string | canvas | ImageData} imageData the image data to store
* @returns {Promise<string>} resolves with retrieval id
*/
async add(imageData) {
await this.init();
let imageId = tabUuid + '-' + (imageIdCounter++);
if (database.isMemory) {
database.images[imageId] = imageData;
} else {
await new Promise((resolve, reject) => {
const transaction = database.transaction('images', 'readwrite');
const images = transaction.objectStore('images');
const image = {
id: imageId,
tabUuid,
data: imageData
}
const request = images.add(image);
request.onsuccess = function() {
resolve();
};
request.onerror = function() {
reject(request.error);
};
});
}
return imageId;
},
/**
* Gets the specified image from the database, by imageId retrieved from "add()" method.
*
* @param {string} imageId the id of the image to get
* @returns {Promise<string | canvas | ImageData>} resolves with the image
*/
async get(imageId) {
await this.init();
if (database.isMemory) {
return database.images[imageId];
} else {
return new Promise((resolve, reject) => {
const transaction = database.transaction('images', 'readonly');
const images = transaction.objectStore('images');
const request = images.get(imageId);
request.onsuccess = function() {
resolve(request.result && request.result.data);
};
request.onerror = function() {
reject(request.error);
};
});
}
},
/**
* Deletes the specified image from the database, by imageId retrieved from "add()" method.
*
* @param {string} imageId the id of the image to delete
* @returns {Promise<void>}
*/
async delete(imageId) {
await this.init();
if (database.isMemory) {
delete database.images[imageId];
} else {
return new Promise((resolve, reject) => {
const transaction = database.transaction('images', 'readwrite');
const images = transaction.objectStore('images');
const request = images.delete(imageId);
request.onsuccess = function() {
resolve();
};
request.onerror = function() {
reject(request.error);
};
});
}
},
/**
* Deletes all images associated with the current tab.
*
* @returns {Promise<void>}
*/
async delete_all() {
await this.init();
if (database.isMemory) {
database.images = {};
} else {
return new Promise((resolve, reject) => {
const transaction = database.transaction('images', 'readwrite');
const images = transaction.objectStore('images');
const getAllImagesRequest = images.getAll();
getAllImagesRequest.onsuccess = async function () {
const allImages = getAllImagesRequest.result;
let errorOccurred = false;
for (let image of allImages) {
if (image.tabUuid === tabUuid) {
try {
await new Promise((deleteResolve, deleteReject) => {
const request = images.delete(image.id);
request.onsuccess = function() {
deleteResolve();
};
request.onerror = function() {
deleteReject(request.error);
};
});
} catch (error) {
errorOccurred = true;
// Should eventually be deleted when database is deleted due to timeout
}
}
}
if (errorOccurred) {
// Use a different uuid to prevent conflicts
tabUuid = uuidv4();
}
resolve();
};
getAllImagesRequest.onerror = function () {
reject(request.error);
};
});
}
}
};

View File

@ -0,0 +1,37 @@
import app from '../app.js';
import config from '../config.js';
import { Base_action } from './base.js';
export class Toggle_layer_visibility_action extends Base_action {
/**
* toggle layer visibility
*
* @param {int} layer_id
*/
constructor(layer_id) {
super('toggle_layer_visibility', 'Toggle Layer Visibility');
this.layer_id = parseInt(layer_id);
this.old_visible = null;
}
async do() {
super.do();
const layer = app.Layers.get_layer(this.layer_id);
this.old_visible = layer.visible;
if (layer.visible == false)
layer.visible = true;
else
layer.visible = false;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
async undo() {
super.undo();
const layer = app.Layers.get_layer(this.layer_id);
layer.visible = this.old_visible;
this.old_visible = null;
app.Layers.render();
app.GUI.GUI_layers.render_layers();
}
}

View File

@ -0,0 +1,37 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Update_config_action extends Base_action {
/**
* Updates the app config with the provided settings
*
* @param {object} settings
*/
constructor(settings) {
super('update_config', 'Update Config');
this.settings = settings;
this.old_settings = {};
}
async do() {
super.do();
for (let i in this.settings) {
this.old_settings[i] = config[i];
config[i] = this.settings[i];
}
}
async undo() {
super.undo();
for (let i in this.old_settings) {
config[i] = this.old_settings[i];
}
this.old_settings = {};
}
free() {
this.settings = null;
this.old_settings = null;
}
}

View File

@ -0,0 +1,149 @@
import app from './../app.js';
import config from './../config.js';
import Helper_class from './../libs/helpers.js';
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
import image_store from './store/image-store.js';
import { Base_action } from './base.js';
const Helper = new Helper_class();
export class Update_layer_image_action extends Base_action {
/**
* updates layer image data
*
* @param {canvas} canvas
* @param {int} layer_id (optional)
*/
constructor(canvas, layer_id) {
super('update_layer_image', 'Update Layer Image');
this.canvas = canvas;
if (layer_id == null)
layer_id = config.layer.id;
this.layer_id = parseInt(layer_id);
this.reference_layer = null;
this.old_image_id = null;
this.new_image_id = null;
this.old_link_database_id = null;
}
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
if (this.reference_layer.type != 'image'){
alertify.error('Error: layer must be image.');
throw new Error('Aborted - layer is not an image');
}
// Get data url representation of image
let canvas_data_url;
if (this.new_image_id) {
try {
canvas_data_url = await image_store.get(this.new_image_id);
} catch (error) {
throw new Error('Aborted - problem retrieving cached image from database');
}
} else if (this.canvas) {
if (Helper.is_edge_or_ie() == false && typeof(FileReader) !== 'undefined') {
// Update image using blob and FileReader (async)
await new Promise((resolve) => {
this.canvas.toBlob((blob) => {
var reader = new FileReader();
reader.onloadend = () => {
canvas_data_url = reader.result;
resolve();
}
reader.readAsDataURL(blob);
}, 'image/png');
});
}
else {
// Slow way for IE, Edge
canvas_data_url = this.canvas.toDataURL();
}
}
// Store data url in database
try {
if (!this.old_image_id) {
if (this.reference_layer._link_database_id) {
this.old_image_id = this.reference_layer._link_database_id;
} else {
this.old_image_id = await image_store.add(this.reference_layer.link.src);
}
}
if (!this.new_image_id) {
this.new_image_id = await image_store.add(canvas_data_url);
}
} catch (error) {
console.log(error);
requestAnimationFrame(() => {
app.State.free(0, this.database_estimate || 1)
});
}
// Estimate storage size
try {
this.database_estimate = new Blob([await image_store.get(this.old_image_id)]).size;
} catch (e) {}
// Assign layer properties
this.reference_layer.link.src = canvas_data_url;
this.old_link_database_id = this.reference_layer._link_database_id;
this.reference_layer._link_database_id = this.new_image_id;
this.canvas = null;
config.need_render = true;
}
async undo() {
super.undo();
// Estimate storage size
try {
this.database_estimate = new Blob([this.reference_layer.link.src]).size;
} catch (e) {}
// Restore old image
if (this.old_image_id != null) {
try {
this.reference_layer.link.src = await image_store.get(this.old_image_id);
} catch (error) {
throw new Error('Failed to retrieve image from store');
}
}
this.reference_layer._link_database_id = this.old_link_database_id;
this.reference_layer = null;
config.need_render = true;
}
async free() {
let has_error = false;
if (this.new_image_id != null) {
try {
await image_store.delete(this.new_image_id);
} catch (error) {
has_error = true;
}
this.new_image_id = null;
}
if (this.is_done || !this.old_link_database_id) {
if (this.old_image_id != null) {
try {
await image_store.delete(this.old_image_id);
} catch (error) {
has_error = true;
}
this.old_image_id = null;
}
}
this.canvas = null;
this.old_link_database_id = null;
this.reference_layer = null;
if (has_error) {
alertify.error('A problem occurred while removing undo history. It\'s suggested you save your work and refresh the page in order to free up memory.');
}
}
}

View File

@ -0,0 +1,67 @@
import app from './../app.js';
import config from './../config.js';
import { Base_action } from './base.js';
export class Update_layer_action extends Base_action {
/**
* Updates an existing layer with the provided settings
* WARNING: If passing objects or arrays into settings, make sure these are new or cloned objects, and not a modified existing object!
*
* @param {string} layer_id
* @param {object} settings
*/
constructor(layer_id, settings) {
super('update_layer', 'Update Layer');
this.layer_id = layer_id;
this.settings = settings;
this.reference_layer = null;
this.old_settings = {};
}
async do() {
super.do();
this.reference_layer = app.Layers.get_layer(this.layer_id);
if (!this.reference_layer) {
throw new Error('Aborted - layer with specified id doesn\'t exist');
}
for (let i in this.settings) {
if (i == 'id')
continue;
if (i == 'order')
continue;
this.old_settings[i] = this.reference_layer[i];
this.reference_layer[i] = this.settings[i];
}
if (this.reference_layer.type === 'text') {
this.reference_layer._needs_update_data = true;
}
if (this.settings.params || this.settings.width || this.settings.height) {
config.need_render_changed_params = true;
}
config.need_render = true;
}
async undo() {
super.undo();
if (this.reference_layer) {
for (let i in this.old_settings) {
this.reference_layer[i] = this.old_settings[i];
}
if (this.reference_layer.type === 'text') {
this.reference_layer._needs_update_data = true;
}
if (this.old_settings.params || this.old_settings.width || this.old_settings.height) {
config.need_render_changed_params = true;
}
this.old_settings = {};
}
this.reference_layer = null;
config.need_render = true;
}
free() {
this.settings = null;
this.old_settings = null;
this.reference_layer = null;
}
}

11
src/js/app.js Normal file
View File

@ -0,0 +1,11 @@
// Store singletons for easy access
export default {
GUI: null,
Tools: null,
Layers: null,
Config: null,
State: null,
FileOpen: null,
FileSave: null,
Actions: null
};

Some files were not shown because too many files have changed in this diff Show More