diff --git a/src/lib/code-blast.js b/src/lib/code-blast.js new file mode 100644 index 0000000..fafa9f4 --- /dev/null +++ b/src/lib/code-blast.js @@ -0,0 +1,219 @@ +/* +Based on Joel Besada's lovely experiment +https://twitter.com/JoelBesada/status/670343885655293952 + */ + +;(function () { + var shakeTime = 0, + shakeTimeMax = 0, + shakeIntensity = 5, + lastTime = 0, + particles = [], + particlePointer = 0, + MAX_PARTICLES = 500, + PARTICLE_NUM_RANGE = { min: 5, max: 10 }, + PARTICLE_GRAVITY = 0.08, + PARTICLE_ALPHA_FADEOUT = 0.96, + PARTICLE_VELOCITY_RANGE = { + x: [-1, 1], + y: [-3.5, -1.5] + }, + w = window.innerWidth, + h = window.innerHeight, + effect, + isActive = false; + + var codemirrors = [], cmNode; + var canvas, ctx; + var throttledShake = throttle(shake, 100); + var throttledSpawnParticles = throttle(spawnParticles, 100); + + function getRGBComponents(node) { + var color = getComputedStyle(node).color; + if (color) { + try { + return color.match(/(\d+), (\d+), (\d+)/).slice(1); + } catch(e) { + return [255, 255, 255]; + } + } else { + return [255, 255, 255]; + } + } + + function spawnParticles(cm, type) { + var cursorPos = cm.getCursor(); + var pos = cm.cursorCoords(); + var node = document.elementFromPoint(pos.left - 5, pos.top + 5); + type = cm.getTokenAt(cursorPos); + if (type) { type = type.type; }; + var numParticles = random(PARTICLE_NUM_RANGE.min, PARTICLE_NUM_RANGE.max); + var color = getRGBComponents(node); + for (var i = numParticles; i--;) { + particles[particlePointer] = createParticle(pos.left + 10, pos.top, color); + particlePointer = (particlePointer + 1) % MAX_PARTICLES; + } + } + + function createParticle(x, y, color) { + var p = { + x: x, + y: y + 10, + alpha: 1, + color: color + }; + if (effect === 1) { + p.size = random(2, 4); + p.vx = PARTICLE_VELOCITY_RANGE.x[0] + Math.random() * + (PARTICLE_VELOCITY_RANGE.x[1] - PARTICLE_VELOCITY_RANGE.x[0]); + p.vy = PARTICLE_VELOCITY_RANGE.y[0] + Math.random() * + (PARTICLE_VELOCITY_RANGE.y[1] - PARTICLE_VELOCITY_RANGE.y[0]); + } else if (effect === 2) { + p.size = random(2, 8); + p.drag = 0.92; + p.vx = random(-3, 3); + p.vy = random(-3, 3); + p.wander = 0.15; + p.theta = random(0, 360) * Math.PI / 180; + } + return p; + } + + function effect1(particle) { + particle.vy += PARTICLE_GRAVITY; + particle.x += particle.vx; + particle.y += particle.vy; + + particle.alpha *= PARTICLE_ALPHA_FADEOUT; + + ctx.fillStyle = 'rgba('+ particle.color[0] +','+ particle.color[1] +','+ particle.color[2] + ',' + particle.alpha + ')'; + ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size); + } + + // Effect based on Soulwire's demo: http://codepen.io/soulwire/pen/foktm + function effect2(particle) { + particle.x += particle.vx; + particle.y += particle.vy; + particle.vx *= particle.drag; + particle.vy *= particle.drag; + particle.theta += random( -0.5, 0.5 ); + particle.vx += Math.sin( particle.theta ) * 0.1; + particle.vy += Math.cos( particle.theta ) * 0.1; + particle.size *= 0.96; + + ctx.fillStyle = 'rgba('+ particle.color[0] +','+ particle.color[1] +','+ particle.color[2] + ',' + particle.alpha + ')'; + ctx.beginPath(); + ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI); + ctx.fill(); + } + + function drawParticles(timeDelta) { + var particle; + for (var i = particles.length; i--;) { + particle = particles[i]; + if (!particle || particle.alpha < 0.01 || particle.size <= 0.5) { continue; } + + if (effect === 1) { effect1(particle); } + else if (effect === 2) { effect2(particle); } + } + } + + function shake(editor, time) { + cmNode = editor.getWrapperElement(); + shakeTime = shakeTimeMax = time; + } + + function random(min, max) { + if (!max) { max = min; min = 0; } + return min + ~~(Math.random() * (max - min + 1)) + } + + function throttle (callback, limit) { + var wait = false; + return function () { + if (!wait) { + callback.apply(this, arguments); + wait = true; + setTimeout(function () { + wait = false; + }, limit); + } + } + } + + function loop() { + if (!isActive) { return; } + + ctx.clearRect(0, 0, w, h); + + // get the time past the previous frame + var current_time = new Date().getTime(); + if(!lastTime) lastTime = current_time; + var dt = (current_time - lastTime) / 1000; + lastTime = current_time; + + if (shakeTime > 0) { + shakeTime -= dt; + var magnitude = (shakeTime / shakeTimeMax) * shakeIntensity; + var shakeX = random(-magnitude, magnitude); + var shakeY = random(-magnitude, magnitude); + cmNode.style.transform = 'translate(' + shakeX + 'px,' + shakeY + 'px)'; + } + drawParticles(); + requestAnimationFrame(loop); + } + + function onCodeMirrorChange(editor) { + if (editor.getOption('blastCode') === true || editor.getOption('blastCode').shake === undefined) { + throttledShake(editor, 0.3); + } + throttledSpawnParticles(editor); + } + + + function init(editor) { + isActive = true; + + if (!canvas) { + canvas = document.createElement('canvas'); + ctx = canvas.getContext('2d'), + + canvas.id = 'code-blast-canvas' + canvas.style.position = 'absolute'; + canvas.style.top = 0; + canvas.style.left = 0; + canvas.style.zIndex = 1; + canvas.style.pointerEvents = 'none'; + canvas.width = w; + canvas.height = h; + + document.body.appendChild(canvas); + loop(); + } + + editor.on("change", onCodeMirrorChange); + } + + function destroy(editor) { + editor.off('change', onCodeMirrorChange); + codemirrors.splice(codemirrors.indexOf(editor), 1); + if (!codemirrors.length) { + isActive = false; + if (canvas) { + canvas.remove(); + canvas = null; + } + } + } + + CodeMirror.defineOption('blastCode', false, function(editor, val, old) { + if (val) { + codemirrors.push(editor); + effect = val.effect || 2; + init(editor); + } else { + destroy(editor); + } + + }); +})(); diff --git a/src/lib/codemirror/theme/duotone-dark.css b/src/lib/codemirror/theme/duotone-dark.css new file mode 100644 index 0000000..b09a585 --- /dev/null +++ b/src/lib/codemirror/theme/duotone-dark.css @@ -0,0 +1,35 @@ +/* +Name: DuoTone-Dark +Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes) + +CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/) +*/ + +.cm-s-duotone-dark.CodeMirror { background: #2a2734; color: #6c6783; } +.cm-s-duotone-dark div.CodeMirror-selected { background: #545167!important; } +.cm-s-duotone-dark .CodeMirror-gutters { background: #2a2734; border-right: 0px; } +.cm-s-duotone-dark .CodeMirror-linenumber { color: #545167; } + +/* begin cursor */ +.cm-s-duotone-dark .CodeMirror-cursor { border-left: 1px solid #ffad5c; /* border-left: 1px solid #ffad5c80; */ border-right: .5em solid #ffad5c; /* border-right: .5em solid #ffad5c80; */ opacity: .5; } +.cm-s-duotone-dark .CodeMirror-activeline-background { background: #363342; /* background: #36334280; */ opacity: .5;} +.cm-s-duotone-dark .cm-fat-cursor .CodeMirror-cursor { background: #ffad5c; /* background: #ffad5c80; */ opacity: .5;} +/* end cursor */ + +.cm-s-duotone-dark span.cm-atom, .cm-s-duotone-dark span.cm-number, .cm-s-duotone-dark span.cm-keyword, .cm-s-duotone-dark span.cm-variable, .cm-s-duotone-dark span.cm-attribute, .cm-s-duotone-dark span.cm-quote, .cm-s-duotone-dark span.cm-hr, .cm-s-duotone-dark span.cm-link { color: #ffcc99; } + +.cm-s-duotone-dark span.cm-property { color: #9a86fd; } +.cm-s-duotone-dark span.cm-punctuation, .cm-s-duotone-dark span.cm-unit, .cm-s-duotone-dark span.cm-negative { color: #e09142; } +.cm-s-duotone-dark span.cm-string { color: #ffb870; } +.cm-s-duotone-dark span.cm-operator { color: #ffad5c; } +.cm-s-duotone-dark span.cm-positive { color: #6a51e6; } + +.cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; } +.cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; } +.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; } + +/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */ +.cm-s-duotone-dark span.cm-error, .cm-s-duotone-dark span.cm-invalidchar { color: #f00; } + +.cm-s-duotone-dark span.cm-header { font-weight: normal; } +.cm-s-duotone-dark .CodeMirror-matchingbracket { text-decoration: underline; color: #eeebff !important; } diff --git a/src/lib/codemirror/theme/duotone-light.css b/src/lib/codemirror/theme/duotone-light.css new file mode 100644 index 0000000..80203d1 --- /dev/null +++ b/src/lib/codemirror/theme/duotone-light.css @@ -0,0 +1,36 @@ +/* +Name: DuoTone-Light +Author: by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes) + +CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bram de Haan (https://github.com/atelierbram/) +*/ + +.cm-s-duotone-light.CodeMirror { background: #faf8f5; color: #b29762; } +.cm-s-duotone-light div.CodeMirror-selected { background: #e3dcce !important; } +.cm-s-duotone-light .CodeMirror-gutters { background: #faf8f5; border-right: 0px; } +.cm-s-duotone-light .CodeMirror-linenumber { color: #cdc4b1; } + +/* begin cursor */ +.cm-s-duotone-light .CodeMirror-cursor { border-left: 1px solid #93abdc; /* border-left: 1px solid #93abdc80; */ border-right: .5em solid #93abdc; /* border-right: .5em solid #93abdc80; */ opacity: .5; } +.cm-s-duotone-light .CodeMirror-activeline-background { background: #e3dcce; /* background: #e3dcce80; */ opacity: .5; } +.cm-s-duotone-light .cm-fat-cursor .CodeMirror-cursor { background: #93abdc; /* #93abdc80; */ opacity: .5; } +/* end cursor */ + +.cm-s-duotone-light span.cm-atom, .cm-s-duotone-light span.cm-number, .cm-s-duotone-light span.cm-keyword, .cm-s-duotone-light span.cm-variable, .cm-s-duotone-light span.cm-attribute, .cm-s-duotone-light span.cm-quote, .cm-s-duotone-light-light span.cm-hr, .cm-s-duotone-light-light span.cm-link { color: #063289; } + +.cm-s-duotone-light span.cm-property { color: #b29762; } +.cm-s-duotone-light span.cm-punctuation, .cm-s-duotone-light span.cm-unit, .cm-s-duotone-light span.cm-negative { color: #063289; } +.cm-s-duotone-light span.cm-string, .cm-s-duotone-light span.cm-operator { color: #1659df; } +.cm-s-duotone-light span.cm-positive { color: #896724; } + +.cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; } +.cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; } +.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; } + +/* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */ +/* .cm-s-duotone-light span.cm-error { background: #896724; color: #728fcb; } */ +.cm-s-duotone-light span.cm-error, .cm-s-duotone-light span.cm-invalidchar { color: #f00; } + +.cm-s-duotone-light span.cm-header { font-weight: normal; } +.cm-s-duotone-light .CodeMirror-matchingbracket { text-decoration: underline; color: #faf8f5 !important; } + diff --git a/src/lib/codemirror/theme/panda-syntax.css b/src/lib/codemirror/theme/panda-syntax.css new file mode 100644 index 0000000..c93b2ea --- /dev/null +++ b/src/lib/codemirror/theme/panda-syntax.css @@ -0,0 +1,85 @@ +/* + Name: Panda Syntax + Author: Siamak Mokhtari (http://github.com/siamak/) + CodeMirror template by Siamak Mokhtari (https://github.com/siamak/atom-panda-syntax) +*/ +.cm-s-panda-syntax { + background: #292A2B; + color: #E6E6E6; + line-height: 1.5; + font-family: 'Operator Mono', 'Source Sans Pro', Menlo, Monaco, Consolas, Courier New, monospace; +} +.cm-s-panda-syntax .CodeMirror-cursor { border-color: #ff2c6d; } +.cm-s-panda-syntax .CodeMirror-activeline-background { + background: rgba(99, 123, 156, 0.1); +} +.cm-s-panda-syntax .CodeMirror-selected { + background: #FFF; +} +.cm-s-panda-syntax .cm-comment { + font-style: italic; + color: #676B79; +} +.cm-s-panda-syntax .cm-operator { + color: #f3f3f3; +} +.cm-s-panda-syntax .cm-string { + color: #19F9D8; +} +.cm-s-panda-syntax .cm-string-2 { + color: #FFB86C; +} + +.cm-s-panda-syntax .cm-tag { + color: #ff2c6d; +} +.cm-s-panda-syntax .cm-meta { + color: #b084eb; +} + +.cm-s-panda-syntax .cm-number { + color: #FFB86C; +} +.cm-s-panda-syntax .cm-atom { + color: #ff2c6d; +} +.cm-s-panda-syntax .cm-keyword { + color: #FF75B5; +} +.cm-s-panda-syntax .cm-variable { + color: #ffb86c; +} +.cm-s-panda-syntax .cm-variable-2 { + color: #ff9ac1; +} +.cm-s-panda-syntax .cm-variable-3 { + color: #ff9ac1; +} + +.cm-s-panda-syntax .cm-def { + color: #e6e6e6; +} +.cm-s-panda-syntax .cm-property { + color: #f3f3f3; +} +.cm-s-panda-syntax .cm-unit { + color: #ffb86c; +} + +.cm-s-panda-syntax .cm-attribute { + color: #ffb86c; +} + +.cm-s-panda-syntax .CodeMirror-matchingbracket { + border-bottom: 1px dotted #19F9D8; + padding-bottom: 2px; + color: #e6e6e6; +} +.cm-s-panda-syntax .CodeMirror-gutters { + background: #292a2b; + border-right-color: rgba(255, 255, 255, 0.1); +} +.cm-s-panda-syntax .CodeMirror-linenumber { + color: #e6e6e6; + opacity: 0.6; +} diff --git a/src/script.js b/src/script.js index f7b39fb..7ddc186 100644 --- a/src/script.js +++ b/src/script.js @@ -1164,7 +1164,7 @@ onboardDontShowInTabOptionBtn, TextareaAutoComplete */ $('[data-setting=indentWith]:checked').value !== 'spaces' ); - scope.cm[type].setOption('blastCode', $('[data-setting=isCodeBlastOn]').checked ? { effect: 2 } : false); + scope.cm[type].setOption('blastCode', $('[data-setting=isCodeBlastOn]').checked ? { effect: 2, shake: false } : false); scope.cm[type].setOption('indentUnit', $('[data-setting=indentSize]').value); scope.cm[type].setOption('tabSize', $('[data-setting=indentSize]').value); scope.cm[type].setOption('theme', $('[data-setting=editorTheme]').value);