1
0
mirror of https://github.com/chinchang/web-maker.git synced 2025-07-10 16:46:28 +02:00

Merge pull request #113 from chinchang/feat-console-56

Implement chrome like developer console
This commit is contained in:
Kushagra Gour
2017-05-17 01:07:15 +05:30
committed by GitHub
4 changed files with 371 additions and 17 deletions

View File

@ -23,7 +23,7 @@
</svg>Run </svg>Run
</a> </a>
<a id="js-add-library-btn" class="fleex-v-center hint--rounded hint--bottom-left" aria-label="Add a JS/CSS library"> <a id="js-add-library-btn" class="flex-v-center hint--rounded hint--bottom-left" aria-label="Add a JS/CSS library">
Add library <span id="js-external-lib-count" style="display:none;" class="count-label"></span> Add library <span id="js-external-lib-count" style="display:none;" class="count-label"></span>
</a> </a>
@ -101,6 +101,28 @@
</div> </div>
<div class="demo-side" id="js-demo-side"> <div class="demo-side" id="js-demo-side">
<iframe src="about://blank" frameborder="0" id="demo-frame"></iframe> <iframe src="about://blank" frameborder="0" id="demo-frame"></iframe>
<div id="consoleEl" class="console is-minimized">
<div id="consoleLogEl" class="console__log" class="code">
<div class="js-console__header code-wrap__header" title="Double click to toggle console">
<span class="code-wrap__header-label">Console (<span id="logCountEl">0</span>)</span>
<div class="code-wrap__header-right-options">
<a class="code-wrap__header-btn" title="Clear console (CTRL + L)" d-click="onClearConsoleBtnClick">
<svg>
<use xlink:href="#cancel-icon"></use>
</svg>
</a>
<a class="code-wrap__header-btn code-wrap__collapse-btn" title="Toggle console" d-click="toggleConsole">
</a>
</div>
</div>
</div>
<div id="consolePromptEl" class="console__prompt flex flex-v-center">
<svg width="18" height="18" fill="#346fd2">
<use xlink:href="#chevron-icon"></use>
</svg>
<input d-keyup="evalConsoleExpr" class="console-exec-input">
</div>
</div>
</div> </div>
</div> </div>
<div class="footer"> <div class="footer">
@ -224,7 +246,7 @@
<p> <p>
<h3>Awesome libraries used</h3> <h3>Awesome libraries used</h3>
<ul> <ul>
<li><a target="_blank" href="http://kushagragour.in/lab/hint/">Hint.css</a> - By me :)</li> <li><a target="_blank" href="https://kushagragour.in/lab/hint/">Hint.css</a> & <a target="_blank" href="https://github.com/chinchang/screenlog.js">Screenlog.js</a> - By me :)</li>
<li><a target="_blank" href="https://nathancahill.github.io/Split.js/">Split.js</a> - Nathan Cahill</li> <li><a target="_blank" href="https://nathancahill.github.io/Split.js/">Split.js</a> - Nathan Cahill</li>
<li><a target="_blank" href="https://codemirror.net/">Codemirror</a> - Marijn Haverbeke</li> <li><a target="_blank" href="https://codemirror.net/">Codemirror</a> - Marijn Haverbeke</li>
<li><a target="_blank" href="https://emmet.io/">Emmet</a> - Sergey Chikuyonok</li> <li><a target="_blank" href="https://emmet.io/">Emmet</a> - Sergey Chikuyonok</li>
@ -577,6 +599,16 @@
<path d="M8,5.14V19.14L19,12.14L8,5.14Z" /> <path d="M8,5.14V19.14L19,12.14L8,5.14Z" />
</svg> </svg>
</symbol> </symbol>
<symbol id="cancel-icon" viewBox="0 0 24 24">
<svg>
<path d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12C4,13.85 4.63,15.55 5.68,16.91L16.91,5.68C15.55,4.63 13.85,4 12,4M12,20A8,8 0 0,0 20,12C20,10.15 19.37,8.45 18.32,7.09L7.09,18.32C8.45,19.37 10.15,20 12,20Z" />
</svg>
</symbol>
<symbol id="chevron-icon" viewBox="0 0 24 24">
<svg>
<path d="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" />
</svg>
</symbol>
</svg> </svg>
<script src="lib/codemirror/lib/codemirror.js"></script> <script src="lib/codemirror/lib/codemirror.js"></script>

183
src/lib/screenlog.js Normal file
View File

@ -0,0 +1,183 @@
(function () {
var logEl,
isInitialized = false,
_console = {}; // backup console obj to contain references of overridden fns.
_options = {
bgColor: 'black',
logColor: 'lightgreen',
infoColor: 'blue',
warnColor: 'orange',
errorColor: 'red',
freeConsole: false,
css: '',
autoScroll: true,
proxyCallback: null,
noUi: false
};
function createElement(tag, css) {
var element = document.createElement(tag);
element.style.cssText = css;
return element;
}
function createPanel() {
var div = createElement('div', 'z-index:2147483647;font-family:Helvetica,Arial,sans-serif;font-size:10px;font-weight:bold;padding:5px;text-align:left;opacity:0.8;position:fixed;right:0;top:0;min-width:200px;max-height:50vh;overflow:auto;background:' + _options.bgColor + ';' + _options.css);
return div;
}
function genericLogger(color) {
return function() {
if (_options.proxyCallback) {
_options.proxyCallback.apply(null, arguments);
}
if (_options.noUi) { return; }
var el = createElement('div', 'line-height:18px;min-height:18px;background:' +
(logEl.children.length % 2 ? 'rgba(255,255,255,0.1)' : '') + ';color:' + color); // zebra lines
var val = [].slice.call(arguments).reduce(function(prev, arg) {
return prev + ' ' + (typeof arg === "object" ? JSON.stringify(arg) : arg);
}, '');
el.textContent = val;
logEl.appendChild(el);
// Scroll to last element, if autoScroll option is set.
if(_options.autoScroll) {
logEl.scrollTop = logEl.scrollHeight - logEl.clientHeight;
}
};
}
function clear() {
logEl.innerHTML = '';
}
function log() {
return genericLogger(_options.logColor).apply(null, arguments);
}
function info() {
return genericLogger(_options.infoColor).apply(null, arguments);
}
function warn() {
return genericLogger(_options.warnColor).apply(null, arguments);
}
function error() {
return genericLogger(_options.errorColor).apply(null, arguments);
}
function setOptions(options) {
for(var i in options)
if(options.hasOwnProperty(i) && _options.hasOwnProperty(i)) {
_options[i] = options[i];
}
}
function init(options) {
if (isInitialized) { return; }
isInitialized = true;
if(options) {
setOptions(options);
}
if (!_options.noUi) {
logEl = createPanel();
document.body.appendChild(logEl);
}
if (!_options.freeConsole) {
// Backup actual fns to keep it working together
_console.log = console.log;
_console.clear = console.clear;
_console.info = console.info;
_console.warn = console.warn;
_console.error = console.error;
console.log = originalFnCallDecorator(log, 'log');
console.clear = originalFnCallDecorator(clear, 'clear');
console.info = originalFnCallDecorator(info, 'info');
console.warn = originalFnCallDecorator(warn, 'warn');
console.error = originalFnCallDecorator(error, 'error');
}
}
function destroy() {
isInitialized = false;
console.log = _console.log;
console.clear = _console.clear;
console.info = _console.info;
console.warn = _console.warn;
console.error = _console.error;
logEl.remove();
}
/**
* Checking if isInitialized is set
*/
function checkInitialized() {
if (!isInitialized) {
throw 'You need to call `screenLog.init()` first.';
}
}
/**
* Decorator for checking if isInitialized is set
* @param {Function} fn Fn to decorate
* @return {Function} Decorated fn.
*/
function checkInitDecorator(fn) {
return function() {
checkInitialized();
return fn.apply(this, arguments);
};
}
/**
* Decorator for calling the original console's fn at the end of
* our overridden fn definitions.
* @param {Function} fn Fn to decorate
* @param {string} fn Name of original function
* @return {Function} Decorated fn.
*/
function originalFnCallDecorator(fn, fnName) {
return function() {
fn.apply(this, arguments);
if (typeof _console[fnName] === 'function') {
_console[fnName].apply(console, arguments);
}
};
}
window.addEventListener('error', function() {
genericLogger(_options.errorColor).call(null, arguments[0].error.stack);
});
// Public API
window.screenLog = {
init: init,
log: originalFnCallDecorator(checkInitDecorator(log), 'log'),
clear: originalFnCallDecorator(checkInitDecorator(clear), 'clear'),
info: originalFnCallDecorator(checkInitDecorator(clear), 'info'),
warn: originalFnCallDecorator(checkInitDecorator(warn), 'warn'),
error: originalFnCallDecorator(checkInitDecorator(error), 'error'),
destroy: checkInitDecorator(destroy)
};
})();
screenLog.init({
noUi: true,
proxyCallback: function () {
window.parent.onMessageFromConsole.apply(null, arguments);
}
});
window._wmEvaluate = function _wmEvaluate(expr) {
try {
var result = eval(expr);
} catch(e) {
window.parent.onMessageFromConsole.call(null, e);
return;
}
window.parent.onMessageFromConsole.call(null, result);
}

View File

@ -5,7 +5,7 @@ addLibraryModal, addLibraryModal, notificationsBtn, notificationsModal, notifica
notificationsModal, notificationsBtn, codepenBtn, saveHtmlBtn, saveBtn, settingsBtn, notificationsModal, notificationsBtn, codepenBtn, saveHtmlBtn, saveBtn, settingsBtn,
onboardModal, settingsModal, notificationsBtn, onboardShowInTabOptionBtn, editorThemeLinkTag, onboardModal, settingsModal, notificationsBtn, onboardShowInTabOptionBtn, editorThemeLinkTag,
onboardDontShowInTabOptionBtn, TextareaAutoComplete, savedItemCountEl, indentationSizeValueEl, onboardDontShowInTabOptionBtn, TextareaAutoComplete, savedItemCountEl, indentationSizeValueEl,
runBtn, searchInput runBtn, searchInput, consoleEl, consoleLogEl, logCountEl
*/ */
/* eslint-disable no-extra-semi */ /* eslint-disable no-extra-semi */
;(function (alertsService) { ;(function (alertsService) {
@ -71,6 +71,7 @@ runBtn, searchInput
, codeInPreview = { html: null, css: null, js: null } , codeInPreview = { html: null, css: null, js: null }
, isSavedItemsPaneOpen = false , isSavedItemsPaneOpen = false
, editorWithFocus , editorWithFocus
, logCount = 0
// DOM nodes // DOM nodes
, frame = $('#demo-frame') , frame = $('#demo-frame')
@ -91,6 +92,7 @@ runBtn, searchInput
; ;
scope.cm = {}; scope.cm = {};
scope.frame = frame;
scope.demoFrameDocument = frame.contentDocument || frame.contentWindow.document; scope.demoFrameDocument = frame.contentDocument || frame.contentWindow.document;
// Check all the code wrap if they are minimized or not // Check all the code wrap if they are minimized or not
@ -463,6 +465,8 @@ runBtn, searchInput
scope.cm.css.refresh(); scope.cm.css.refresh();
scope.cm.js.refresh(); scope.cm.js.refresh();
scope.clearConsole();
// To have the library count updated // To have the library count updated
updateExternalLibUi(); updateExternalLibUi();
@ -700,6 +704,7 @@ runBtn, searchInput
window.previewException = function (error) { window.previewException = function (error) {
console.error('Possible infinite loop detected.', error.stack) console.error('Possible infinite loop detected.', error.stack)
window.onMessageFromConsole('Possible infinite loop detected.', error.stack);
} }
window.onunload = function () { window.onunload = function () {
saveCode('code'); saveCode('code');
@ -734,6 +739,9 @@ runBtn, searchInput
+ '<body>\n' + html + '\n' + '<body>\n' + html + '\n'
+ externalJs + '\n'; + externalJs + '\n';
contents += '<script src="'
+ chrome.extension.getURL('lib/screenlog.js') + '"></script>';
if (js) { if (js) {
contents += '<script>\n' + js + '\n//# sourceURL=userscript.js'; contents += '<script>\n' + js + '\n//# sourceURL=userscript.js';
} else { } else {
@ -969,8 +977,18 @@ runBtn, searchInput
}); });
Inlet(scope.cm.js); Inlet(scope.cm.js);
// Initialize codemirror in console
scope.consoleCm = CodeMirror(consoleLogEl, {
mode: 'javascript',
lineWrapping: true,
theme: 'monokai',
foldGutter: true,
readOnly: true,
gutters: [ 'CodeMirror-foldgutter' ]
});
function openSettings() { function openSettings() {
settingsModal.classList.toggle('is-modal-visible'); scope.toggleModal(settingsModal);
/* if (chrome.runtime.openOptionsPage) { /* if (chrome.runtime.openOptionsPage) {
// New way to open options pages, if supported (Chrome 42+). // New way to open options pages, if supported (Chrome 42+).
@ -1232,6 +1250,7 @@ runBtn, searchInput
htmlCode.querySelector('.CodeMirror').style.fontSize = prefs.fontSize; htmlCode.querySelector('.CodeMirror').style.fontSize = prefs.fontSize;
cssCode.querySelector('.CodeMirror').style.fontSize = prefs.fontSize; cssCode.querySelector('.CodeMirror').style.fontSize = prefs.fontSize;
jsCode.querySelector('.CodeMirror').style.fontSize = prefs.fontSize; jsCode.querySelector('.CodeMirror').style.fontSize = prefs.fontSize;
consoleEl.querySelector('.CodeMirror').style.fontSize = prefs.fontSize;
// Update indentation count when slider is updated // Update indentation count when slider is updated
indentationSizeValueEl.textContent = $('[data-setting=indentSize]').value; indentationSizeValueEl.textContent = $('[data-setting=indentSize]').value;
@ -1252,6 +1271,7 @@ runBtn, searchInput
scope.cm[type].setOption('keyMap', $('[data-setting=keymap]:checked').value); scope.cm[type].setOption('keyMap', $('[data-setting=keymap]:checked').value);
scope.cm[type].refresh(); scope.cm[type].refresh();
}); });
scope.consoleCm.setOption('theme', $('[data-setting=editorTheme]').value);
}; };
scope.onNewBtnClick = function () { scope.onNewBtnClick = function () {
@ -1273,6 +1293,15 @@ runBtn, searchInput
trackEvent('ui', 'saveBtnClick', currentItem.id ? 'saved' : 'new'); trackEvent('ui', 'saveBtnClick', currentItem.id ? 'saved' : 'new');
saveItem(); saveItem();
}; };
/**
* Toggles a modal and logs an event.
* @param {Node} modal modal to be toggled
*/
scope.toggleModal = function (modal) {
modal.classList.toggle('is-modal-visible');
document.body.classList[modal.classList.contains('is-modal-visible') ? 'add' : 'remove']('overlay-visible');
};
scope.onSearchInputChange = function (e) { scope.onSearchInputChange = function (e) {
const text = e.target.value; const text = e.target.value;
let el; let el;
@ -1287,8 +1316,53 @@ runBtn, searchInput
trackEvent('ui', 'searchInputType'); trackEvent('ui', 'searchInputType');
}; };
function compileNodes() { scope.toggleConsole = function () {
consoleEl.classList.toggle('is-minimized');
trackEvent('ui', 'consoleToggle');
};
scope.clearConsole = function () {
scope.consoleCm.setValue('');
logCount = 0;
logCountEl.textContent = logCount;
};
scope.onClearConsoleBtnClick = function () {
scope.clearConsole();
trackEvent('ui', 'consoleClearBtnClick');
};
scope.evalConsoleExpr = function (e) {
// Clear console on CTRL + L
if (((e.which === 76 || e.which === 12) && e.ctrlKey)) {
scope.clearConsole();
trackEvent('ui', 'consoleClearKeyboardShortcut');
} else if (e.which === 13) {
window.onMessageFromConsole('> ' + e.target.value);
/* eslint-disable no-underscore-dangle */
frame.contentWindow._wmEvaluate(e.target.value);
/* eslint-enable no-underscore-dangle */
e.target.value = '';
trackEvent('fn', 'evalConsoleExpr');
}
};
window.onMessageFromConsole = function() {
/* eslint-disable no-param-reassign */
[...arguments].forEach(function(arg) {
if (arg && arg.indexOf && arg.indexOf('filesystem:chrome-extension') !== -1) {
arg = arg.replace(/filesystem:chrome-extension.*\.js:(\d+):*(\d*)/g, 'script $1:$2');
}
scope.consoleCm.replaceRange(arg + ' ' + ((arg + '').match(/\[object \w+]/) ? JSON.stringify(arg) : '') + '\n', { line: Infinity });
scope.consoleCm.scrollTo(0, Infinity);
logCount++;
});
logCountEl.textContent = logCount;
/* eslint-enable no-param-reassign */
};
function compileNodes() {
function attachListenerForEvent(eventName) { function attachListenerForEvent(eventName) {
const nodes = $all(`[d-${eventName}]`); const nodes = $all(`[d-${eventName}]`);
nodes.forEach(function (el) { nodes.forEach(function (el) {
@ -1300,6 +1374,7 @@ runBtn, searchInput
attachListenerForEvent('click'); attachListenerForEvent('click');
attachListenerForEvent('change'); attachListenerForEvent('change');
attachListenerForEvent('input'); attachListenerForEvent('input');
attachListenerForEvent('keyup');
} }
function init () { function init () {
@ -1321,19 +1396,17 @@ runBtn, searchInput
layoutBtn4.addEventListener('click', getToggleLayoutButtonListener(4)); layoutBtn4.addEventListener('click', getToggleLayoutButtonListener(4));
utils.onButtonClick(helpBtn, function () { utils.onButtonClick(helpBtn, function () {
helpModal.classList.toggle('is-modal-visible'); scope.toggleModal(helpModal);
document.body.classList[helpModal.classList.contains('is-modal-visible') ? 'add' : 'remove']('overlay-visible');
trackEvent('ui', 'helpButtonClick'); trackEvent('ui', 'helpButtonClick');
}); });
utils.onButtonClick(addLibraryBtn, function () { utils.onButtonClick(addLibraryBtn, function () {
addLibraryModal.classList.toggle('is-modal-visible'); scope.toggleModal(addLibraryModal);
document.body.classList[addLibraryModal.classList.contains('is-modal-visible') ? 'add' : 'remove']('overlay-visible');
trackEvent('ui', 'addLibraryButtonClick'); trackEvent('ui', 'addLibraryButtonClick');
}); });
notificationsBtn.addEventListener('click', function () { notificationsBtn.addEventListener('click', function () {
notificationsModal.classList.toggle('is-modal-visible'); scope.toggleModal(notificationsModal);
document.body.classList[notificationsModal.classList.contains('is-modal-visible') ? 'add' : 'remove']('overlay-visible');
if (notificationsModal.classList.contains('is-modal-visible') && !hasSeenNotifications) { if (notificationsModal.classList.contains('is-modal-visible') && !hasSeenNotifications) {
hasSeenNotifications = true; hasSeenNotifications = true;
notificationsBtn.classList.remove('has-new'); notificationsBtn.classList.remove('has-new');
@ -1440,6 +1513,7 @@ runBtn, searchInput
}); });
}); });
// Editor keyboard shortucuts
window.addEventListener('keydown', function (event) { window.addEventListener('keydown', function (event) {
var selectedItemElement; var selectedItemElement;
// Ctrl/⌘ + S // Ctrl/⌘ + S
@ -1505,6 +1579,10 @@ runBtn, searchInput
}); });
window.addEventListener('dblclick', function(e) { window.addEventListener('dblclick', function(e) {
var target = e.target; var target = e.target;
if (target.classList.contains('js-console__header')) {
scope.toggleConsole();
trackEvent('ui', 'consoleToggleDblClick');
}
if (target.classList.contains('js-code-wrap__header')) { if (target.classList.contains('js-code-wrap__header')) {
var codeWrapParent = target.parentElement; var codeWrapParent = target.parentElement;
toggleCodeWrapCollapse(codeWrapParent); toggleCodeWrapCollapse(codeWrapParent);
@ -1538,6 +1616,24 @@ runBtn, searchInput
new TextareaAutoComplete(externalJsTextarea, (obj) => obj.latest.match(/\.js$/)); new TextareaAutoComplete(externalJsTextarea, (obj) => obj.latest.match(/\.js$/));
new TextareaAutoComplete(externalCssTextarea, (obj) => obj.latest.match(/\.css$/)); new TextareaAutoComplete(externalCssTextarea, (obj) => obj.latest.match(/\.css$/));
// Console header drag resize logic
var consoleHeaderDragStartY;
var consoleInitialHeight;
function onConsoleHeaderDrag(e) {
consoleEl.style.height = (consoleInitialHeight + consoleHeaderDragStartY - e.pageY) + 'px';
utils.log(e.pageY, consoleHeaderDragStartY)
}
$('.js-console__header').addEventListener('mousedown', (e) => {
consoleHeaderDragStartY = e.pageY;
consoleInitialHeight = consoleEl.getBoundingClientRect().height;
$('#demo-frame').classList.add('pointer-none');
window.addEventListener('mousemove', onConsoleHeaderDrag);
});
$('.js-console__header').addEventListener('mouseup', () => {
window.removeEventListener('mousemove', onConsoleHeaderDrag);
$('#demo-frame').classList.add('pointer-none');
});
chrome.storage.local.get({ chrome.storage.local.get({
layoutMode: 1, layoutMode: 1,
code: '' code: ''

View File

@ -107,6 +107,7 @@ select, input[type="text"], input[type="number"], textarea {
top: 0; bottom: 0; top: 0; bottom: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden;
will-change: -webkit-filter; will-change: -webkit-filter;
transition: 0.10s ease 0.2s; transition: 0.10s ease 0.2s;
} }
@ -119,6 +120,7 @@ select, input[type="text"], input[type="number"], textarea {
.demo-side { .demo-side {
flex-basis: inherit; flex-basis: inherit;
position: relative; position: relative;
width: 50%;
} }
.layout-3 .content-wrap { .layout-3 .content-wrap {
flex-direction: row-reverse; flex-direction: row-reverse;
@ -126,7 +128,6 @@ select, input[type="text"], input[type="number"], textarea {
.code-side { .code-side {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 50%;
} }
.layout-2 .content-wrap { .layout-2 .content-wrap {
flex-direction: column; flex-direction: column;
@ -135,6 +136,9 @@ select, input[type="text"], input[type="number"], textarea {
flex-direction: row; flex-direction: row;
width: auto; width: auto;
} }
.layout-2 .demo-side {
width: auto;
}
.layout-4 .code-side { .layout-4 .code-side {
display: none; display: none;
} }
@ -182,6 +186,7 @@ select, input[type="text"], input[type="number"], textarea {
color: #888; color: #888;
border-bottom: 1px solid rgba(0,0,0,0.3); border-bottom: 1px solid rgba(0,0,0,0.3);
font-weight: bold; font-weight: bold;
user-select: none;
} }
.code-wrap__header-label { .code-wrap__header-label {
/*transform: translate(0px) scale(1.2);*/ /*transform: translate(0px) scale(1.2);*/
@ -190,7 +195,7 @@ select, input[type="text"], input[type="number"], textarea {
opacity: 0.5; opacity: 0.5;
/*transform-origin: left center;*/ /*transform-origin: left center;*/
} }
.layout-2 .is-minimized .code-wrap__header { .layout-2 .code-side .is-minimized .code-wrap__header {
writing-mode: vertical-lr; writing-mode: vertical-lr;
padding: 10px 5px; padding: 10px 5px;
} }
@ -201,9 +206,14 @@ select, input[type="text"], input[type="number"], textarea {
opacity: 0; opacity: 0;
} }
.code-wrap__header-btn { .code-wrap__header-btn {
display: inline-block;
vertical-align: top;
margin-left: 8px;
}
.code-wrap__header-btn,
.code-wrap__header-btn > svg {
width: 18px; width: 18px;
height: 18px; height: 18px;
display: inline-block;
} }
.code-wrap__collapse-btn:before { .code-wrap__collapse-btn:before {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" style="width:18px;height:18px" viewBox="0 0 24 24"><path fill="rgba(255,255,255,0.2)" d="M19.5,3.09L15,7.59V4H13V11H20V9H16.41L20.91,4.5L19.5,3.09M4,13V15H7.59L3.09,19.5L4.5,20.91L9,16.41V20H11V13H4Z" /></svg>'); content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" style="width:18px;height:18px" viewBox="0 0 24 24"><path fill="rgba(255,255,255,0.2)" d="M19.5,3.09L15,7.59V4H13V11H20V9H16.41L20.91,4.5L19.5,3.09M4,13V15H7.59L3.09,19.5L4.5,20.91L9,16.41V20H11V13H4Z" /></svg>');
@ -263,7 +273,7 @@ li.CodeMirror-hint-active {
#demo-frame { #demo-frame {
border: 0; border: 0;
width: 100%; width: 100%;
height: 100%; height: calc(100% - 29px); /* minus minimized console height */
position: absolute; position: absolute;
z-index: 1; z-index: 1;
background: white; background: white;
@ -271,11 +281,14 @@ li.CodeMirror-hint-active {
.main-header, .main-header,
.footer { .footer {
padding: 5px 10px; padding: 5px 10px;
background-color: rgba(0, 0, 0, 0.5); background-color: rgb(18, 19, 27);
color: rgba(255, 255, 255, 0.45); color: rgba(255, 255, 255, 0.45);
border-top: 1px solid rgba(255,255,255,0.14); border-top: 1px solid rgba(255,255,255,0.14);
/*line-height: 20px;*/ /*line-height: 20px;*/
} }
.footer {
z-index: 1;
}
.main-header { .main-header {
border: 0; border: 0;
border-bottom: 1px solid rgba(255,255,255,0.14); border-bottom: 1px solid rgba(255,255,255,0.14);
@ -810,3 +823,33 @@ li.CodeMirror-hint-active {
.wobble { .wobble {
animation-name: wobble; animation-name: wobble;
} }
.console {
background: var(--color-bg);
z-index: 1; /* bring above iframe */
position: absolute;
bottom: 0;
min-height: 80px;
height: 35vh;
left: 0;
right: 0;
transform: translateY(0);
transition: transform 0.4s cubic-bezier(0.76, 0.01, 0.13, 0.9);
}
.console.is-minimized {
transform: translateY(calc(100% - 29px));
}
.console .Codemirror {
height: calc(100% - 55px);
}
.console-exec-input {
padding: 5px;
font-size: 1.3em;
flex: 1;
background: rgba(0,0,0,0.3);
color: white;
border: 0;
outline: 0;
}
.console:not(.is-minimized) .code-wrap__header {
cursor: ns-resize;
}