diff --git a/src/css/base.css b/src/css/base.css new file mode 100644 index 0000000..511c1ee --- /dev/null +++ b/src/css/base.css @@ -0,0 +1,71 @@ +:root { + /* grays blues reds */ + --z0:rgb(24, 32, 40); --a0: rgb(24, 32, 40); --b0:rgb(41, 23, 35); + --z1:rgb(36, 44, 52); --a1: rgb(34, 52, 68); --b1:rgb(68, 33, 52); + --z2:rgb(49, 56, 64); --a2: rgb(42, 74, 97); --b2:rgb(97, 42, 67); + --z3:rgb(63, 69, 76); --a3: rgb(47, 98, 127); --b3:rgb(129, 51, 79); + --z4:rgb(76, 83, 89); --a4: rgb(49, 122,159); --b4:rgb(161, 60, 88); + --z5:rgb(91, 97, 103); --a5: rgb(48, 148,191); --b5:rgb(193, 71, 94); + --z6:rgb(105, 111, 116); --a6: rgb(40, 174, 223); --b6:rgb(225, 84, 97); + --z7:rgb(120, 125, 130); --a7: rgb(14, 202, 255); --b7:rgb(255, 100, 96); + --z8:rgb(120, 125, 130); --a8: rgb(14, 202, 255); --b8:rgb(255, 100, 96); + --z9:rgb(137, 142, 146); --a9: rgb(89, 209, 254); --b9:rgb(255, 125, 116); + --z10:rgb(155, 159, 163); --a10:rgb(126, 216, 254); --b10:rgb(255, 147, 137); + --z11:rgb(174, 177, 180); --a11:rgb(155, 223, 253); --b11:rgb(255, 168, 159); + --z12:rgb(192, 195, 197); --a12:rgb(181, 230, 253); --b12:rgb(255, 189, 181); + --z13:rgb(211, 213, 214); --a13:rgb(205, 237, 252); --b13:rgb(255, 210, 204); + --z14:rgb(230, 231, 232); --a14:rgb(228, 243, 251); --b14:rgb(255, 230, 227); + --z15:rgb(250, 250, 250); --a15:rgb(250, 250, 250); --b15:rgb(250, 250, 250); + -webkit-font-smoothing: antialiased; +} + +.inverted { + --z15:rgb(24, 32, 40); --a15:rgb(24, 32, 40); --b15:rgb(41, 23, 35); + --z14:rgb(36, 44, 52); --a14:rgb(34, 52, 68); --b14:rgb(68, 33, 52); + --z13:rgb(49, 56, 64); --a13:rgb(42, 74, 97); --b13:rgb(97, 42, 67); + --z12:rgb(63, 69, 76); --a12:rgb(47, 98, 127); --b12:rgb(129, 51, 79); + --z11:rgb(76, 83, 89); --a11:rgb(49, 122, 159); --b11:rgb(161, 60, 88); + --z10:rgb(91, 97, 103); --a10:rgb(48, 148, 191); --b10:rgb(193, 71, 94); + --z9:rgb(105, 111, 116); --a9:rgb(40, 174, 223); --b9 :rgb(225, 84, 97); + --z8:rgb(120, 125, 130); --a8:rgb(14, 202, 255); --b8 :rgb(255, 100, 96); + --z7:rgb(120, 125, 130); --a7:rgb(14, 202, 255); --b7 :rgb(255, 100, 96); + --z6:rgb(137, 142, 146); --a6:rgb(89, 209, 254); --b6 :rgb(255, 125, 116); + --z5:rgb(155, 159, 163); --a5:rgb(126, 216, 254); --b5 :rgb(255, 147, 137); + --z4:rgb(174, 177, 180); --a4:rgb(155, 223, 253); --b4 :rgb(255, 168, 159); + --z3:rgb(192, 195, 197); --a3:rgb(181, 230, 253); --b3 :rgb(255, 189, 181); + --z2:rgb(211, 213, 214); --a2:rgb(205, 237, 252); --b2 :rgb(255, 210, 204); + --z1:rgb(230, 231, 232); --a1:rgb(228, 243, 251); --b1 :rgb(255, 230, 227); + --z0:rgb(250, 250, 250); --a0:rgb(250, 250, 250); --b0 :rgb(250, 250, 250); + -webkit-font-smoothing: auto; +} + +:root { + --x1: 4px; + --x2: 8px; + --x3: 12px; + --x4: 16px; + --x5: 20px; + --x6: 24px; + --x7: 28px; + --x8: 32px; + --x9: 36px; + --x10: 40px; + --x11: 44px; + --x12: 48px; + --x13: 52px; + --x14: 56px; + --x15: 60px; + + --mono-font: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; + --ui-font: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; + --transition-duration: 333ms; + --transition-fast: 200ms; +} + +a, a:link, a:active, a:visited { + color: var(--a6); +} + +a:hover { + color: var(--a8); +} \ No newline at end of file diff --git a/src/css/dialog.css b/src/css/dialog.css new file mode 100644 index 0000000..ee6e17b --- /dev/null +++ b/src/css/dialog.css @@ -0,0 +1,74 @@ + +#dialog_box { + display: none; +} + +#dialog_box_overlay { + background: black; + opacity: .5; + height:100%; + left:0; + position:absolute; + top:0; + width:100%; + z-index: 6; +} + +#dialog_content { + height: 95px; + padding: 32px; + overflow: auto; + text-align: left; + font-size: 16px; +} + +#dialog_content h4 { + margin: 0; +} + + +#dialog_buttons input:last-child { + position: absolute; + left: 10px; + bottom: 10px; +} + +#dialog_buttons input:first-child { + position: absolute; + right: 10px; + bottom: 10px; +} + +#dialog_content.prompt { + height: 75px; +} + +#dialog_content p { + line-height: 1.3em; +} + +#dialog_container { + position: absolute; + left: 50%; + top: 50%; + width: 400px; + transform: translate(-50%, -50%); + position:fixed; + z-index:50001; + background: #fff; +} + + +#dialog_container, #dialog_content { + border-radius: 3px; +} + +#dialog_buttons input[type=text] { + width: 90%; + display: block; + margin: 0 0 5px 11px; +} + +#dialog_buttons input[type=button] { + margin: 0 1em; +} diff --git a/src/css/draginput.css b/src/css/draginput.css index a7c7f15..4f8cb57 100644 --- a/src/css/draginput.css +++ b/src/css/draginput.css @@ -27,7 +27,6 @@ font-size: 14px; color: white; font-weight: bold; - font-family: sans-serif; } .draginput label#resolution_label, .draginput label#seg_type_label { @@ -73,7 +72,6 @@ padding: 0 5px; color: #333; z-index: 10; - font-family: sans-serif; font-weight: bold; text-align: right; padding-right: 10px; diff --git a/src/css/keyboard.css b/src/css/keyboard.css new file mode 100644 index 0000000..9fa32a6 --- /dev/null +++ b/src/css/keyboard.css @@ -0,0 +1,25 @@ +#shortcuts { + columns: 4; +} +.shortcut-keys { + display: flex; + margin: var(--x1) 0; + break-inside: avoid; +} + +.shortcut-key { + text-transform: uppercase; + color: var(--z4); + border: solid var(--z4) 1px; + border-radius: var(--x1); + padding: 0 var(--x1); + margin: 2px; + font-size: 12px; + font-weight: 600; +} + +.shortcut-name { + margin-left: var(--x2); + line-height: 160%; + white-space: nowrap; +} \ No newline at end of file diff --git a/src/css/menu.css b/src/css/menu.css index f2af515..dffea28 100644 --- a/src/css/menu.css +++ b/src/css/menu.css @@ -1,4 +1,3 @@ - #menu { display: none; position: absolute; @@ -111,7 +110,7 @@ .menu_list .menu_item:hover, .menu_list .menu_item.push_button_pressed:hover { - background: rgba(0,0,0,0.1); + background: var(--a14); color: #000; } diff --git a/src/css/method-draw.css b/src/css/method-draw.css index 1cdf314..95925c1 100644 --- a/src/css/method-draw.css +++ b/src/css/method-draw.css @@ -1,5 +1,6 @@ /* Comment to prevent wrong concat */ + body { background: #3f3f3c; font: 14px/120% -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; @@ -331,26 +332,56 @@ div#font-selector .font-item:hover { input[type=text].tuco, input[type=number].tuco {width: 150px;} input[type=submit], input[type=button], button { - background: #4F80FF; - color: #fff; - border-radius: 3px; - padding: 7px 17px; + background: var(--a7); + color: var(--z1); + border-radius: var(--x1); + padding: var(--x2) var(--x4); border: none; line-height: 140%; - font-size: 14px; - font-weight: bold; - font-family: sans-serif; - + font-size: 16px; + font-weight: 550; + cursor: pointer; } - input[type=submit]:hover, button:hover { -box-shadow: inset 0 3px 10px rgba(255, 255, 255, 0.1), - inset 0 -3px 10px rgba(0, 0, 0, 0.2); +input[type=submit]:hover, +input[type=button]:hover, +button:hover { + background: var(--a9); } - input[type=submit]:hover, button:hover {background: #2F84C1;} - input[type=submit]:active, button:active { box-shadow: inset 0 2px 2px rgba(0,0,0,0.2); border-bottom: solid rgba(255,255,255,0.1) 1px;} +input[type=submit]:active, +input[type=button]:active, +button:active { + box-shadow: 0 0 0 var(--x1) var(--a14); + outline: none; +} +input[type=submit]:focus, +input[type=button]:focus, +button:focus { + outline: none; +} + + button.cancel, input.Cancel, input.cancel, input.jGraduate_Cancel, button.cancel { + -webkit-appearance: none; + background-color: var(--z10); + margin: 0; +} + + button.cancel:hover, input.Cancel:hover, input.cancel:hover, input.jGraduate_Cancel:hover, button.cancel:hover { + background-color: var(--z11); +} + + button.warning { + -webkit-appearance: none; + background-color: var(--b6); + color: var(--z15); + margin: 0; +} + + button.warning:hover { + background-color: var(--b7); + } #tools_left { position: absolute; @@ -591,164 +622,14 @@ input[type=file] { background-color: #F4E284; } -#svg_source_editor { - display: none; -} - -#svg_source_editor #svg_source_overlay { - position: absolute; - top: 0px; - right: 0px; - left: 0px; - bottom: 0px; - background-color: black; - opacity: 0.6; - z-index: 5; -} - -#svg_source_editor #svg_source_container { - position: absolute; - top: 30px; - left: 100px; - right: 100px; - bottom: 30px; - background-color: #fff; - border-radius: 3px; - opacity: 1.0; - text-align: center; - z-index: 6; - padding: 15px 0; -} - -#svg_source_editor form { - position: absolute; - display: block; - top: 15px; - bottom: 55px; - left: 15px; - right: 12px; - padding: 5px; - font-size: 12px; -} - -#svg_source_textarea { - width: 100%; - height: 100%; - line-height: 140%; - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; -} - -#svg_source_editor #tool_source_back { - position: absolute; - bottom: 45px; - left: 15px; - right: 15px; -} - -#svg_source_editor #tool_source_back #tool_source_save { - display: block; - position: absolute; - right: 0; -} - - -#svg_source_editor #tool_source_back #tool_source_cancel { - display: block; - position: absolute; - left: 0; -} - - - button.cancel, input.Cancel, input.cancel, input.jGraduate_Cancel, button.cancel { - -webkit-appearance: none; - background-color: #999; - box-shadow: 0 0 1px rgba(0,0,0,0.5); - margin: 0; -} - .toolbar_button button .svg_icon { display: none; } -#dialog_box { - display: none; -} - -#dialog_box_overlay { - background: black; - opacity: .5; - height:100%; - left:0; - position:absolute; - top:0; - width:100%; - z-index: 6; -} - -#dialog_content { - height: 95px; - margin: 10px 10px 5px 10px; - overflow: auto; - text-align: left; - font-size: 13px; -} - -#dialog_buttons input:last-child { - background: #999 !important; - position: absolute; - left: 10px; - bottom: 10px; -} - -#dialog_buttons input:first-child { - position: absolute; - right: 10px; - bottom: 10px; -} - -#dialog_content.prompt { - height: 75px; -} - -#dialog_content p { - margin: 10px; - line-height: 1.3em; -} - -#dialog_container { - position: absolute; - left: 50%; - top: 50%; - width: 300px; - margin-left: -150px; - height: 150px; - margin-top: -80px; - position:fixed; - z-index:50001; - background: #fff; -} - - -#dialog_container, #dialog_content { - border-radius: 3px; -} - -#dialog_buttons input[type=text] { - width: 90%; - display: block; - margin: 0 0 5px 11px; -} - -#dialog_buttons input[type=button] { - margin: 0 1em; -} - .invisible { visibility: none; } - .touch .shortcut { display: none; } diff --git a/src/css/modal.css b/src/css/modal.css new file mode 100644 index 0000000..5ca792d --- /dev/null +++ b/src/css/modal.css @@ -0,0 +1,45 @@ +.modal { + background: rgba(50,50,50,0.8); + position: absolute; + z-index: 1000; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + opacity: 1; + font-size: 16px; + line-height: 150%; +} + +.modal.hidden { + opacity: 0; + pointer-events: none; + transition: opacity 300ms ease; +} + +.modal-item { + background-color: white; + position: relative; + border-radius: var(--x1); + padding: var(--x12); + max-width: 600px; + margin: 32px; +} + +.modal-item.modal-item-wide { + max-width: none; + width: 900px; +} + +.modal-item.modal-item-source { + height: 504px; + max-width: none; + width: 704px; +} + +.modal h1:first-child { + margin-top: 0; +} \ No newline at end of file diff --git a/src/css/source.css b/src/css/source.css new file mode 100644 index 0000000..ea0c159 --- /dev/null +++ b/src/css/source.css @@ -0,0 +1,45 @@ +#svg_source_editor { + position: relative; + width: 800px; + height: 600px; + margin: -48px; +} + +#svg_source_container { + width: 800px; + position: relative; + height: 100%; +} + +#svg_source_editor form { + position: absolute; + top: 0; + bottom: 55px; + left: 0; + right: 0; + font-size: 14px; + background-color: #eee; + border-radius: 8px 8px 0 0; +} + +#svg_source_textarea { + width: calc(100% - 64px); + height: calc(100% - 64px); + line-height: 140%; + font-family: var(--mono-font); + font-size: 14px; + color: #555; + border: none; + padding: 32px; + background-color: transparent; +} + +#svg_source_editor #tool_source_back { + position: absolute; + display: flex; + justify-content: space-between; + bottom: 0; + left: 0; + right: 0; + padding: var(--x2) var(--x2); +} diff --git a/src/index.html b/src/index.html index cf35caf..76dea1d 100644 --- a/src/index.html +++ b/src/index.html @@ -11,6 +11,7 @@ + @@ -22,6 +23,10 @@ + + + + @@ -59,10 +64,11 @@ @@ -119,7 +125,7 @@
- + @@ -629,22 +635,7 @@ -
-
-
-
-

Copy the contents of this box into a text editor, then save the file with a .svg extension.

- -
-
- -
-
- - -
-
-
+
diff --git a/src/js/Keyboard.js b/src/js/Keyboard.js index fd0b375..d409ec9 100644 --- a/src/js/Keyboard.js +++ b/src/js/Keyboard.js @@ -1,4 +1,62 @@ MD.Keyboard = function(){ + + const keys = { + "v": { name: "Select tool", cb: ()=> state.set("canvasMode", "select") }, + "q": { name: "Freehand tool", cb: ()=> state.set("canvasMode", "fhpath") }, + "l": { name: "Line tool", cb: ()=> state.set("canvasMode", "fhplineath")}, + "r": { name: "Rectangle tool", cb: ()=> state.set("canvasMode", "rect")}, + "o": { name: "Ellipse tool", cb: ()=> state.set("canvasMode", "ellipse")}, + "s": { name: "Shape tool", cb: ()=> state.set("canvasMode", "shapelib")}, + "p": { name: "Path tool", cb: ()=> state.set("canvasMode", "path")}, + "t": { name: "Text tool", cb: ()=> state.set("canvasMode", "text")}, + "z": { name: "Zoom tool", cb: ()=> state.set("canvasMode", "zoom")}, + "e": { name: "Eyedropper tool", cb: ()=> state.set("canvasMode", "eyedropper")}, + "x": { name: "Switch fill/stroke", cb: ()=> editor.switchPaint()}, + "alt": { name: false, cb: ()=> $("#workarea").toggleClass("out", canvasMode === "zoom" )}, + "cmd_s": { name: "Save SVG File", cb: ()=> editor.save()}, + "cmd_z": { name: "Undo", cb: ()=> editor.undo()}, + "cmd_y": { name: "Redo", cb: ()=> editor.redo()}, + "cmd_shift_z": { name: "Redo", cb: ()=> editor.redo()}, + "cmd_c": { name: "Copy", cb: ()=> editor.copySelected()}, + "cmd_x": { name: "Cut", cb: ()=> editor.cutSelected()}, + "cmd_v": { name: "Paste", cb: ()=> editor.pasteSelected()}, + "cmd_d": { name: "Duplicate", cb: ()=> editor.duplicateSelected()}, + "cmd_u": { name: "View source", cb: ()=> editor.source()}, + "cmd_a": { name: "Select All", cb: ()=> svgCanvas.selectAllInCurrentLayer()}, + "cmd_b": { name: "Set bold text", cb: ()=> editor.text.setBold()}, + "cmd_i": { name: "Set italic text", cb: ()=> editor.text.setItalic()}, + "cmd_g": { name: "Group selected", cb: ()=> editor.groupSelected()}, + "cmd_shift_g": { name: "Ungroup", cb: ()=> editor.ungroupSelected()}, + "cmd_o": { name: "Open SVG File", cb: ()=> editor.import.open()}, + "cmd_k": { name: "Place image", cb: ()=> editor.import.place()}, + "backspace": { name: "Delete", cb: ()=> editor.deleteSelected()}, + "ctrl_arrowleft": { name: "Rotate -1deg", cb: ()=> editor.rotateSelected(0,1)}, + "ctrl_arrowright": { name: "Rotate +1deg", cb: ()=> editor.rotateSelected(1,1)}, + "ctrl_shift_arrowleft": { name: "Rotate -5deg", cb: ()=> editor.rotateSelected(0,5)}, + "ctrl_shift_arrowright": { name: "Rotate +5deg ", cb: ()=> editor.rotateSelected(1,5)}, + "shift_o": { name: "Next item", cb: ()=> svgCanvas.cycleElement(0)}, + "shift_p": { name: "Prev item", cb: ()=> svgCanvas.cycleElement(1)}, + "shift_r": { name: "Show/hide rulers", cb: ()=> editor.rulers.toggleRulers()}, + "cmd_+": { name: "Zoom in", cb: ()=> editor.zoom.multiply(1.5)}, + "cmd_-": { name: "Zoom out", cb: ()=> editor.zoom.multiply(0.75)}, + "cmd_=": { name: "Actual size", cb: ()=> editor.zoom.reset()}, + "arrowleft": { name: "Nudge left", cb: ()=> editor.moveSelected(-1,0)}, + "arrowright": { name: "Nudge right", cb: ()=> editor.moveSelected(1,0)}, + "arrowup": { name: "Nudge up", cb: ()=> editor.moveSelected(0,-1)}, + "arrowdown": { name: "Nudge down", cb: ()=> editor.moveSelected(0,1)}, + "shift_arrowleft": {name: "Jump left", cb: () => editor.moveSelected(state.get("canvasSnapStep") * -1, 0)}, + "shift_arrowright": {name: "Jump right", cb: () => editor.moveSelected(state.get("canvasSnapStep") * 1, 0)}, + "shift_arrowup": {name: "Jump up", cb: () => editor.moveSelected(0, state.get("canvasSnapStep") * -1)}, + "shift_arrowdown": {name: "Jump down", cb: () => editor.moveSelected(0, state.get("canvasSnapStep") * 1)}, + "cmd_arrowup":{ name: "Bring forward", cb: () => editor.moveUpSelected()}, + "cmd_arrowdown":{ name: "Send backward", cb: () => editor.moveDownSelected()}, + "cmd_shift_arrowup":{ name: "Bring to front", cb: () => editor.moveToTopSelected()}, + "cmd_shift_arrowdown":{ name: "Send to back", cb: () => editor.moveToBottomSelected()}, + "escape": { name: false, cb: ()=> editor.escapeMode()}, + "enter": { name: false, cb: ()=> editor.escapeMode()}, + " ": { name: "Pan canvas", cb: ()=> editor.pan.startPan()}, + }; + document.addEventListener("keydown", function(e){ if ($("#color_picker").is(":visible")) return e; const modKey = !svgedit.browser.isMac() ? "ctrlKey" : "metaKey"; @@ -6,67 +64,18 @@ MD.Keyboard = function(){ const shift = e.shiftKey ? "shift_" : ""; const key = cmd + shift + e.key.toLowerCase(); const canvasMode = state.get("canvasMode"); - const keys = { - v: ()=> state.set("canvasMode", "select"), - q: ()=> state.set("canvasMode", "fhpath"), - l: ()=> state.set("canvasMode", "line"), - r: ()=> state.set("canvasMode", "rect"), - o: ()=> state.set("canvasMode", "ellipse"), - s: ()=> state.set("canvasMode", "shapelib"), - p: ()=> state.set("canvasMode", "path"), - t: ()=> state.set("canvasMode", "text"), - z: ()=> state.set("canvasMode", "zoom"), - e: ()=> state.set("canvasMode", "eyedropper"), - x: ()=> editor.switchPaint(), - "alt": ()=> { if (canvasMode === "zoom") $("#workarea").addClass("out") }, - "cmd_s": ()=> editor.save(), - "cmd_z": ()=> editor.undo(), - "cmd_shift_z": ()=> editor.redo(), - "cmd_c": ()=> editor.copySelected(), - "cmd_x": ()=> editor.cutSelected(), - "cmd_v": ()=> editor.pasteSelected(), - "cmd_d": ()=> editor.duplicateSelected(), - "cmd_u": ()=> editor.modal.viewSource(), - "cmd_a": ()=> svgCanvas.selectAllInCurrentLayer(), - "cmd_b": ()=> editor.text.setBold(), - "cmd_i": ()=> editor.text.setItalic(), - "cmd_g": ()=> editor.groupSelected(), - "cmd_o": ()=> editor.import.open(), - "cmd_k": ()=> editor.import.place(), - "cmd_shift_g": ()=> editor.ungroupSelected(), - "backspace": () => editor.deleteSelected(), - "ctrl_arrowleft": () => editor.rotateSelected(0,1), - "ctrl_arrowright": () => editor.rotateSelected(1,1), - "ctrl_shift_arrowleft": () => editor.rotateSelected(0,5), - "ctrl_shift_arrowright": () => editor.rotateSelected(1,5), - "shift_o": () => svgCanvas.cycleElement(0), - "shift_p": () => svgCanvas.cycleElement(1), - "shift_r": () => editor.rulers.toggleRulers(), - "cmd_+": () => editor.zoom.multiply(1.5), - "cmd_=": () => editor.zoom.multiply(1.5), - "cmd_-": () => editor.zoom.multiply(0.75), - "arrowleft": () => editor.moveSelected(-1,0), - "arrowright": () => editor.moveSelected(1,0), - "arrowup": () => editor.moveSelected(0,-1), - "arrowdown": () => editor.moveSelected(0,1), - "cmd_arrowup": () => editor.moveUpSelected(), - "cmd_arrowdown": () => editor.moveDownSelected(), - "cmd_shift_arrowup": () => editor.moveToTopSelected(), - "cmd_shift_arrowdown": () => editor.moveToBottomSelected(), - "shift_arrowleft": () => editor.moveSelected(state.get("canvasSnapStep") * -1, 0), - "shift_arrowright": () => editor.moveSelected(state.get("canvasSnapStep") * 1, 0), - "shift_arrowup": () => editor.moveSelected(0, state.get("canvasSnapStep") * -1), - "shift_arrowdown": () => editor.moveSelected(0, state.get("canvasSnapStep") * 1), - "escape": () => editor.escapeMode(), - "enter": () => editor.escapeMode(), - " ": ()=> editor.pan.startPan(), - }; + + const modalIsOpen = Object.values(editor.modal).filter((modal) => { + const isHidden = modal.el.classList.contains("hidden"); + if (!isHidden && key === "cmd_enter") modal.confirm(); + if (!isHidden && key === "escape") modal.close(); + return !isHidden; + }).length; - // keyboard shortcut exists - if (keys[key]) { - if (editor.modal.isVisible()) return; + // keyboard shortcut exists for app + if (!modalIsOpen && keys[key]) { e.preventDefault(); - keys[key](); + keys[key].cb(); } }); @@ -85,4 +94,41 @@ MD.Keyboard = function(){ }) + // modal shortcuts + const shortcutEl = document.getElementById("shortcuts"); + const docFrag = document.createDocumentFragment(); + for (const key in keys) { + const name = keys[key].name; + if (!name) continue; + const shortcut = document.createElement("div"); + shortcut.classList.add("shortcut") + const chords = key.split("_"); + const shortcutKeys = document.createElement("div"); + shortcutKeys.classList.add("shortcut-keys") + chords.forEach(key => { + const shortcutKey = document.createElement("div"); + shortcutKey.classList.add("shortcut-key"); + if (key === "arrowright") key = "→"; + if (key === "arrowleft") key = "←"; + if (key === "arrowup") key = "↑"; + if (key === "arrowdown") key = "↓"; + if (key === " ") key = "SPACEBAR"; + if (key === "shift") key = "⇧"; + if (key === "cmd") key = svgedit.browser.isMac ? "⌘" : "Ctrl"; + shortcutKey.textContent = key; + shortcutKeys.appendChild(shortcutKey); + shortcut.appendChild(shortcutKeys); + }); + + const shortcutName = document.createElement("div"); + shortcutName.classList.add("shortcut-name"); + shortcutName.textContent = name; + shortcutKeys.appendChild(shortcutName); + + docFrag.appendChild(shortcutKeys); + } + + shortcutEl.appendChild(docFrag); + + } \ No newline at end of file diff --git a/src/js/Menu.js b/src/js/Menu.js index a859c04..c3c090a 100644 --- a/src/js/Menu.js +++ b/src/js/Menu.js @@ -8,7 +8,9 @@ MD.Menu = function(){ $('#tool_topath').on("click", editor.convertToPath); $('#tool_group').on("click", editor.groupSelected); $('#tool_ungroup').on("click", editor.ungroupSelected); - + $('#tool_ungroup').on("click", editor.ungroupSelected); + if (window.location.host !== "editor.method.ac") + $('#modal_donate').hide(); // top dropdown menus $('.menu_title') .on('mousedown', function() { diff --git a/src/js/Modal.js b/src/js/Modal.js index 273cff7..452d596 100644 --- a/src/js/Modal.js +++ b/src/js/Modal.js @@ -1,66 +1,47 @@ -MD.Modal = function(){ +MD.Modal = function(config){ - var orig_source = false; + const el = document.createElement("div"); + el.classList.add("modal", "hidden"); - $("button.cancel, .overlay").on("click", cancelOverlays); - $("#tool_source").on("click", viewSource); - $("#tool_source_save").on("click", saveSource); + const item = document.createElement("div"); + item.innerHTML = config.html; + item.classList.add("modal-item"); + el.appendChild(item); - function viewSource(e, forSaving){ - editor.menu.flash($('#view_menu')); - $('#save_output_btns').toggle(!!forSaving); - $('#tool_source_back').toggle(!forSaving); - orig_source = svgCanvas.getSvgString(); - $('#svg_source_textarea').val(orig_source); - $('#svg_source_editor').fadeIn(); - $('#svg_source_textarea').focus().select(); - }; + el.addEventListener("click", close); + + item.addEventListener("click", function(e){ + e.stopPropagation(); + }); - function saveSource(){ - var saveChanges = function() { - svgCanvas.clearSelection(); - $('#svg_source_editor').hide(); - $('#svg_source_textarea').blur(); - editor.zoom.multiply(1); - editor.rulers.update(); - editor.paintBox.fill.prep(); - editor.paintBox.stroke.prep(); - } + document.body.appendChild(el); - if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { - $.confirm("There were parsing errors in your SVG source.\nRevert back to original SVG source?", function(ok) { - if(!ok) return false; - saveChanges(); - }); - } else { - saveChanges(); - } - }; - function cancelOverlays() { - $('#dialog_box').hide(); - if (orig_source && orig_source !== $('#svg_source_textarea').val()) { - $.confirm("Ignore changes made to SVG source?", function(ok) { - if(ok) { - $('#svg_source_editor').hide(); - $('#svg_source_textarea').blur(); - }; - }); - } else { - $('#svg_source_editor').hide(); - $('#svg_source_textarea').blur(); - } - }; - - function isVisible(){ - return $('#svg_source_editor').is(":visible"); + function open(){ + el.classList.remove("hidden"); } - this.cancelOverlays = cancelOverlays; - this.isVisible = isVisible; - this.viewSource = viewSource; - this.saveSource = saveSource; + function close(){ + el.classList.add("hidden"); + } + function confirm(cb){ + if (cb) cb(); + close(); + } + + this.open = open; + this.close = close; + this.confirm = confirm; + this.cb = config.cb || function(){}; + this.el = el; + + if (config.js) { + const el = this.el; + config.js(el); + } + + return this } \ No newline at end of file diff --git a/src/js/dao.js b/src/js/dao.js index b5613cc..91d8973 100644 --- a/src/js/dao.js +++ b/src/js/dao.js @@ -7,7 +7,7 @@ const dao = [ label: "Canvas ID", type: "id", default: "", - private: false, + private: true, save: true }, diff --git a/src/js/dialog.js b/src/js/dialog.js index f0ccbf9..c69ba26 100644 --- a/src/js/dialog.js +++ b/src/js/dialog.js @@ -9,14 +9,14 @@ var box = $('#dialog_box'), btn_holder = $('#dialog_buttons'); var dbox = function(type, msg, callback, defText) { - $('#dialog_content').html('

'+msg.replace(/\n/g,'

')+'

') + $('#dialog_content').html(msg) .toggleClass('prompt',(type==='prompt')); btn_holder.empty(); var ok = $('').appendTo(btn_holder); if(type != 'alert') { - $('') + $('') .appendTo(btn_holder) .on("click touchstart", function() { box.hide();callback(false)}); } diff --git a/src/js/editor.js b/src/js/editor.js index 2ee1607..00efa4f 100644 --- a/src/js/editor.js +++ b/src/js/editor.js @@ -9,7 +9,7 @@ MD.Editor = function(){ function clear(){ var dims = state.get("canvasSize"); - $.confirm("Do you want to clear the drawing?\nThis will also erase your undo history", function(ok) { + $.confirm("

Do you want to clear the drawing?

This will also erase your undo history

", function(ok) { if(!ok) return; state.set("canvasMode", "select") svgCanvas.clear(); @@ -135,6 +135,7 @@ MD.Editor = function(){ }; function escapeMode(){ + for (key in editor.modal) editor.modal[key].close(); state.set("canvasMode", "select"); state.set("canvasContent", svgCanvas.getSvgString()) } @@ -310,6 +311,29 @@ MD.Editor = function(){ } } + function about(){ + editor.modal.about.open(); + } + + function configure(){ + //const props = dao.filter + editor.modal.configure.open(); + } + + function shortcuts(){ + editor.modal.shortcuts.open(); + } + + function donate(){ + editor.modal.donate.open(); + } + + function source(){ + const textarea = editor.modal.source.el.querySelector("textarea"); + textarea.value = svgCanvas.getSvgString(); + editor.modal.source.open(); + } + this.selectedChanged = selectedChanged; this.elementChanged = elementChanged; this.changeAttribute = changeAttribute; @@ -340,6 +364,12 @@ MD.Editor = function(){ this.toggleWireframe = toggleWireframe; this.groupSelected = groupSelected; this.ungroupSelected = ungroupSelected; + this.about = about; + this.configure = configure; + this.shortcuts = shortcuts; + this.donate = donate; + this.source = source; + this.export = function(){ if(window.canvg) { svgCanvas.rasterExport(); diff --git a/src/js/modalbackup.js b/src/js/modalbackup.js new file mode 100644 index 0000000..5016980 --- /dev/null +++ b/src/js/modalbackup.js @@ -0,0 +1,62 @@ + + var orig_source = false; + + $("button.cancel, .overlay").on("click", cancelOverlays); + $("#tool_source").on("click", viewSource); + $("#tool_source_save").on("click", saveSource); + + function viewSource(e, forSaving){ + editor.menu.flash($('#view_menu')); + $('#save_output_btns').toggle(!!forSaving); + $('#tool_source_back').toggle(!forSaving); + orig_source = svgCanvas.getSvgString(); + $('#svg_source_textarea').val(orig_source); + $('#svg_source_editor').fadeIn(); + $('#svg_source_textarea').focus().select(); + }; + + function saveSource(){ + var saveChanges = function() { + svgCanvas.clearSelection(); + $('#svg_source_editor').hide(); + $('#svg_source_textarea').blur(); + editor.zoom.multiply(1); + editor.rulers.update(); + editor.paintBox.fill.prep(); + editor.paintBox.stroke.prep(); + } + + if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { + $.confirm("There were parsing errors in your SVG source.\nRevert back to original SVG source?", function(ok) { + if(!ok) return false; + saveChanges(); + }); + } else { + saveChanges(); + } + }; + + function cancelOverlays() { + $('#dialog_box').hide(); + + if (orig_source && orig_source !== $('#svg_source_textarea').val()) { + $.confirm("Ignore changes made to SVG source?", function(ok) { + if(ok) { + $('#svg_source_editor').hide(); + $('#svg_source_textarea').blur(); + }; + }); + } else { + $('#svg_source_editor').hide(); + $('#svg_source_textarea').blur(); + } + }; + + function isVisible(){ + return $('#svg_source_editor').is(":visible"); + } + + this.cancelOverlays = cancelOverlays; + this.isVisible = isVisible; + this.viewSource = viewSource; + this.saveSource = saveSource; \ No newline at end of file diff --git a/src/js/start.js b/src/js/start.js index 70b170d..0af2a86 100644 --- a/src/js/start.js +++ b/src/js/start.js @@ -1,6 +1,89 @@ // globals const svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas")); const editor = new MD.Editor(); + +editor.modal = { + about: new MD.Modal({ + html: ` +

About this application

+

Method Draw is a simple open source vector drawing application. Method Draw was forked from SVG-Edit several years ago with the goal of improving and modernizing the interface.

+

At this time (2021), the author (Mark MacKay) is working on improving stability and improving the codebase, which contains a lot of legacy practices. The goal is to create a vector editor suitable for simple graphic design tasks.

+ ` + }), + source: new MD.Modal({ + html: ` +
+
+
+
+ +
+
+ + +
+
+
`, + js: function(el){ + el.children[0].classList.add("modal-item-source"); + el.querySelector("#tool_source_save").addEventListener("click", function(){ + var saveChanges = function() { + svgCanvas.clearSelection(); + $('#svg_source_textarea').blur(); + editor.zoom.multiply(1); + editor.rulers.update(); + editor.paintBox.fill.prep(); + editor.paintBox.stroke.prep(); + editor.modal.source.close(); + } + + if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { + $.confirm("There were parsing errors in your SVG source.\nRevert back to original SVG source?", function(ok) { + if(!ok) return false; + saveChanges(); + }); + } else { + saveChanges(); + } + }) + el.querySelector("#tool_source_cancel").addEventListener("click", function(){ + editor.modal.source.close(); + }); + } + }), + configure: new MD.Modal({ + html: ` +

Configuration

+
+ +
+
`, + js: function(el){ + const input = el.querySelector("#configuration button.warning"); + input.addEventListener("click", function(){ + state.clean(); + }) + } + }), + donate: new MD.Modal({ + html: ` +

Donate

+

Lorem ipsum dolor sit amet

` + }), + shortcuts: new MD.Modal({ + html: ` +

Shortcuts

+
`, + js: function(el){ + el.children[0].classList.add("modal-item-wide"); + } + }) +}; + +editor.source(); + +editor.keyboard = new MD.Keyboard(); + editor.menu = new MD.Menu(); editor.toolbar = new MD.Toolbar(); editor.rulers = new MD.Rulers(); @@ -14,9 +97,8 @@ editor.paintBox = { canvas: new MD.PaintBox('#canvas_color', 'canvas') }; editor.palette = new MD.Palette(); -editor.keyboard = new MD.Keyboard(); editor.pan = new MD.Pan(); -editor.modal = new MD.Modal(); + editor.import = new MD.Import(); editor.contextMenu = new MD.ContextMenu(); diff --git a/src/js/state.js b/src/js/state.js index 7788428..1bcc525 100644 --- a/src/js/state.js +++ b/src/js/state.js @@ -34,7 +34,7 @@ function State(){ this.clean = (warn = true) => { if (warn) { - const confirmed = confirm("Deletes all configuration and text, are you sure?"); + const confirmed = confirm("Clears all editor configuration and canvas, are you sure?"); if (!confirmed) return; } diff --git a/src/js/svgcanvas.js b/src/js/svgcanvas.js index f633d64..444ecbc 100644 --- a/src/js/svgcanvas.js +++ b/src/js/svgcanvas.js @@ -94,9 +94,6 @@ var clearSvgContentElement = canvas.clearSvgContentElement = function() { "xmlns:xlink": xlinkns }).appendTo(svgroot); - // TODO: make this string optional and set by the client - var comment = svgdoc.createComment(" Created with Method Draw - http://github.com/duopixel/Method-Draw/ "); - svgcontent.appendChild(comment); }; clearSvgContentElement();