diff --git a/.gitignore b/.gitignore index 1bdbebc0..41c1deac 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,8 @@ npm-debug.log # builds build +# marked as private +*.private.* + # Closure compiler generated JS binary. closure_compiled_binary.js \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 2201f43e..01ea242a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -65,7 +65,7 @@ module.exports = function(grunt) { } }, ghost : { - 'default' : getGhostConfig(3000), + 'default' : getGhostConfig(5000), local : getGhostConfig(50) }, concat : { diff --git a/css/settings.css b/css/settings.css index 41bf99ce..829a727e 100644 --- a/css/settings.css +++ b/css/settings.css @@ -56,6 +56,13 @@ position: relative; } +.tool-icon.local-storage-icon { + background-image: url(../img/local-storage-icon.png); + background-position: 10px 12px; + background-size: 30px; + position: relative; +} + .tool-icon.import-icon { background-image: url(../img/import-icon.png); background-position: 10px 5px; @@ -247,12 +254,10 @@ } #save-status { - margin-left: 10px; + margin-top: 10px; } .status { height: 1.5rem; - - word-break : break-all; vertical-align: middle; font-weight: normal; text-shadow: none; @@ -264,4 +269,33 @@ [name*=checkbox] { vertical-align: middle; +} + +.local-piskels-list { + width: 100%; +} + +.local-piskel-item { + height: 3em; +} + +.local-piskel-name { + width: 40%; +} + +.local-piskel-save-date { + font-weight : normal; +} + +.local-piskels-list a { + text-decoration: none; +} +.local-piskels-list a:hover { + text-decoration: underline; +} +.local-piskel-load-link { + color : gold; +} +.local-piskel-delete-link { + color : red; } \ No newline at end of file diff --git a/css/spectrum/spectrum-overrides.css b/css/spectrum/spectrum-overrides.css index 1bd874ea..2b214ded 100644 --- a/css/spectrum/spectrum-overrides.css +++ b/css/spectrum/spectrum-overrides.css @@ -25,13 +25,18 @@ /* Remove the padding on the input container */ .sp-replacer { - padding: 3px; + padding: 4px; height: 100%; border-width: 0; box-sizing: border-box; -moz-box-sizing:border-box; background-color: #444; } + +.sp-replacer:hover { + background-color: #888; +} + /* Hide the triangle */ .sp-dd { display: none; diff --git a/css/tools.css b/css/tools.css index 28242a37..bda3cdee 100644 --- a/css/tools.css +++ b/css/tools.css @@ -136,6 +136,36 @@ cursor: url(../img/icons/dropper.png) 0 15, pointer; } +.swap-colors-icon { + background-image: url(../img/tools/swap-arrow-square-small-grey.png); + position: relative; + top: 50px; + left: 6px; + height: 18px; + width: 18px; + background-size: 18px; + opacity : 0.3; + cursor : pointer; +} + +.swap-colors-icon:hover { + opacity : 1; +} + +.tool-color-picker { + position:relative; +} + +.tool-color-picker:nth-child(1) { + z-index : 100; +} + +.tool-color-picker:nth-child(2) { + z-index : 90; + margin-top: 20px; + margin-left:-20px; +} + .tool-color-picker input { width: 16px; height: 16px; @@ -155,6 +185,7 @@ .palette-wrapper { margin-top: 10px; + margin-left: 10px; } .palette-color[data-color=TRANSPARENT] { diff --git a/img/local-storage-icon.png b/img/local-storage-icon.png new file mode 100644 index 00000000..d9b757e7 Binary files /dev/null and b/img/local-storage-icon.png differ diff --git a/img/tools/swap-arrow-square-small-grey.png b/img/tools/swap-arrow-square-small-grey.png new file mode 100644 index 00000000..ce91d240 Binary files /dev/null and b/img/tools/swap-arrow-square-small-grey.png differ diff --git a/index.html b/index.html index 08bbd11b..05d758b1 100644 --- a/index.html +++ b/index.html @@ -9,8 +9,8 @@ -
+
diff --git a/js/Events.js b/js/Events.js index aebb0306..b7b4523e 100644 --- a/js/Events.js +++ b/js/Events.js @@ -29,6 +29,8 @@ var Events = { */ PISKEL_RESET: "PISKEL_RESET", + PISKEL_SAVED: "PISKEL_SAVED", + FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED", SELECTION_CREATED: "SELECTION_CREATED", diff --git a/js/app.js b/js/app.js index 3f37fcc0..c8a93526 100644 --- a/js/app.js +++ b/js/app.js @@ -75,6 +75,9 @@ this.cheatsheetService = new pskl.service.keyboard.CheatsheetService(); this.cheatsheetService.init(); + this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController); + this.savedStatusService.init(); + if (this.isAppEngineVersion) { this.storageService = new pskl.service.AppEngineStorageService(this.piskelController); } else { @@ -103,8 +106,6 @@ "content" : "Loading animation with id : [" + framesheetId + "]" }]); this.loadFramesheetFromService(framesheetId); - } else { - this.localStorageService.displayRestoreNotification(); } }, @@ -118,6 +119,10 @@ } }, + isLoggedIn : function () { + return pskl.appEnginePiskelData_ && pskl.appEnginePiskelData_.isLoggedIn; + }, + initTooltips_ : function () { $('body').tooltip({ selector: '[rel=tooltip]' diff --git a/js/controller/PaletteController.js b/js/controller/PaletteController.js index 93f658e7..786ced1e 100644 --- a/js/controller/PaletteController.js +++ b/js/controller/PaletteController.js @@ -43,6 +43,8 @@ secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this)); this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker); + var swapColorsIcon = $('.swap-colors-icon'); + swapColorsIcon.click(this.swapColors.bind(this)); }; /** diff --git a/js/controller/ToolController.js b/js/controller/ToolController.js index 0e2d42dc..9126cb44 100644 --- a/js/controller/ToolController.js +++ b/js/controller/ToolController.js @@ -36,7 +36,7 @@ // Set SimplePen as default selected tool: this.selectTool_(this.tools[0]); // Activate listener on tool panel: - $("#tool-section").click($.proxy(this.onToolIconClicked_, this)); + $("#tool-section").mousedown($.proxy(this.onToolIconClicked_, this)); }; /** @@ -47,6 +47,7 @@ var previousSelectedToolClass = stage.data("selected-tool-class"); if(previousSelectedToolClass) { stage.removeClass(previousSelectedToolClass); + stage.removeClass(pskl.drawingtools.Move.TOOL_ID); } stage.addClass(tool.instance.toolId); stage.data("selected-tool-class", tool.instance.toolId); diff --git a/js/controller/settings/LocalStorageController.js b/js/controller/settings/LocalStorageController.js new file mode 100644 index 00000000..9e6fc80f --- /dev/null +++ b/js/controller/settings/LocalStorageController.js @@ -0,0 +1,70 @@ +(function () { + var ns = $.namespace("pskl.controller.settings"); + + ns.LocalStorageController = function () {}; + + /** + * @public + */ + ns.LocalStorageController.prototype.init = function() { + this.localStorageItemTemplate_ = pskl.utils.Template.get("local-storage-item-template"); + this.service_ = pskl.app.localStorageService; + this.piskelsList = $('.local-piskels-list'); + + this.fillLocalPiskelsList_(); + + this.piskelsList.click(this.onPiskelsListClick_.bind(this)); + }; + + ns.LocalStorageController.prototype.onPiskelsListClick_ = function (evt) { + var action = evt.target.getAttribute('data-action'); + var name = evt.target.getAttribute('data-name'); + if (action === 'load') { + if (window.confirm('This will erase your current piskel. Continue ?')) { + this.service_.load(name); + $.publish(Events.CLOSE_SETTINGS_DRAWER); + } + } else if (action === 'delete') { + if (window.confirm('This will permanently DELETE this piskel from your computer. Continue ?')) { + this.service_.remove(name); + $.publish(Events.CLOSE_SETTINGS_DRAWER); + } + } + }; + + ns.LocalStorageController.prototype.fillLocalPiskelsList_ = function () { + var html = ""; + var keys = this.service_.getKeys(); + + var pad = function (num) { + if (num < 10) { + return "0" + num; + } else { + return "" + num; + } + }; + + + keys.sort(function (k1, k2) { + if (k1.date < k2.date) {return 1;} + if (k1.date > k2.date) {return -1;} + return 0; + }); + + keys.forEach((function (key) { + var date = new Date(key.date); + var formattedDate = pskl.utils.Template.replace("{{Y}}/{{M}}/{{D}} {{H}}:{{m}}", { + Y : date.getFullYear(), + M : pad(date.getMonth() + 1), + D : pad(date.getDate()), + H : pad(date.getHours()), + m : pad(date.getMinutes()) + }); + html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : formattedDate}); + }).bind(this)); + + var tableBody_ = this.piskelsList.get(0).tBodies[0]; + tableBody_.innerHTML = html; + }; + +})(); \ No newline at end of file diff --git a/js/controller/settings/SaveController.js b/js/controller/settings/SaveController.js index 0b10eebe..01c7a6f9 100644 --- a/js/controller/settings/SaveController.js +++ b/js/controller/settings/SaveController.js @@ -13,7 +13,12 @@ this.nameInput = $('#save-name'); this.descriptionInput = $('#save-description'); this.isPublicCheckbox = $('input[name=save-public-checkbox]'); - this.saveButton = $('#save-button'); + this.saveCloudButton = $('#save-cloud-button'); + this.saveLocalButton = $('#save-local-button'); + + // Only available in app-engine mode ... + this.piskelName = $('.piskel-name').get(0); + this.status = $('#save-status'); var descriptor = this.piskelController.piskel.getDescriptor(); @@ -22,21 +27,22 @@ this.isPublicCheckbox.prop('checked', descriptor.isPublic); - if (!pskl.app.isAppEngineVersion) { - this.nameInput.attr('disabled', 'disabled'); - this.descriptionInput.attr('disabled', 'disabled'); - this.isPublicCheckbox.attr('disabled', 'disabled'); + if (!pskl.app.isLoggedIn()) { + this.saveCloudButton.attr('disabled', 'disabled'); + this.status.html('You are not logged in. Only Local Save is available.'); + } else { + this.saveForm.submit(this.onSaveFormSubmit_.bind(this)); } - this.saveForm.submit(this.onSaveFormSubmit_.bind(this)); + this.saveLocalButton.click(this.onSaveLocalClick_.bind(this)); }; ns.SaveController.prototype.onSaveFormSubmit_ = function (evt) { evt.preventDefault(); evt.stopPropagation(); - var name = this.nameInput.val(); - var description = this.descriptionInput.val(); + var name = this.getName(); + var description = this.getDescription(); var isPublic = !!this.isPublicCheckbox.prop('checked'); var descriptor = new pskl.model.piskel.Descriptor(name, description, isPublic); @@ -50,15 +56,46 @@ }); }; + ns.SaveController.prototype.onSaveLocalClick_ = function (evt) { + var localStorageService = pskl.app.localStorageService; + var isOk = true; + var name = this.getName(); + var description = this.getDescription(); + if (localStorageService.getPiskel(name)) { + isOk = window.confirm('There is already a piskel saved as ' + name + '. Override ?'); + } + + if (isOk) { + this.beforeSaving_(); + localStorageService.save(name, description, pskl.app.piskelController.serialize()); + window.setTimeout(function () { + this.onSaveSuccess_(); + this.afterSaving_(); + }.bind(this), 1000); + } + }; + + ns.SaveController.prototype.getName = function () { + return this.nameInput.val(); + }; + + ns.SaveController.prototype.getDescription = function () { + return this.descriptionInput.val(); + }; + ns.SaveController.prototype.beforeSaving_ = function () { - this.saveButton.attr('disabled', true); + this.saveCloudButton.attr('disabled', true); this.status.html('Saving ...'); - $('.piskel-name').get(0).classList.add('piskel-name-saving'); + + if (this.piskelName) { + this.piskelName.classList.add('piskel-name-saving'); + } }; ns.SaveController.prototype.onSaveSuccess_ = function () { $.publish(Events.CLOSE_SETTINGS_DRAWER); $.publish(Events.SHOW_NOTIFICATION, [{"content": "Successfully saved !"}]); + $.publish(Events.PISKEL_SAVED); }; ns.SaveController.prototype.onSaveError_ = function (status) { @@ -66,9 +103,12 @@ }; ns.SaveController.prototype.afterSaving_ = function () { - this.saveButton.attr('disabled', false); + this.saveCloudButton.attr('disabled', false); this.status.html(''); - $('.piskel-name').get(0).classList.remove('piskel-name-saving'); + + if (this.piskelName) { + this.piskelName.classList.remove('piskel-name-saving'); + } window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); }; diff --git a/js/controller/settings/SettingsController.js b/js/controller/settings/SettingsController.js index bc1f0318..de4a0bd9 100644 --- a/js/controller/settings/SettingsController.js +++ b/js/controller/settings/SettingsController.js @@ -18,6 +18,10 @@ template : 'templates/settings/import.html', controller : ns.ImportController }, + 'localstorage' : { + template : 'templates/settings/localstorage.html', + controller : ns.LocalStorageController + }, 'save' : { template : 'templates/settings/save.html', controller : ns.SaveController diff --git a/js/drawingtools/Move.js b/js/drawingtools/Move.js index 1635e0cf..0ff49857 100644 --- a/js/drawingtools/Move.js +++ b/js/drawingtools/Move.js @@ -7,7 +7,7 @@ var ns = $.namespace("pskl.drawingtools"); ns.Move = function() { - this.toolId = "tool-move"; + this.toolId = ns.Move.TOOL_ID; this.helpText = "Move tool"; // Stroke's first point coordinates (set in applyToolAt) @@ -15,6 +15,8 @@ this.startRow = null; }; + ns.Move.TOOL_ID = "tool-move"; + pskl.utils.inherit(ns.Move, ns.BaseTool); /** diff --git a/js/drawingtools/selectiontools/BaseSelect.js b/js/drawingtools/selectiontools/BaseSelect.js index b5ca0da1..b6cb3b0b 100644 --- a/js/drawingtools/selectiontools/BaseSelect.js +++ b/js/drawingtools/selectiontools/BaseSelect.js @@ -7,7 +7,7 @@ var ns = $.namespace("pskl.drawingtools"); ns.BaseSelect = function() { - this.secondaryToolId = "tool-move"; + this.secondaryToolId = pskl.drawingtools.Move.TOOL_ID; this.BodyRoot = $('body'); // Select's first point coordinates (set in applyToolAt) diff --git a/js/service/LocalStorageService.js b/js/service/LocalStorageService.js index c68cee38..62a174a9 100644 --- a/js/service/LocalStorageService.js +++ b/js/service/LocalStorageService.js @@ -7,83 +7,74 @@ throw "Bad LocalStorageService initialization: "; } this.piskelController = piskelController; - this.localStorageThrottler_ = null; }; - /** - * @public - */ - ns.LocalStorageService.prototype.init = function(piskelController) { - $.subscribe(Events.LOCALSTORAGE_REQUEST, $.proxy(this.persistToLocalStorageRequest_, this)); + ns.LocalStorageService.prototype.init = function() {}; + +// localStorage.setItem('piskel_bkp', pskl.app.piskelController.serialize()) + + ns.LocalStorageService.prototype.save = function(name, description, piskel) { + this.removeFromKeys_(name); + this.addToKeys_(name, description, Date.now()); + window.localStorage.setItem('piskel.' + name, piskel); }; - /** - * @private - */ - ns.LocalStorageService.prototype.persistToLocalStorageRequest_ = function () { - // Persist to localStorage when drawing. We throttle localStorage accesses - // for high frequency drawing (eg mousemove). - if(this.localStorageThrottler_ !== null) { - window.clearTimeout(this.localStorageThrottler_); - } - this.localStorageThrottler_ = window.setTimeout($.proxy(function() { - this.persistToLocalStorage_(); - this.localStorageThrottler_ = null; - }, this), 1000); - }; + ns.LocalStorageService.prototype.load = function(name) { + var piskelString = this.getPiskel(name); + var key = this.getKey_(name); - /** - * @private - */ - ns.LocalStorageService.prototype.persistToLocalStorage_ = function() { - console.log('[LocalStorage service]: Snapshot stored'); - window.localStorage.snapShot = this.piskelController.serialize(); - }; - - /** - * @private - */ - ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() { - var framesheet = JSON.parse(window.localStorage.snapShot); - - pskl.utils.serialization.Deserializer.deserialize(framesheet, function (piskel) { + pskl.utils.serialization.Deserializer.deserialize(JSON.parse(piskelString), function (piskel) { + piskel.setDescriptor(new pskl.model.piskel.Descriptor(name, key.description, true)); pskl.app.piskelController.setPiskel(piskel); }); }; - /** - * @private - */ - ns.LocalStorageService.prototype.cleanLocalStorage_ = function() { - console.log('[LocalStorage service]: Snapshot removed'); - delete window.localStorage.snapShot; + ns.LocalStorageService.prototype.remove = function(name) { + this.removeFromKeys_(name); + window.localStorage.removeItem('piskel.' + name); }; - /** - * @public - */ - ns.LocalStorageService.prototype.displayRestoreNotification = function() { - if(window.localStorage && window.localStorage.snapShot) { - var reloadLink = "reload"; - var discardLink = "discard"; - var content = "Non saved version found. " + reloadLink + " or " + discardLink; + ns.LocalStorageService.prototype.saveKeys_ = function(keys) { + window.localStorage.setItem('piskel.keys', JSON.stringify(keys)); + }; - $.publish(Events.SHOW_NOTIFICATION, [{ - "content": content, - "behavior": $.proxy(function(rootNode) { - rootNode = $(rootNode); - rootNode.click($.proxy(function(evt) { - var target = $(evt.target); - if(target.hasClass("localstorage-restore")) { - this.restoreFromLocalStorage_(); - } - else if (target.hasClass("localstorage-discard")) { - this.cleanLocalStorage_(); - } - $.publish(Events.HIDE_NOTIFICATION); - }, this)); - }, this) - }]); + ns.LocalStorageService.prototype.removeFromKeys_ = function(name) { + var keys = this.getKeys(); + var otherKeys = keys.filter(function (key) { + return key.name !== name; + }); + + this.saveKeys_(otherKeys); + }; + + ns.LocalStorageService.prototype.getKey_ = function(name) { + var matches = this.getKeys().filter(function (key) { + return key.name === name; + }); + if (matches.length > 0) { + return matches[0]; + } else { + return null; } }; + + ns.LocalStorageService.prototype.addToKeys_ = function(name, description, date) { + var keys = this.getKeys(); + keys.push({ + name : name, + description : description, + date : date + }); + this.saveKeys_(keys); + }; + + ns.LocalStorageService.prototype.getPiskel = function(name) { + return window.localStorage.getItem('piskel.' + name); + }; + + ns.LocalStorageService.prototype.getKeys = function(name) { + var keysString = window.localStorage.getItem('piskel.keys'); + return JSON.parse(keysString) || []; + }; + })(); \ No newline at end of file diff --git a/js/service/SavedStatusService.js b/js/service/SavedStatusService.js new file mode 100644 index 00000000..e2445ef4 --- /dev/null +++ b/js/service/SavedStatusService.js @@ -0,0 +1,64 @@ +(function () { + var ns = $.namespace('pskl.service'); + + ns.SavedStatusService = function (piskelController) { + this.piskelController_ = piskelController; + }; + + ns.SavedStatusService.prototype.init = function () { + $.subscribe(Events.TOOL_RELEASED, this.onToolReleased.bind(this)); + $.subscribe(Events.PISKEL_RESET, this.onPiskelReset.bind(this)); + + $.subscribe(Events.PISKEL_SAVED, this.onPiskelSaved.bind(this)); + + window.addEventListener("beforeunload", this.onBeforeUnload.bind(this)); + }; + + ns.SavedStatusService.prototype.onPiskelReset = function () { + var piskel = this.piskelController_.piskel; + // A first PISKEL_RESET is triggered during the load of a new Piskel, it should be ignored + // putting a firstResetDone flag as a nasty workaround for this + if (piskel.firstResetDone_) { + this.updateDirtyStatus(true); + } else { + piskel.firstResetDone_ = true; + } + }; + + ns.SavedStatusService.prototype.onToolReleased = function () { + this.updateDirtyStatus(true); + }; + + ns.SavedStatusService.prototype.onPiskelSaved = function () { + this.updateDirtyStatus(false); + }; + + ns.SavedStatusService.prototype.updateDirtyStatus = function (status) { + var piskel = this.piskelController_.piskel; + if (piskel.isDirty_ !== status) { + // Redraw piskel name only if dirty status actually changed + piskel.isDirty_ = status; + this.updatePiskelName(); + } + }; + + ns.SavedStatusService.prototype.updatePiskelName = function () { + var piskel = this.piskelController_.piskel; + var name = piskel.getDescriptor().name; + if (piskel.isDirty_) { + $('.piskel-name').html(name + ' *'); + } else { + $('.piskel-name').html(name); + } + }; + + ns.SavedStatusService.prototype.onBeforeUnload = function (evt) { + var piskel = this.piskelController_.piskel; + if (piskel.isDirty_) { + var confirmationMessage = "Your Piskel seem to have unsaved changes"; + + (evt || window.event).returnValue = confirmationMessage; + return confirmationMessage; + } + }; +})(); \ No newline at end of file diff --git a/js/utils/serialization/Deserializer.js b/js/utils/serialization/Deserializer.js index 799b1f09..5c35322a 100644 --- a/js/utils/serialization/Deserializer.js +++ b/js/utils/serialization/Deserializer.js @@ -20,11 +20,12 @@ deserializer.deserialize(); }; - ns.Deserializer.prototype.deserialize = function () { + ns.Deserializer.prototype.deserialize = function (name) { var data = this.data_; var piskelData = data.piskel; + name = name || 'Deserialized piskel'; - var descriptor = new pskl.model.piskel.Descriptor('Deserialized piskel', ''); + var descriptor = new pskl.model.piskel.Descriptor(name, ''); this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height, descriptor); this.layersToLoad_ = piskelData.layers.length; diff --git a/piskel-script-list.js b/piskel-script-list.js index 27286eaa..65247a70 100644 --- a/piskel-script-list.js +++ b/piskel-script-list.js @@ -72,6 +72,7 @@ exports.scripts = [ "js/controller/settings/ApplicationSettingsController.js", "js/controller/settings/ResizeController.js", "js/controller/settings/GifExportController.js", + "js/controller/settings/LocalStorageController.js", "js/controller/settings/SaveController.js", "js/controller/settings/ImportController.js", // Settings controller @@ -82,6 +83,7 @@ exports.scripts = [ "js/service/GithubStorageService.js", "js/service/AppEngineStorageService.js", "js/service/HistoryService.js", + "js/service/SavedStatusService.js", "js/service/keyboard/ShortcutService.js", "js/service/keyboard/KeycodeTranslator.js", "js/service/keyboard/CheatsheetService.js", diff --git a/resources/swap-arrow-small.png b/resources/swap-arrow-small.png new file mode 100644 index 00000000..7a60355b Binary files /dev/null and b/resources/swap-arrow-small.png differ diff --git a/resources/swap-arrow-square-small-grey.png b/resources/swap-arrow-square-small-grey.png new file mode 100644 index 00000000..ce91d240 Binary files /dev/null and b/resources/swap-arrow-square-small-grey.png differ diff --git a/resources/swap-arrow-square-small.png b/resources/swap-arrow-square-small.png new file mode 100644 index 00000000..be49877f Binary files /dev/null and b/resources/swap-arrow-square-small.png differ diff --git a/resources/swap-arrow-square.svg b/resources/swap-arrow-square.svg new file mode 100644 index 00000000..d708004c --- /dev/null +++ b/resources/swap-arrow-square.svg @@ -0,0 +1,80 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/resources/swap-arrow.svg b/resources/swap-arrow.svg new file mode 100644 index 00000000..00ecd7f6 --- /dev/null +++ b/resources/swap-arrow.svg @@ -0,0 +1,80 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/templates/drawing-tools.html b/templates/drawing-tools.html index 6f93ab45..47ac6c8e 100644 --- a/templates/drawing-tools.html +++ b/templates/drawing-tools.html @@ -3,12 +3,28 @@
-
+
-
+
+
diff --git a/templates/settings.html b/templates/settings.html index 80ac056c..bb12a438 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -27,6 +27,13 @@ rel="tooltip" data-placement="left">
+
+
+
+
+ Browse Local Piskels +
+
+ + +
+
+ +
\ No newline at end of file diff --git a/templates/settings/save.html b/templates/settings/save.html index a2ac1030..54e6a126 100644 --- a/templates/settings/save.html +++ b/templates/settings/save.html @@ -15,8 +15,9 @@ Public : - - + + +
\ No newline at end of file