Compare commits

...

466 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
299 changed files with 39795 additions and 15555 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,11 +1,8 @@
# miniPaint
Online image editor lets you create, edit images using HTML5 technologies.
No need to buy, download, install or have obsolete flash. No ads.
Key features: layers, filters, HTML5, open source, Photoshop alternative.
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:
**https://viliusle.github.io/miniPaint/**
@ -20,24 +17,30 @@ or upload from computer (using menu or drag & drop). Nothing will be sent to any
- Chrome
- Firefox
- Opera
- Edge
- Safari
- Edge (missing few features)
- IE 11 (only basic support)
- 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, Blueprint, Night Vision, Pencil.
- **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.
**Edit**: undo, cut, copy, paste, selection, paste from the clipboard.
**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.
**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 in other page, use this HTML code:
To embed this app on another page, use the following HTML code:
<iframe style="width:100%; height:1000px;" id="miniPaint" src="https://viliusle.github.io/miniPaint/"></iframe>
<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)
@ -45,8 +48,13 @@ See [Wiki > Build instructions](https://github.com/viliusle/miniPaint/wiki/Build
## Wiki
See [Wiki](https://github.com/viliusle/miniPaint/wiki)
## 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

86
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

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
<html>
<body style="margin:0;">
<iframe id="myFrame" style="width:100%;height:100vh;border:0;" src="../"></iframe>
<iframe id="myFrame" style="width:100%;height:100vh;border:0;" src="../" allow="camera"></iframe>
<script>
window.addEventListener('load', function (e) {

View File

@ -1,16 +1,23 @@
<html>
<body style="margin:0;">
<iframe id="myFrame" style="width:100%;height:70vh;border:0;" 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");
@ -56,12 +78,21 @@ function my_save(){
else{
//slow way for IE, Edge
var data = tempCanvas.toDataURL();
console.log(data);
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;

View File

@ -1,56 +1,70 @@
<html>
<body style="margin:0;">
<iframe id="myFrame" style="width:100%;height:100vh;border:0;" src="../"></iframe>
<iframe id="myFrame" style="width:100%;height:100vh;border:0;" src="../" allow="camera"></iframe>
<script>
window.addEventListener('load', function (e) {
main();
}, false);
function main() {
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(1000, 1000);
Layers.Base_gui.set_size(canvas_width, canvas_height);
//add rectangle
this.layer = {
name: 'layer1',
type: 'rectangle',
params: {fill: true, size: 2 },
params: {
fill: true,
square: false,
border_size: 2,
border: false,
border_color: "#1b1bd8",
fill_color: "#1b1bd8"
},
color: '#ff0000',
render_function: ['rectangle', 'render'],
x: 500,
y: 500,
x: canvas_width/2 - 25,
y: canvas_height/2 - 25,
width: 50,
height: 50,
};
Layers.insert(this.layer);
await Layers.insert(this.layer);
//zoom to 500%
Layers.Base_gui.GUI_preview.zoom(500); //change zoom power
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
}, 200);
}, 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 = 500 + 50/2;
var cy = 500 + 50/2;
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);
}

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

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

View File

@ -5,9 +5,10 @@
<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..." />
@ -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"
}
]
}

16003
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "miniPaint",
"version": "4.2.0",
"version": "4.14.2",
"author": "Vilius L.",
"description": "Online graphics editing tool lets create, edit images using HTML5 technologies.",
"keywords": [
@ -11,7 +11,7 @@
"effects"
],
"scripts": {
"server": "webpack-dev-server --mode development --open",
"server": "webpack serve --mode development --env development --open",
"dev": "webpack --mode development",
"build": "webpack --mode production"
},
@ -22,27 +22,30 @@
"homepage": "https://github.com/viliusle/miniPaint",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-env": "^1.7.0",
"css-loader": "^0.28.11",
"source-map-loader": "^0.2.4",
"style-loader": "^0.21.0",
"webpack": "^4.29.0",
"webpack-cli": "^3.2.1",
"webpack-dev-server": "^3.1.14"
"@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.2",
"babel-polyfill": "^6.26.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.3.1",
"pica": "^5.0.0",
"spectrum-colorpicker": "^1.8.0",
"terser": "^3.14.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 */
@ -55,27 +61,31 @@
.block{
position: relative;
background-color: rgba(255, 255, 255, 0.2);
background-color: var(--background-color-area);
background-color: var(--block-background-color);
border: 1px solid rgba(0, 0, 0, 0.5);
border: 1px solid var(--border-color);
margin-bottom: 10px;
user-select: none;
border-radius: 4px;
}
.sidebar_right .block{
background-color: #68727b;
background-color: var(--background-color-section);
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;
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-header);
background-color: var(--header-background-color);
border-bottom: #555;
border-radius: 4px 4px 0 0;
}
.block.toggled h2, .block h2.toggled:after{
border: none;
@ -89,16 +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{
/* icon */
border-width: 6px 5px 0 5px;
border-color: #333333 transparent transparent transparent;
border-width: 5px 4px 0 4px;
border-color: var(--text-color-muted) transparent transparent transparent;
}
.block .content{
padding:5px;
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;
@ -124,7 +143,6 @@ body .sp-preview{
.logo{
position: relative;
display: inline-block;
float: left;
height: 30px;
width: 110px;
padding: 5px 5px 5px 36px;
@ -142,126 +160,167 @@ body .sp-preview{
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-section);
background-color: var(--section-background-color);
overflow: hidden;
margin-bottom: 5px;
}
.attributes{
float: left;
display: flex;
flex-wrap: nowrap;
background-color: var(--area-background-color);
width: calc(100% - 125px);
height: 30px;
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;
border-color: var(--border-color);
background-color: var(--background-color-button);
margin-right: 5px;
}
.attributes button:hover{
background-color: rgba(255, 255, 255, 0.3);
background-color: var(--background-color-hover);
}
.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-section);
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-area);
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;
}
.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-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: -643px 4px; }
.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{
@ -272,24 +331,26 @@ body .sp-preview{
/* ========== 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 */
@ -301,6 +362,9 @@ body .sp-preview{
.canvas_preview_details{
padding: 0 5px;
}
.canvas_preview_details button{
margin: 0;
}
.preview canvas{
cursor: pointer;
}
@ -316,43 +380,6 @@ body .sp-preview{
cursor: pointer;
margin: 5px;
}
.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;
}
/* layers */
.layers_list{
@ -366,16 +393,18 @@ body .sp-preview{
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;
}
@ -386,32 +415,69 @@ body .sp-preview{
display:block;
padding:1px 5px 3px 5px;
height:19px;
width: calc(100% - 44px);
text-align: left;
overflow:hidden;
background-color:#989898;
background-color: var(--background-color-area);
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;
filter: drop-shadow(0px 0px 2px white);
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{
@ -421,7 +487,10 @@ body .sp-preview{
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{
@ -445,63 +514,148 @@ body .sp-preview{
}
.sidebar_right .label{
display: inline-block;
width: 60px;
}
.info .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;
}
.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 var(--border-color);
box-sizing: content-box;
font-kerning: normal !important;
}
.loaded .canvas_wrapper canvas{
border: 1px solid var(--border-color);
}
#mouse{
position:absolute;
@ -522,16 +676,10 @@ body .sp-preview{
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;
@ -575,32 +723,47 @@ canvas{
.alertify-notifier{
color: black;
}
@media screen and (max-width:700px){
body{
padding-top:50px;
}
.main_wrapper{
margin-right: 5px;
}
.effectsPreview{
cursor: pointer;
background-color: #ddd;
}
@media screen and (max-width:550px){
.canvas_wrapper{
margin-left: 0px;
}
}
@media screen and (max-height: 720px){
@media screen and (max-height: 690px){
.sidebar_left{
width: 79px;
padding: 4px 2px 0px 2px;
width: 75px;
}
.sidebar_left .item{
display: inline-block;
width: 30px;
margin-right: 5px;
margin: 1px 3px 0 3px;
}
@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;
}
.main_wrapper{
margin-left: 85px;
}
}

View File

@ -1,215 +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;
background: var(--background-color-menu);
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: #cccccc;
color: var(--text-color-menu);
text-decoration: none;
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,112 +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(--background-color-section);
background-color: var(--block-background-color);
border: 1px solid rgba(0, 0, 0, 0.5);
border: 1px solid var(--border-color);
width:500px;
max-width: 100%;
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-header);
/*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 .close{
float: right;
#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-left: 10px;
margin-top: 10px;
margin-right: 10px;
border: none;
background: none;
z-index: 1;
}
#popup td, #popup th{
#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-button);
background-color: var(--button-background-color);
min-width:60px;
border:1px solid rgba(0, 0, 0, 0.5);
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,58 +1,131 @@
*{
box-sizing: border-box;
background-repeat: no-repeat;
}
:root {
/* original - default */
--background: #424F5A;
--text-color: #000000;
--background-color-section: #68727b;
--background-color-area: #868e95;
--background-color-header: #a2a8ae;
--background-color-button: #959ca2;
--background-color-menu: #2D2D2D;
--text-color-menu: #cccccc;
--background-color-active: #419147;
--background-color-hover: #b4b9bd;
--border-color: #3c3c3c;
--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;
--background-color-section: #f1f1f1;
--background-color-area: #ccc;
--background-color-header: #dcdcdc;
--background-color-button: #f9f9fa;
--background-color-menu: #f1f1f1;
--text-color-menu: #333333;
--background-color-active: #0a84ff;
--background-color-hover: #e1e1e2;
--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;
--background-color-section: #1c2e04;
--background-color-area: #3b5f11;
--background-color-header: #2b460f;
--background-color-button: #2e4a0d;
--background-color-menu: #1c2e04;
--text-color-menu: #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;
}
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: var(--background);
font-size: 13px;
font-size: 1.3rem;
font-family: Arial, Helvetica, sans-serif;
color: #000000;
color: var(--text-color);
line-height: 1.4;
font-weight: normal;
@ -62,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;
@ -95,9 +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;
border-color: var(--border-color);
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;
}
@ -108,20 +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{
border-radius: 0;
cursor: pointer;
background-color: var(--background-color-button);
color: var(--color-text);
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;
@ -146,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
};

View File

@ -1,201 +1,768 @@
var menu_template = `
<ul>
<li>
<a class="trn" href="#">File</a>
<ul>
<li><a class="trn" data-target="file/new.new" href="#">New</a></li>
<li><div class="mid-line"></div></li>
<li class="more">
<a class="trn" href="#">Open</a>
<ul>
<li><a class="trn dots" data-target="file/open.open_file" data-key="Drag&Drop" href="#">Open File</a></li>
<li><a class="trn dots" data-target="file/open.open_dir" href="#">Open Directory</a></li>
<li><a class="trn dots" data-target="file/open.open_webcam" href="#">Open from Webcam</a></li>
<li><a class="trn dots" data-target="file/open.open_url" href="#">Open URL</a></li>
<li><a class="trn dots" data-target="file/open.open_data_url" href="#">Open Data URL</a></li>
<li><a class="trn dots" data-target="file/open.open_template_test" href="#">Open test template</a></li>
</ul>
</li>
<li><a class="trn dots" data-target="file/search.search" href="#">Search images</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="file/save.save" data-key="S" href="#">Save as</a></li>
<li><a class="trn dots" data-target="file/save.save_data_url" href="#">Save as data URL</a></li>
<li><a class="trn dots" data-target="file/print.print" data-key="Ctrl-P" href="#">Print</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn" data-target="file/quicksave.quicksave" data-key="F9" href="#">Quick save</a></li>
<li><a class="trn" data-target="file/quickload.quickload" data-key="F10" href="#">Quick load</a></li>
</ul>
</li>
<li>
<a class="trn" href="#">Edit</a>
<ul>
<li><a class="trn" data-target="edit/undo.undo" href="#">Undo</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn" data-target="edit/selection.delete" data-key="Del" href="#">Delete selection</a></li>
<li><a class="trn" data-target="layer/new.new_selection" href="#">Copy selection</a></li>
<li><a class="trn" data-target="edit/paste.paste" data-key="Ctrl+V" href="#">Paste</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn" data-target="edit/selection.select_all" href="#">Select all</a></li>
</ul>
</li>
<li>
<a class="trn" href="#">Image</a>
<ul>
<li><a class="trn dots" data-target="image/information.information" href="#">Information</a></li>
<li><a class="trn dots" data-target="image/size.size" href="#">Size</a></li>
<li><a class="trn dots" data-target="image/trim.trim" data-key="T" href="#">Trim</a>
<li class="more">
<a class="trn" href="#">Zoom</a>
<ul>
<li><a class="trn" data-target="image/zoom.in" href="#">Zoom In</a></li>
<li><a class="trn" data-target="image/zoom.out" href="#">Zoom Out</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn" data-target="image/zoom.original" href="#">Original size</a></li>
<li><a class="trn" data-target="image/zoom.auto" href="#">Fit window</a></li>
</ul>
</li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="image/resize.resize" href="#">Resize</a></li>
<li><a class="trn dots" data-target="image/rotate.rotate" href="#">Rotate</a></li>
<li class="more">
<a class="trn" href="#">Flip</a>
<ul>
<li><a class="trn" data-target="image/flip.vertical" href="#">Vertical</a></li>
<li><a class="trn" data-target="image/flip.horizontal" href="#">Horizontal</a></li>
</ul>
</li>
<li><a class="trn dots" data-target="image/translate.translate" href="#">Translate</a></li>
<li><a class="trn dots" data-target="image/opacity.opacity" href="#">Opacity</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="image/color_corrections.color_corrections" href="#">Color corrections</a></li>
<li><a class="trn" data-target="image/auto_adjust.auto_adjust" href="#">Auto adjust colors</a></li>
<li><a class="trn" data-target="image/decrease_colors.decrease_colors" href="#">Decrease color depth</a></li>
<li><a class="trn dots" data-target="image/palette.palette" href="#">Color palette</a></li>
<li><a class="trn dots" data-target="image/grid.grid" data-key="G" href="#">Grid</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="image/histogram.histogram" data-key="H" href="#">Histogram</a></li>
</ul>
</li>
<li>
<a class="trn" href="#">Layers</a>
<ul>
<li><a class="trn" data-target="layer/new.new" data-key="N" href="#">New</a></li>
<li><a class="trn" data-target="layer/new.new_selection" href="#">New from selection</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn" data-target="layer/duplicate.duplicate" href="#">Duplicate</a></li>
<li><a class="trn" data-target="layer/visibility.toggle" href="#">Show / Hide</a></li>
<li><a class="trn" data-target="layer/delete.delete" href="#">Delete</a></li>
<li><a class="trn" data-target="layer/raster.raster" href="#">Convert to raster</a></li>
<li><div class="mid-line"></div></li>
<li class="more">
<a class="trn" href="#">Move</a>
<ul>
<li><a class="trn" data-target="layer/move.up" href="#">Up</a></li>
<li><a class="trn" data-target="layer/move.down" href="#">Down</a></li>
</ul>
</li>
<li><a class="trn dots" data-target="layer/composition.composition" href="#">Composition</a></li>
<li><a class="trn dots" data-target="layer/rename.rename" href="#">Rename</a></li>
<li><a class="trn" data-target="layer/clear.clear" href="#">Clear</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn" data-target="layer/differences.differences" href="#">Differences Down</a></li>
<li><a class="trn" data-target="layer/merge.merge" href="#">Merge Down</a></li>
<li><a class="trn" data-target="layer/flatten.flatten" href="#">Flatten Image</a></li>
</ul>
</li>
<li>
<a class="trn" href="#">Effects</a>
<ul id="effects_list">
<li><div class="mid-line"></div></li>
<li class="more">
<a class="trn" href="#">CSS filters</a>
<ul>
<li><a class="trn dots" data-target="effects/blur.blur" href="#">Gaussian Blur</a>
<li><a class="trn dots" data-target="effects/brightness.brightness" href="#">Brightness</a>
<li><a class="trn dots" data-target="effects/contrast.contrast" href="#">Contrast</a>
<li><a class="trn dots" data-target="effects/grayscale.grayscale" href="#">Grayscale</a>
<li><a class="trn dots" data-target="effects/hue_rotate.hue_rotate" href="#">Hue Rotate</a>
<li><a class="trn dots" data-target="effects/negative.negative" href="#">Negative</a>
<li><a class="trn dots" data-target="effects/saturate.saturate" href="#">Saturate</a>
<li><a class="trn dots" data-target="effects/sepia.sepia" href="#">Sepia</a>
<li><a class="trn dots" data-target="effects/shadow.shadow" href="#">Shadow</a>
</ul>
</li>
<li><a class="trn dots" data-target="effects/black_and_white.black_and_white" href="#">Black and White</a>
<li><a class="trn dots" data-target="effects/blueprint.blueprint" href="#">Blueprint</a>
<li><a class="trn dots" data-target="effects/box_blur.box_blur" href="#">Box Blur</a>
<li><a class="trn dots" data-target="effects/denoise.denoise" href="#">Denoise</a>
<li><a class="trn dots" data-target="effects/dither.dither" href="#">Dither</a>
<li><a class="trn dots" data-target="effects/dot_screen.dot_screen" href="#">Dot Screen</a>
<li><a class="trn dots" data-target="effects/edge.edge" href="#">Edge</a>
<li><a class="trn dots" data-target="effects/emboss.emboss" href="#">Emboss</a>
<li><a class="trn dots" data-target="effects/enrich.enrich" href="#">Enrich</a>
<li><a class="trn dots" data-target="effects/grains.grains" href="#">Grains</a>
<li><a class="trn dots" data-target="effects/heatmap.heatmap" href="#">Heatmap</a>
<li><a class="trn dots" data-target="effects/mosaic.mosaic" href="#">Mosaic</a>
<li><a class="trn dots" data-target="effects/night_vision.night_vision" href="#">Night Vision</a>
<li><a class="trn dots" data-target="effects/oil.oil" href="#">Oil</a>
<li><a class="trn dots" data-target="effects/pencil.pencil" href="#">Pencil</a>
<li><a class="trn dots" data-target="effects/sharpen.sharpen" href="#">Sharpen</a>
<li><a class="trn dots" data-target="effects/solarize.solarize" href="#">Solarize</a>
<li><a class="trn dots" data-target="effects/tilt_shift.tilt_shift" href="#">Tilt Shift</a>
<li><a class="trn dots" data-target="effects/vignette.vignette" href="#">Vignette</a>
<li><a class="trn dots" data-target="effects/vibrance.vibrance" href="#">Vibrance</a>
<li><a class="trn dots" data-target="effects/vintage.vintage" href="#">Vintage</a>
<li><a class="trn dots" data-target="effects/zoom_blur.zoom_blur" href="#">Zoom Blur</a>
</ul>
</li>
<li>
<a class="trn" href="#">Tools</a>
<ul>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="tools/borders.borders" href="#">Borders</a></li>
<li><a class="trn" data-target="tools/sprites.sprites" href="#">Sprites</a></li>
<li><a class="trn" data-target="tools/keypoints.keypoints" href="#">Key-points</a></li>
<li><a class="trn dots" data-target="tools/content_fill.content_fill" href="#">Content fill</a></li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="tools/color_to_alpha.color_to_alpha" href="#">Color to alpha</a></li>
<li><a class="trn dots" data-target="tools/color_zoom.color_zoom" href="#">Color Zoom</a></li>
<li><a class="trn dots" data-target="tools/replace_color.replace_color" href="#">Replace Color</a></li>
<li><a class="trn dots" data-target="tools/restore_alpha.restore_alpha" href="#">Restore alpha</a></li>
<li class="more">
<a class="trn" href="#">External</a>
<ul>
<li><a class="trn external" target="_blank" href="https://tinypng.com/">Compress PNG and JPEG</a>
</ul>
</li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="tools/settings.settings" href="#">Settings</a></li>
</ul>
</li>
<li>
<a class="trn" href="#">Help</a>
<ul>
<li><a class="trn dots" data-target="help/shortcuts.shortcuts" href="#">Keyboard Shortcuts</a></li>
<li><a class="trn external" target="_blank" href="https://github.com/viliusle/miniPaint/issues">Report issues</a></li>
<li class="more">
<a class="trn" href="#">Language</a>
<ul>
<li><a data-target="help/translate.translate.en" href="#">English</a>
<li><div class="mid-line"></div></li>
<li><a data-target="help/translate.translate.zh" href="#">简体中文</a>
<li><a data-target="help/translate.translate.es" href="#">Español</a>
<li><a data-target="help/translate.translate.fr" href="#">French</a>
<li><a data-target="help/translate.translate.de" href="#">German</a>
<li><a data-target="help/translate.translate.it" href="#">Italiano</a>
<li><a data-target="help/translate.translate.ja" href="#">Japanese</a>
<li><a data-target="help/translate.translate.ko" href="#">Korean</a>
<li><a data-target="help/translate.translate.lt" href="#">Lietuvių</a>
<li><a data-target="help/translate.translate.pt" href="#">Portuguese</a>
<li><a data-target="help/translate.translate.ru" href="#">Russian</a>
<li><a data-target="help/translate.translate.tr" href="#">Turkish</a>
</ul>
</li>
<li><div class="mid-line"></div></li>
<li><a class="trn dots" data-target="help/about.about" href="#">About</a></li>
</ul>
</li>
</ul>
`;
const menuDefinition = [
{
name: 'File',
children: [
{
name: 'New',
target: 'file/new.new'
},
{
divider: true
},
{
name: 'Open',
children: [
{
name: 'Open File',
shortcut: 'O',
ellipsis: true,
target: 'file/open.open_file'
},
{
name: 'Open Directory',
ellipsis: true,
target: 'file/open.open_dir'
},
{
name: 'Open from Webcam',
target: 'file/open.open_webcam'
},
{
name: 'Open URL',
ellipsis: true,
target: 'file/open.open_url'
},
{
name: 'Open Data URL',
ellipsis: true,
target: 'file/open.open_data_url'
},
{
name: 'Open Test Template',
target: 'file/open.open_template_test'
}
]
},
{
name: 'Search Images',
ellipsis: true,
target: 'file/open.search'
},
{
divider: true
},
{
name: 'Export',
ellipsis: true,
shortcut: 'S',
target: 'file/save.export'
},
{
name: 'Save As',
ellipsis: true,
shortcut: 'Shift + S',
target: 'file/save.save'
},
{
name: 'Save As Data URL',
ellipsis: true,
target: 'file/save.save_data_url'
},
{
name: 'Print',
ellipsis: true,
shortcut: 'Ctrl+P',
target: 'file/print.print'
},
{
divider: true
},
{
name: 'Quick Save',
shortcut: 'F9',
target: 'file/quicksave.quicksave'
},
{
name: 'Quick Load',
shortcut: 'F10',
target: 'file/quickload.quickload'
}
]
},
{
name: 'Edit',
children: [
{
name: 'Undo',
shortcut: 'Ctrl+Z',
target: 'edit/undo.undo'
},
{
name: 'Redo',
shortcut: 'Ctrl+Y',
target: 'edit/redo.redo'
},
{
divider: true
},
{
name: 'Delete Selection',
shortcut: 'Del',
target: 'edit/selection.delete'
},
{
name: 'Copy Selection',
target: 'layer/new.new_selection'
},
{
name: 'Copy to Clipboard',
shortcut: 'Ctrl+C',
target: 'edit/copy.copy_to_clipboard'
},
{
name: 'Paste',
shortcut: 'Ctrl+V',
target: 'edit/paste.paste'
},
{
divider: true
},
{
name: 'Select All',
shortcut: 'Ctrl+A',
target: 'edit/selection.select_all'
}
]
},
{
name: 'View',
children: [
{
name: 'Zoom',
children: [
{
name: 'Zoom In',
target: 'view/zoom.in'
},
{
name: 'Zoom Out',
target: 'view/zoom.out'
},
{
divider: true
},
{
name: 'Original Size',
target: 'view/zoom.original'
},
{
name: 'Fit Window',
target: 'view/zoom.auto'
}
]
},
{
name: 'Grid',
shortcut: 'G',
target: 'view/grid.grid'
},
{
name: 'Guides',
children: [
{
name: 'Insert',
ellipsis: true,
target: 'view/guides.insert'
},
{
name: 'Update',
target: 'view/guides.update'
},
{
name: 'Remove all',
target: 'view/guides.remove'
}
]
},
{
name: 'Ruler',
target: 'view/ruler.ruler'
},
{
divider: true
},
{
name: 'Full Screen',
target: 'view/full_screen.fs'
}
]
},
{
name: 'Image',
children: [
{
name: 'Information',
shortcut: 'I',
ellipsis: true,
target: 'image/information.information'
},
{
name: 'Canvas Size',
ellipsis: true,
target: 'image/size.size'
},
{
name: 'Trim',
ellipsis: true,
shortcut: 'T',
target: 'image/trim.trim'
},
{
divider: true
},
{
name: 'Resize',
ellipsis: true,
shortcut: 'R',
target: 'image/resize.resize'
},
{
name: 'Rotate',
ellipsis: true,
target: 'image/rotate.rotate'
},
{
name: 'Flip',
children: [
{
name: 'Vertical',
target: 'image/flip.vertical'
},
{
name: 'Horizontal',
target: 'image/flip.horizontal'
}
]
},
{
name: 'Translate',
ellipsis: true,
target: 'image/translate.translate'
},
{
name: 'Opacity',
ellipsis: true,
target: 'image/opacity.opacity'
},
{
divider: true
},
{
name: 'Color Corrections',
ellipsis: true,
target: 'image/color_corrections.color_corrections'
},
{
name: 'Auto Adjust Colors',
shortcut: 'F',
target: 'image/auto_adjust.auto_adjust'
},
{
name: 'Decrease Color Depth',
target: 'image/decrease_colors.decrease_colors'
},
{
name: 'Color Palette',
ellipsis: true,
target: 'image/palette.palette'
},
{
divider: true
},
{
name: 'Histogram',
ellipsis: true,
target: 'image/histogram.histogram'
}
]
},
{
name: 'Layer',
children: [
{
name: 'New',
shortcut: 'N',
target: 'layer/new.new'
},
{
name: 'New from Selection',
target: 'layer/new.new_selection'
},
{
divider: true
},
{
name: 'Duplicate',
shortcut: 'D',
target: 'layer/duplicate.duplicate'
},
{
name: 'Show / Hide',
target: 'layer/visibility.toggle'
},
{
name: 'Delete',
target: 'layer/delete.delete'
},
{
name: 'Convert to Raster',
target: 'layer/raster.raster'
},
{
divider: true
},
{
name: 'Move',
children: [
{
name: 'Up',
target: 'layer/move.up'
},
{
name: 'Down',
target: 'layer/move.down'
}
]
},
{
name: 'Composition',
ellipsis: true,
target: 'layer/composition.composition'
},
{
name: 'Rename',
ellipsis: true,
target: 'layer/rename.rename'
},
{
name: 'Clear',
target: 'layer/clear.clear'
},
{
divider: true
},
{
name: 'Differences Down',
target: 'layer/differences.differences'
},
{
name: 'Merge Down',
target: 'layer/merge.merge'
},
{
name: 'Flatten Image',
target: 'layer/flatten.flatten'
}
]
},
{
name: 'Effects',
children: [
{
name: 'Effect browser',
ellipsis: true,
target: 'effects/browser.browser'
},
{
divider: true
},
{
name: 'Common Filters',
children: [
{
name: 'Gaussian Blur',
ellipsis: true,
target: 'effects/common/blur.blur'
},
{
name: 'Brightness',
ellipsis: true,
target: 'effects/common/brightness.brightness'
},
{
name: 'Contrast',
ellipsis: true,
target: 'effects/common/contrast.contrast'
},
{
name: 'Grayscale',
ellipsis: true,
target: 'effects/common/grayscale.grayscale'
},
{
name: 'Hue Rotate',
ellipsis: true,
target: 'effects/common/hue-rotate.hue_rotate'
},
{
name: 'Negative',
ellipsis: true,
target: 'effects/common/invert.invert'
},
{
name: 'Saturate',
ellipsis: true,
target: 'effects/common/saturate.saturate'
},
{
name: 'Sepia',
ellipsis: true,
target: 'effects/common/sepia.sepia'
},
{
name: 'Shadow',
ellipsis: true,
target: 'effects/common/shadow.shadow'
},
]
},
{
name: 'Instagram Filters',
children: [
{
name: '1977',
target: 'effects/instagram/1977.1977'
},
{
name: 'Aden',
target: 'effects/instagram/aden.aden'
},
{
name: 'Clarendon',
target: 'effects/instagram/clarendon.clarendon'
},
{
name: 'Gingham',
target: 'effects/instagram/gingham.gingham'
},
{
name: 'Inkwell',
target: 'effects/instagram/inkwell.inkwell'
},
{
name: 'Lo-fi',
target: 'effects/instagram/lofi.lofi'
},
{
name: 'Toaster',
target: 'effects/instagram/toaster.toaster'
},
{
name: 'Valencia',
target: 'effects/instagram/valencia.valencia'
},
{
name: 'X-Pro II',
target: 'effects/instagram/xpro2.xpro2'
}
]
},
{
name: 'Black and White',
ellipsis: true,
target: 'effects/black_and_white.black_and_white'
},
{
name: 'Borders',
ellipsis: true,
target: 'effects/borders.borders'
},
{
name: 'Blueprint',
target: 'effects/blueprint.blueprint'
},
{
name: 'Box Blur',
ellipsis: true,
target: 'effects/box_blur.box_blur'
},
{
name: 'Denoise',
ellipsis: true,
target: 'effects/denoise.denoise'
},
{
name: 'Dither',
ellipsis: true,
target: 'effects/dither.dither'
},
{
name: 'Dot Screen',
ellipsis: true,
target: 'effects/dot_screen.dot_screen'
},
{
name: 'Edge',
target: 'effects/edge.edge'
},
{
name: 'Emboss',
target: 'effects/emboss.emboss'
},
{
name: 'Enrich',
ellipsis: true,
target: 'effects/enrich.enrich'
},
{
name: 'Grains',
ellipsis: true,
target: 'effects/grains.grains'
},
{
name: 'Heatmap',
target: 'effects/heatmap.heatmap'
},
{
name: 'Mosaic',
ellipsis: true,
target: 'effects/mosaic.mosaic'
},
{
name: 'Night Vision',
target: 'effects/night_vision.night_vision'
},
{
name: 'Oil',
ellipsis: true,
target: 'effects/oil.oil'
},
{
name: 'Pencil',
target: 'effects/pencil.pencil'
},
{
name: 'Sharpen',
ellipsis: true,
target: 'effects/sharpen.sharpen'
},
{
name: 'Solarize',
target: 'effects/solarize.solarize'
},
{
name: 'Tilt Shift',
ellipsis: true,
target: 'effects/tilt_shift.tilt_shift'
},
{
name: 'Vignette',
ellipsis: true,
target: 'effects/vignette.vignette'
},
{
name: 'Vibrance',
ellipsis: true,
target: 'effects/vibrance.vibrance'
},
{
name: 'Vintage',
ellipsis: true,
target: 'effects/vintage.vintage'
},
{
name: 'Zoom Blur',
ellipsis: true,
target: 'effects/zoom_blur.zoom_blur'
}
]
},
{
name: 'Tools',
children: [
{
name: 'Sprites',
target: 'tools/sprites.sprites'
},
{
name: 'Key-Points',
target: 'tools/keypoints.keypoints'
},
{
name: 'Content Fill',
ellipsis: true,
target: 'tools/content_fill.content_fill'
},
{
divider: true
},
{
name: 'Color Zoom',
ellipsis: true,
target: 'tools/color_zoom.color_zoom'
},
{
name: 'Replace Color',
ellipsis: true,
target: 'tools/replace_color.replace_color'
},
{
name: 'Restore Alpha',
ellipsis: true,
target: 'tools/restore_alpha.restore_alpha'
},
{
name: 'External',
children: [
{
name: 'TINYPNG - Compress PNG and JPEG',
href: 'https://tinypng.com'
},
{
name: 'REMOVE.BG - Remove Image Background',
href: 'https://www.remove.bg'
},
{
name: 'PNGTOSVG - Convert Image to SVG',
href: 'https://www.pngtosvg.com'
},
{
name: 'SQUOOSH - Compress and Compare Images',
href: 'https://squoosh.app'
}
]
},
{
divider: true
},
{
name: 'Language',
children: [
{
name: 'English',
target: 'tools/translate.translate',
parameter: 'en',
},
{
divider: true
},
{
//Arabic
name: 'عربي',
target: 'tools/translate.translate',
parameter: 'ar',
},
{
//Chinese simplified
name: '简体中文',
target: 'tools/translate.translate',
parameter: 'zh',
},
{
name: 'Deutsch',
target: 'tools/translate.translate',
parameter: 'de',
},
{
name: 'Dutch',
target: 'tools/translate.translate',
parameter: 'nl',
},
{
name: 'English (UK)',
target: 'tools/translate.translate',
parameter: 'uk',
},
{
name: 'Español',
target: 'tools/translate.translate',
parameter: 'es',
},
{
name: 'Français',
target: 'tools/translate.translate',
parameter: 'fr',
},
{
name: 'Greek',
target: 'tools/translate.translate',
parameter: 'el',
},
{
name: 'Italiano',
target: 'tools/translate.translate',
parameter: 'it',
},
{
//Japanese
name: '日本語',
target: 'tools/translate.translate',
parameter: 'ja',
},
{
//Korean
name: '한국어',
target: 'tools/translate.translate',
parameter: 'ko',
},
{
name: 'Lietuvių',
target: 'tools/translate.translate',
parameter: 'lt',
},
{
name: 'Português',
target: 'tools/translate.translate',
parameter: 'pt',
},
{
name: 'русский язык',
target: 'tools/translate.translate',
parameter: 'ru',
},
{
name: 'Türkçe',
target: 'tools/translate.translate',
parameter: 'tr',
}
]
},
{
name: 'Search',
shortcut: 'F3',
ellipsis: true,
target: 'tools/search.search'
},
{
name: 'Settings',
ellipsis: true,
target: 'tools/settings.settings'
}
]
},
{
name: 'Help',
children: [
{
name: 'Keyboard Shortcuts',
ellipsis: true,
target: 'help/shortcuts.shortcuts'
},
{
name: 'Report Issues',
href: 'https://github.com/viliusle/miniPaint/issues'
},
{
divider: true
},
{
name: 'About',
ellipsis: true,
target: 'help/about.about'
}
]
}
];
export default menu_template;
export default menuDefinition;

View File

@ -12,11 +12,24 @@ config.visible_height = null;
config.COLOR = '#008000';
config.ALPHA = 255;
config.ZOOM = 1;
config.SNAP = true;
config.pixabay_key = '3ca2cd8af3fde33af218bea02-9021417';
config.safe_search_can_be_disabled = true;
config.google_webfonts_key = 'AIzaSyAC_Tx8RKkvN235fXCUyi_5XhSaRCzNhMg';
config.layers = [];
config.layer = null;
config.need_render = false;
config.need_render_changed_params = false; // Set specifically when param change in layer details triggered render
config.mouse = {};
config.mouse_lock = null;
config.swatches = {
default: [] // Only default used right now, object format for swatch swapping in future.
};
config.user_fonts = {};
config.guides_enabled = true;
config.guides = [];
config.ruler_active = false;
config.enable_autoresize_by_default = true;
//requires styles in reset.css
config.themes = [
@ -25,6 +38,47 @@ config.themes = [
'green',
];
//no-translate BEGIN
config.FONTS = [
"Arial",
"Courier",
"Impact",
"Helvetica",
"Monospace",
"Tahoma",
"Times New Roman",
"Verdana",
"Amatic SC",
"Arimo",
"Codystar",
"Creepster",
"Indie Flower",
"Lato",
"Lora",
"Merriweather",
"Monoton",
"Montserrat",
"Mukta",
"Muli",
"Nosifer",
"Nunito",
"Oswald",
"Orbitron",
"Pacifico",
"PT Sans",
"PT Serif",
"Playfair Display",
"Poppins",
"Raleway",
"Roboto",
"Rubik",
"Special Elite",
"Tangerine",
"Titillium Web",
"Ubuntu"
];
//no-translate END
config.TOOLS = [
{
name: 'select',
@ -35,37 +89,31 @@ config.TOOLS = [
},
{
name: 'selection',
title: 'Selection',
attributes: {},
on_leave: 'on_leave',
},
{
name: 'brush',
title: 'Brush',
attributes: {
size: 4,
smart_brush: true,
pressure: false,
},
},
{
name: 'pencil',
title: 'Pencil',
on_update: 'on_params_update',
attributes: {
antialiasing: true,
size: 2,
size: 1,
pressure: false,
},
},
{
name: 'pick_color',
title: 'Pick Color',
attributes: {
global: false,
},
},
{
name: 'erase',
title: 'Erase',
on_update: 'on_params_update',
attributes: {
size: 30,
@ -74,8 +122,8 @@ config.TOOLS = [
},
},
{
name: 'magic_wand',
title: 'Magic Wand Tool',
name: 'magic_erase',
title: 'Magic Eraser Tool',
attributes: {
power: 15,
anti_aliasing: true,
@ -84,7 +132,6 @@ config.TOOLS = [
},
{
name: 'fill',
title: 'Fill',
attributes: {
power: 5,
anti_aliasing: false,
@ -92,51 +139,295 @@ config.TOOLS = [
},
},
{
name: 'line',
title: 'Line',
name: 'shape',
on_activate: 'on_activate',
title: 'Shapes (H)',
attributes: {
size: 1,
type: {
value: 'Simple',
values: ['Simple', 'Arrow'],
},
size: 3,
stroke: '#00aa00',
},
},
{
name: 'line',
visible: false,
attributes: {
size: 4,
},
},
{
name: 'arrow',
visible: false,
attributes: {
size: 4,
},
},
{
name: 'rectangle',
title: 'Rectangle',
visible: false,
attributes: {
size: 1,
radius: 0,
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
radius: {
value: 0,
min: 0,
},
square: false,
},
},
{
name: 'circle',
title: 'Circle',
name: 'ellipse',
visible: false,
attributes: {
size: 1,
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
circle: false,
},
},
{
name: 'media',
title: 'Search images',
title: 'Search Images',
on_activate: 'on_activate',
attributes: {
size: 30,
},
},
{
name: 'triangle',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'right_triangle',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'romb',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'parallelogram',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'trapezoid',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'plus',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'pentagon',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'hexagon',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'star',
visible: false,
attributes: {
border_size: 4,
corners: 5,
inner_radius: 40,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'heart',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'cylinder',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'human',
visible: false,
attributes: {
border_size: 4,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'tear',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'cog',
visible: false,
attributes: {
fill_color: '#555555',
},
},
{
name: 'bezier_curve',
visible: false,
attributes: {
size: 4,
},
},
{
name: 'moon',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'callout',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
{
name: 'text',
title: 'Text',
attributes: {},
on_update: 'on_params_update',
attributes: {
font: {
value: 'Arial',
values() {
const user_font_names = Object.keys(config.user_fonts);
return ['', '[Add Font...]', ...Array.from(new Set([...config.FONTS, ...user_font_names].sort()))];
}
},
size: 40,
bold: {
value: false,
icon: `bold.svg`
},
italic: {
value: false,
icon: `italic.svg`
},
underline: {
value: false,
icon: `underline.svg`
},
strikethrough: {
value: false,
icon: `strikethrough.svg`
},
fill: '#008800',
stroke: '#000000',
stroke_size: {
value: 0,
min: 0,
step: 0.1
},
kerning: {
value: 0,
min: -999,
max: 999,
step: 1
},
leading: {
value: 0,
min: -999,
max: 999,
step: 1
}
},
},
{
name: 'gradient',
title: 'Gradient',
attributes: {
color_1: '#008000',
color_2: '#ffffff',
@ -147,7 +438,6 @@ config.TOOLS = [
},
{
name: 'clone',
title: 'Clone tool',
attributes: {
size: 30,
anti_aliasing: true,
@ -159,7 +449,6 @@ config.TOOLS = [
},
{
name: 'crop',
title: 'Crop',
on_update: 'on_params_update',
on_leave: 'on_leave',
attributes: {
@ -168,7 +457,6 @@ config.TOOLS = [
},
{
name: 'blur',
title: 'Blur tool',
attributes: {
size: 30,
strength: 1,
@ -176,14 +464,12 @@ config.TOOLS = [
},
{
name: 'sharpen',
title: 'Sharpen tool',
attributes: {
size: 30,
},
},
{
name: 'desaturate',
title: 'Desaturate',
attributes: {
size: 50,
anti_aliasing: true,
@ -191,7 +477,7 @@ config.TOOLS = [
},
{
name: 'bulge_pinch',
title: 'Bulge/Pinch tool',
title: 'Bulge/Pinch Tool',
attributes: {
radius: 80,
power: 50,
@ -200,7 +486,7 @@ config.TOOLS = [
},
{
name: 'animation',
title: 'Play animation',
on_activate: 'on_activate',
on_update: 'on_params_update',
on_leave: 'on_leave',
attributes: {
@ -208,10 +494,20 @@ config.TOOLS = [
delay: 400,
},
},
{
name: 'polygon',
visible: false,
attributes: {
border_size: 4,
border: true,
fill: true,
border_color: '#555555',
fill_color: '#aaaaaa',
},
},
];
//link to active tool
config.TOOL = config.TOOLS[2];
export default config;

View File

@ -4,6 +4,7 @@
*/
import config from './../config.js';
import Base_layers_class from './base-layers.js';
import GUI_tools_class from './gui/gui-tools.js';
import GUI_preview_class from './gui/gui-preview.js';
import GUI_colors_class from './gui/gui-colors.js';
@ -11,7 +12,8 @@ import GUI_layers_class from './gui/gui-layers.js';
import GUI_information_class from './gui/gui-information.js';
import GUI_details_class from './gui/gui-details.js';
import GUI_menu_class from './gui/gui-menu.js';
import Help_translate_class from './../modules/help/translate.js';
import Tools_translate_class from './../modules/tools/translate.js';
import Tools_settings_class from './../modules/tools/settings.js';
import Helper_class from './../libs/helpers.js';
import alertify from './../../../node_modules/alertifyjs/build/alertify.min.js';
@ -30,16 +32,19 @@ class Base_gui_class {
instance = this;
this.Helper = new Helper_class();
this.Base_layers = new Base_layers_class();
//last used menu id
this.last_menu = '';
//grid dimnesions config
//grid dimensions config
this.grid_size = [50, 50];
//if grid is visible
this.grid = false;
this.canvas_offset = {x: 0, y: 0};
//common image dimensions
this.common_dimensions = [
[640, 480, '480p'],
@ -59,10 +64,18 @@ class Base_gui_class {
this.GUI_information = new GUI_information_class(this);
this.GUI_details = new GUI_details_class(this);
this.GUI_menu = new GUI_menu_class();
this.Help_translate = new Help_translate_class();
this.Tools_translate = new Tools_translate_class();
this.Tools_settings = new Tools_settings_class();
this.modules = {};
}
init() {
this.load_modules();
this.load_default_values();
this.render_main_gui();
this.init_service_worker();
}
load_modules() {
var _this = this;
var modules_context = require.context("./../modules/", true, /\.js$/);
@ -98,6 +111,26 @@ class Base_gui_class {
if (transparency_type) {
config.TRANSPARENCY_TYPE = transparency_type;
}
//snap
var snap_cookie = this.Helper.getCookie('snap');
if (snap_cookie === null) {
//default
config.SNAP = true;
}
else{
config.SNAP = Boolean(snap_cookie);
}
//guides
var guides_cookie = this.Helper.getCookie('guides');
if (guides_cookie === null) {
//default
config.guides_enabled = true;
}
else{
config.guides_enabled = Boolean(guides_cookie);
}
}
render_main_gui() {
@ -118,37 +151,37 @@ class Base_gui_class {
this.load_translations();
}
init_service_worker() {
/*if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./service-worker.js').then(function(reg) {
//Successfully registered service worker
}).catch(function(err) {
console.warn('Error registering service worker', err);
});
}*/
}
set_events() {
var _this = this;
//menu events
var targets = document.querySelectorAll('#main_menu a');
for (var i = 0; i < targets.length; i++) {
if (targets[i].dataset.target == undefined)
continue;
targets[i].addEventListener('click', function (event) {
var parts = this.dataset.target.split('.');
var module = parts[0];
var function_name = parts[1];
var param = parts[2];
this.GUI_menu.on('select_target', (target, object) => {
var parts = target.split('.');
var module = parts[0];
var function_name = parts[1];
var param = object.parameter ??= null;
//close menu
var menu = document.querySelector('#main_menu .selected');
if (menu != undefined) {
menu.click();
}
//call module
if (_this.modules[module] == undefined) {
alertify.error('Modules class not found: ' + module);
return;
}
if (_this.modules[module][function_name] == undefined) {
alertify.error('Module function not found. ' + module + '.' + function_name);
return;
}
_this.modules[module][function_name](param);
});
}
//call module
if (this.modules[module] == undefined) {
alertify.error('Modules class not found: ' + module);
return;
}
if (this.modules[module][function_name] == undefined) {
alertify.error('Module function not found. ' + module + '.' + function_name);
return;
}
this.modules[module][function_name](param);
});
//registerToggleAbility
var targets = document.querySelectorAll('.toggle');
@ -160,13 +193,16 @@ class Base_gui_class {
var target = document.getElementById(this.dataset.target);
target.classList.toggle('hidden');
//save
if (_this.Helper.strpos(target.classList, 'hidden') === false)
if (target.classList.contains('hidden') == false)
_this.Helper.setCookie(this.dataset.target, 1);
else
_this.Helper.setCookie(this.dataset.target, 0);
});
}
document.getElementById('left_mobile_menu_button').addEventListener('click', function (event) {
document.querySelector('.sidebar_left').classList.toggle('active');
});
document.getElementById('mobile_menu_button').addEventListener('click', function (event) {
document.querySelector('.sidebar_right').classList.toggle('active');
});
@ -175,6 +211,29 @@ class Base_gui_class {
_this.prepare_canvas();
config.need_render = true;
}, false);
this.check_canvas_offset();
//confirmation on exit
var exit_confirm = this.Tools_settings.get_setting('exit_confirm');
window.addEventListener('beforeunload', function (e) {
if(exit_confirm && (config.layers.length > 1 || _this.Base_layers.is_layer_empty(config.layer.id) == false)){
e.preventDefault();
e.returnValue = '';
}
return undefined;
});
document.getElementById('canvas_minipaint').addEventListener('contextmenu', function (e) {
e.preventDefault();
}, false);
}
check_canvas_offset() {
//calc canvas position offset
var bodyRect = document.body.getBoundingClientRect();
var canvas_el = document.getElementById('canvas_minipaint').getBoundingClientRect();
this.canvas_offset.x = canvas_el.left - bodyRect.left;
this.canvas_offset.y = canvas_el.top - bodyRect.top;
}
prepare_canvas() {
@ -194,16 +253,20 @@ class Base_gui_class {
config.visible_width = w;
config.visible_height = h;
ctx.webkitImageSmoothingEnabled = false;
ctx.oImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
if(config.ZOOM >= 1) {
ctx.imageSmoothingEnabled = false;
}
else{
ctx.imageSmoothingEnabled = true;
}
this.render_canvas_background('canvas_minipaint');
//change wrapper dimensions
document.getElementById('canvas_wrapper').style.width = w + 'px';
document.getElementById('canvas_wrapper').style.height = h + 'px';
this.check_canvas_offset();
}
load_saved_changes() {
@ -232,7 +295,7 @@ class Base_gui_class {
if (lang != null && lang != config.LANG) {
config.LANG = lang.replace(/([^a-z]+)/gi, '');
this.Help_translate.translate(config.LANG);
this.Tools_translate.translate(config.LANG);
}
}
@ -242,37 +305,23 @@ class Base_gui_class {
var page_h = wrapper.clientHeight;
var auto_size = false;
var save_resolution_cookie = this.Helper.getCookie('save_resolution');
var last_resolution = this.Helper.getCookie('last_resolution');
if (save_resolution_cookie != null && save_resolution_cookie != ''
&& last_resolution != null && last_resolution != '') {
//load last saved resolution
last_resolution = JSON.parse(last_resolution);
config.WIDTH = parseInt(last_resolution[0]);
config.HEIGHT = parseInt(last_resolution[1]);
//use largest possible
for (var i = this.common_dimensions.length - 1; i >= 0; i--) {
if (this.common_dimensions[i][0] > page_w
|| this.common_dimensions[i][1] > page_h) {
//browser size is too small
continue;
}
config.WIDTH = parseInt(this.common_dimensions[i][0]);
config.HEIGHT = parseInt(this.common_dimensions[i][1]);
auto_size = true;
break;
}
else {
//use largest possible
for (var i = this.common_dimensions.length - 1; i >= 0; i--) {
if (this.common_dimensions[i][0] > page_w
|| this.common_dimensions[i][1] > page_h) {
//browser size is too small
continue;
}
config.WIDTH = parseInt(this.common_dimensions[i][0]);
config.HEIGHT = parseInt(this.common_dimensions[i][1]);
auto_size = true;
break;
}
if (auto_size == false) {
//screen size is smaller then 400x300
config.WIDTH = parseInt(page_w) - 5;
config.HEIGHT = parseInt(page_h) - 10;
if (page_w < 585) {
config.HEIGHT = config.HEIGHT - 15;
}
}
if (auto_size == false) {
//screen size is smaller then 400x300
config.WIDTH = parseInt(page_w) - 15;
config.HEIGHT = parseInt(page_h) - 10;
}
}
@ -350,6 +399,41 @@ class Base_gui_class {
ctx.stroke();
}
}
draw_guides(ctx){
if(config.guides_enabled == false){
return;
}
var thick_guides = this.Tools_settings.get_setting('thick_guides');
for(var i in config.guides) {
var guide = config.guides[i];
if (guide.x === 0 || guide.y === 0) {
continue;
}
//set styles
ctx.strokeStyle = '#00b8b8';
if(thick_guides == false)
ctx.lineWidth = 1;
else
ctx.lineWidth = 3;
ctx.beginPath();
if (guide.y === null) {
//vertical
ctx.moveTo(guide.x, 0);
ctx.lineTo(guide.x, config.HEIGHT);
}
if (guide.x === null) {
//horizontal
ctx.moveTo(0, guide.y);
ctx.lineTo(config.WIDTH, guide.y);
}
ctx.stroke();
}
}
/**
* change draw area size
@ -387,24 +471,48 @@ class Base_gui_class {
*
* @param {string} theme_name
*/
change_theme(theme_name){
if(theme_name == undefined){
change_theme(theme_name = null){
if(theme_name == null){
//auto detect
var theme_cookie = this.Helper.getCookie('theme');
if (theme_cookie) {
theme_name = theme_cookie;
}
else {
theme_name = config.themes[0];
theme_name = this.Tools_settings.get_setting('theme');
}
}
for(var i in config.themes){
document.querySelector('body').classList.remove('theme-' + config.themes[i]);
document.querySelector('body').classList.remove('theme-' + config.themes[i]);
}
document.querySelector('body').classList.add('theme-' + theme_name);
}
get_language() {
return config.LANG;
}
get_color() {
return config.COLOR;
}
get_alpha() {
return config.ALPHA;
}
get_zoom() {
return config.ZOOM;
}
get_transparency_support() {
return config.TRANSPARENCY;
}
get_active_tool() {
return config.TOOL;
}
}
export default Base_gui_class;

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